lexgui 0.7.15 → 8.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (134) hide show
  1. package/LICENSE +201 -21
  2. package/README.md +14 -5
  3. package/build/components/AlertDialog.d.ts +7 -0
  4. package/build/components/ArrayInput.d.ts +9 -0
  5. package/build/components/BaseComponent.d.ts +73 -0
  6. package/build/components/Button.d.ts +14 -0
  7. package/build/components/Calendar.d.ts +41 -0
  8. package/build/components/CalendarRange.d.ts +16 -0
  9. package/build/components/CanvasCurve.d.ts +10 -0
  10. package/build/components/CanvasDial.d.ts +11 -0
  11. package/build/components/CanvasMap2D.d.ts +61 -0
  12. package/build/components/Card.d.ts +8 -0
  13. package/build/components/Checkbox.d.ts +8 -0
  14. package/build/components/Color.d.ts +20 -0
  15. package/build/components/ColorInput.d.ts +13 -0
  16. package/build/components/ColorPicker.d.ts +29 -0
  17. package/build/components/ComboButtons.d.ts +8 -0
  18. package/build/components/ContextMenu.d.ts +16 -0
  19. package/build/components/Counter.d.ts +9 -0
  20. package/build/components/Curve.d.ts +10 -0
  21. package/build/components/DatePicker.d.ts +13 -0
  22. package/build/components/Dial.d.ts +10 -0
  23. package/build/components/Dialog.d.ts +20 -0
  24. package/build/components/DropdownMenu.d.ts +32 -0
  25. package/build/components/FileInput.d.ts +8 -0
  26. package/build/components/Footer.d.ts +14 -0
  27. package/build/components/Form.d.ts +8 -0
  28. package/build/components/Layers.d.ts +9 -0
  29. package/build/components/List.d.ts +9 -0
  30. package/build/components/Map2D.d.ts +12 -0
  31. package/build/components/Menubar.d.ts +59 -0
  32. package/build/components/NodeTree.d.ts +26 -0
  33. package/build/components/NumberInput.d.ts +9 -0
  34. package/build/components/OTPInput.d.ts +8 -0
  35. package/build/components/Pad.d.ts +8 -0
  36. package/build/components/Pagination.d.ts +26 -0
  37. package/build/components/PocketDialog.d.ts +11 -0
  38. package/build/components/Popover.d.ts +20 -0
  39. package/build/components/Progress.d.ts +8 -0
  40. package/build/components/RadioGroup.d.ts +8 -0
  41. package/build/components/RangeInput.d.ts +11 -0
  42. package/build/components/Rate.d.ts +8 -0
  43. package/build/components/Select.d.ts +10 -0
  44. package/build/components/Sheet.d.ts +10 -0
  45. package/build/components/Sidebar.d.ts +84 -0
  46. package/build/components/SizeInput.d.ts +8 -0
  47. package/build/components/Skeleton.d.ts +5 -0
  48. package/build/components/Spinner.d.ts +9 -0
  49. package/build/components/TabSections.d.ts +11 -0
  50. package/build/components/Table.d.ts +34 -0
  51. package/build/components/Tabs.d.ts +20 -0
  52. package/build/components/Tags.d.ts +9 -0
  53. package/build/components/TextArea.d.ts +8 -0
  54. package/build/components/TextInput.d.ts +11 -0
  55. package/build/components/Title.d.ts +8 -0
  56. package/build/components/Toggle.d.ts +8 -0
  57. package/build/components/Tour.d.ts +36 -0
  58. package/build/components/Vector.d.ts +9 -0
  59. package/build/core/Area.d.ts +143 -0
  60. package/build/core/Branch.d.ts +19 -0
  61. package/build/core/Core.d.ts +1 -0
  62. package/build/core/Event.d.ts +26 -0
  63. package/build/core/Icons.d.ts +4 -0
  64. package/build/core/Namespace.d.ts +2 -0
  65. package/build/core/Namespace.js +34 -0
  66. package/build/core/Namespace.js.map +1 -0
  67. package/build/core/Panel.d.ts +538 -0
  68. package/build/core/Utils.d.ts +1 -0
  69. package/build/core/Vec2.d.ts +21 -0
  70. package/build/extensions/AssetView.d.ts +136 -0
  71. package/build/extensions/AssetView.js +1367 -0
  72. package/build/extensions/AssetView.js.map +1 -0
  73. package/build/extensions/Audio.d.ts +9 -0
  74. package/build/extensions/Audio.js +163 -0
  75. package/build/extensions/Audio.js.map +1 -0
  76. package/build/extensions/CodeEditor.d.ts +350 -0
  77. package/build/extensions/CodeEditor.js +5022 -0
  78. package/build/extensions/CodeEditor.js.map +1 -0
  79. package/build/extensions/DocMaker.d.ts +27 -0
  80. package/build/extensions/DocMaker.js +327 -0
  81. package/build/extensions/DocMaker.js.map +1 -0
  82. package/build/extensions/GraphEditor.d.ts +276 -0
  83. package/build/extensions/GraphEditor.js +2770 -0
  84. package/build/extensions/GraphEditor.js.map +1 -0
  85. package/build/extensions/ImUi.d.ts +46 -0
  86. package/build/extensions/ImUi.js +227 -0
  87. package/build/extensions/ImUi.js.map +1 -0
  88. package/build/extensions/Timeline.d.ts +670 -0
  89. package/build/extensions/Timeline.js +3955 -0
  90. package/build/extensions/Timeline.js.map +1 -0
  91. package/build/extensions/VideoEditor.d.ts +128 -0
  92. package/build/extensions/VideoEditor.js +898 -0
  93. package/build/extensions/VideoEditor.js.map +1 -0
  94. package/build/extensions/index.d.ts +8 -0
  95. package/build/extensions/index.js +10 -0
  96. package/build/extensions/index.js.map +1 -0
  97. package/build/index.all.d.ts +2 -0
  98. package/build/index.css.d.ts +4 -0
  99. package/build/index.d.ts +56 -0
  100. package/build/lexgui.all.js +28498 -0
  101. package/build/lexgui.all.js.map +1 -0
  102. package/build/lexgui.all.min.js +1 -0
  103. package/build/lexgui.all.module.js +28422 -0
  104. package/build/lexgui.all.module.js.map +1 -0
  105. package/build/lexgui.all.module.min.js +1 -0
  106. package/build/lexgui.css +939 -346
  107. package/build/lexgui.js +13406 -17286
  108. package/build/lexgui.js.map +1 -0
  109. package/build/lexgui.min.css +3 -10
  110. package/build/lexgui.min.js +1 -1
  111. package/build/lexgui.module.js +12762 -16698
  112. package/build/lexgui.module.js.map +1 -0
  113. package/build/lexgui.module.min.js +1 -1
  114. package/changelog.md +170 -74
  115. package/demo.js +162 -48
  116. package/examples/all-components.html +45 -14
  117. package/examples/asset-view.html +110 -47
  118. package/examples/code-editor.html +5 -5
  119. package/examples/dialogs.html +3 -3
  120. package/examples/editor.html +27 -13
  121. package/examples/index.html +19 -14
  122. package/examples/node-graph.html +2 -2
  123. package/examples/previews/video-editor.png +0 -0
  124. package/examples/timeline.html +1 -1
  125. package/examples/video-editor.html +2 -2
  126. package/package.json +25 -9
  127. package/build/extensions/audio.js +0 -212
  128. package/build/extensions/codeeditor.js +0 -6319
  129. package/build/extensions/docmaker.js +0 -432
  130. package/build/extensions/imui.js +0 -325
  131. package/build/extensions/nodegraph.js +0 -3696
  132. package/build/extensions/timeline.js +0 -4636
  133. package/build/extensions/videoeditor.js +0 -953
  134. package/build/lexgui-docs.css +0 -352
@@ -0,0 +1,898 @@
1
+ // This is a generated file. Do not edit.
2
+ import { LX } from '../core/Namespace.js';
3
+
4
+ // VideoEditor.ts @evallsg
5
+ if (!LX) {
6
+ throw ('Missing LX namespace!');
7
+ }
8
+ LX.extensions.push('VideoEditor');
9
+ const vec2 = LX.vec2;
10
+ LX.Area;
11
+ LX.Panel;
12
+ /**
13
+ * @class TimeBar
14
+ */
15
+ class TimeBar {
16
+ static TIMEBAR_PLAY = 1;
17
+ static TIMEBAR_TRIM = 2;
18
+ static BACKGROUND_COLOR = LX.getThemeColor('global-branch-darker');
19
+ static COLOR = LX.getThemeColor('global-button-color');
20
+ static ACTIVE_COLOR = '#668ee4';
21
+ type = TimeBar.TIMEBAR_PLAY;
22
+ duration = 1.0;
23
+ canvas;
24
+ ctx;
25
+ markerWidth = 8;
26
+ markerHeight;
27
+ offset;
28
+ lineWidth;
29
+ lineHeight;
30
+ position;
31
+ startX;
32
+ endX;
33
+ currentX;
34
+ hovering;
35
+ dragging;
36
+ onChangeCurrent;
37
+ onChangeStart;
38
+ onChangeEnd;
39
+ onDraw;
40
+ onMouse;
41
+ constructor(area, type, options = {}) {
42
+ this.type = type ?? TimeBar.TIMEBAR_PLAY;
43
+ this.duration = options.duration ?? this.duration;
44
+ // Create canvas
45
+ this.canvas = document.createElement('canvas');
46
+ this.canvas.width = area.size[0];
47
+ this.canvas.height = area.size[1];
48
+ area.attach(this.canvas);
49
+ this.ctx = this.canvas.getContext('2d');
50
+ this.markerWidth = options.markerWidth ?? this.markerWidth;
51
+ this.markerHeight = options.markerHeight ?? (this.canvas.height * 0.5);
52
+ this.offset = options.offset || (this.markerWidth * 0.5 + 5);
53
+ // dimensions of line (not canvas)
54
+ this.lineWidth = this.canvas.width - this.offset * 2;
55
+ this.lineHeight = options.barHeight ?? 5;
56
+ this.position = new vec2(this.offset, this.canvas.height * 0.5 - this.lineHeight * 0.5);
57
+ this.startX = this.position.x;
58
+ this.endX = this.position.x + this.lineWidth;
59
+ this.currentX = this.startX;
60
+ this._draw();
61
+ this.updateTheme();
62
+ LX.addSignal('@on_new_color_scheme', () => {
63
+ // Retrieve again the color using LX.getThemeColor, which checks the applied theme
64
+ this.updateTheme();
65
+ });
66
+ this.canvas.onmousedown = (e) => this.onMouseDown(e);
67
+ this.canvas.onmousemove = (e) => this.onMouseMove(e);
68
+ this.canvas.onmouseup = (e) => this.onMouseUp(e);
69
+ }
70
+ updateTheme() {
71
+ TimeBar.BACKGROUND_COLOR = LX.getThemeColor('global-color-secondary');
72
+ TimeBar.COLOR = LX.getThemeColor('global-color-quaternary');
73
+ TimeBar.ACTIVE_COLOR = '#668ee4';
74
+ }
75
+ setDuration(duration) {
76
+ this.duration = duration;
77
+ }
78
+ xToTime(x) {
79
+ return ((x - this.offset) / (this.lineWidth)) * this.duration;
80
+ }
81
+ timeToX(time) {
82
+ return (time / this.duration) * (this.lineWidth) + this.offset;
83
+ }
84
+ setCurrentTime(time) {
85
+ this.currentX = this.timeToX(time);
86
+ this.onSetCurrentValue(this.currentX);
87
+ }
88
+ setStartTime(time) {
89
+ this.startX = this.timeToX(time);
90
+ this.onSetStartValue(this.startX);
91
+ }
92
+ setEndTime(time) {
93
+ this.endX = this.timeToX(time);
94
+ this.onSetEndValue(this.endX);
95
+ }
96
+ onSetCurrentValue(x) {
97
+ this.update(x);
98
+ const t = this.xToTime(x);
99
+ if (this.onChangeCurrent) {
100
+ this.onChangeCurrent(t);
101
+ }
102
+ }
103
+ onSetStartValue(x) {
104
+ this.update(x);
105
+ const t = this.xToTime(x);
106
+ if (this.onChangeStart) {
107
+ this.onChangeStart(t);
108
+ }
109
+ }
110
+ onSetEndValue(x) {
111
+ this.update(x);
112
+ const t = this.xToTime(x);
113
+ if (this.onChangeEnd) {
114
+ this.onChangeEnd(t);
115
+ }
116
+ }
117
+ _draw() {
118
+ const ctx = this.ctx;
119
+ if (!ctx)
120
+ return;
121
+ ctx.save();
122
+ ctx.fillStyle = TimeBar.BACKGROUND_COLOR;
123
+ ctx.clearRect(0, 0, this.canvas.width, this.canvas.height);
124
+ ctx.fillRect(0, 0, this.canvas.width, this.canvas.height);
125
+ // Draw background timeline
126
+ ctx.fillStyle = TimeBar.COLOR;
127
+ ctx.fillRect(this.position.x, this.position.y, this.lineWidth, this.lineHeight);
128
+ // Draw background trimed timeline
129
+ ctx.fillStyle = TimeBar.ACTIVE_COLOR;
130
+ ctx.fillRect(this.startX, this.position.y, this.endX - this.startX, this.lineHeight);
131
+ ctx.restore();
132
+ // Min-Max time markers
133
+ this._drawTrimMarker('start', this.startX, { color: null, fillColor: TimeBar.ACTIVE_COLOR || '#5f88c9' });
134
+ this._drawTrimMarker('end', this.endX, { color: null, fillColor: TimeBar.ACTIVE_COLOR || '#5f88c9' });
135
+ this._drawTimeMarker('current', this.currentX, { color: '#e5e5e5',
136
+ fillColor: TimeBar.ACTIVE_COLOR || '#5f88c9', width: this.markerWidth });
137
+ if (this.onDraw) {
138
+ this.onDraw();
139
+ }
140
+ }
141
+ _drawTrimMarker(name, x, options = {}) {
142
+ const w = this.markerWidth;
143
+ const h = this.markerHeight;
144
+ const y = this.canvas.height * 0.5 - h * 0.5;
145
+ const ctx = this.ctx;
146
+ if (!ctx)
147
+ return;
148
+ // Shadow
149
+ if (this.hovering == name) {
150
+ ctx.shadowColor = 'white';
151
+ ctx.shadowBlur = 2;
152
+ }
153
+ ctx.globalAlpha = 1;
154
+ ctx.fillStyle = ctx.strokeStyle = options.fillColor || '#111'; // "#FFF";
155
+ ctx.beginPath();
156
+ ctx.roundRect(x - w * 0.5, y, w, h, 2);
157
+ ctx.fill();
158
+ ctx.fillStyle = ctx.strokeStyle = options.fillColor || '#111'; // "#FFF";
159
+ ctx.strokeStyle = 'white';
160
+ ctx.beginPath();
161
+ ctx.lineWidth = 2;
162
+ ctx.moveTo(x, y + 4);
163
+ ctx.lineTo(x, y + h - 4);
164
+ ctx.stroke();
165
+ ctx.shadowBlur = 0;
166
+ }
167
+ _drawTimeMarker(name, x, options = {}) {
168
+ let y = this.offset;
169
+ const w = options.width ? options.width : (this.dragging == name ? 6 : 4);
170
+ const h = this.canvas.height - this.offset * 2;
171
+ let ctx = this.ctx;
172
+ if (!ctx)
173
+ return;
174
+ ctx.globalAlpha = 1;
175
+ ctx.fillStyle = ctx.strokeStyle = options.fillColor || '#111'; // "#FFF";
176
+ // Shadow
177
+ if (this.hovering == name) {
178
+ ctx.shadowColor = 'white';
179
+ ctx.shadowBlur = 2;
180
+ }
181
+ // Current time line
182
+ ctx.fillStyle = ctx.strokeStyle = 'white';
183
+ ctx.beginPath();
184
+ ctx.moveTo(x, y);
185
+ ctx.lineTo(x, y + h * 0.5);
186
+ ctx.stroke();
187
+ ctx.closePath();
188
+ ctx.fillStyle = ctx.strokeStyle = options.fillColor || '#111'; // "#FFF";
189
+ y -= this.offset + 8;
190
+ // Current time ball grab
191
+ ctx.fillStyle = options.fillColor || '#e5e5e5';
192
+ ctx.beginPath();
193
+ ctx.roundRect(x - w * 0.5, y + this.offset, w, w, 5);
194
+ ctx.fill();
195
+ ctx.shadowBlur = 0;
196
+ }
197
+ update(x) {
198
+ this.currentX = Math.min(Math.max(this.startX, x), this.endX);
199
+ this._draw();
200
+ }
201
+ onMouseDown(e) {
202
+ if (this.onMouse) {
203
+ this.onMouse(e);
204
+ }
205
+ e.preventDefault();
206
+ if (!this.canvas || e.target != this.canvas || e.cancelBubble) {
207
+ return;
208
+ }
209
+ const canvas = this.canvas;
210
+ // Process mouse
211
+ const x = e.offsetX;
212
+ const y = e.offsetY;
213
+ // Check if some marker is clicked
214
+ const threshold = this.markerWidth;
215
+ // grab trim markers only from the bottom
216
+ if (Math.abs(this.startX - x) < threshold && this.position.y < y) {
217
+ this.dragging = 'start';
218
+ canvas.style.cursor = 'grabbing';
219
+ }
220
+ else if (Math.abs(this.endX - x) < threshold && this.position.y < y) {
221
+ this.dragging = 'end';
222
+ canvas.style.cursor = 'grabbing';
223
+ }
224
+ else {
225
+ this.dragging = 'current';
226
+ canvas.style.cursor = 'grabbing';
227
+ if (x < this.startX) {
228
+ this.currentX = this.startX;
229
+ }
230
+ else if (x > this.endX) {
231
+ this.currentX = this.endX;
232
+ }
233
+ else {
234
+ this.currentX = x;
235
+ }
236
+ this.onSetCurrentValue(this.currentX);
237
+ }
238
+ this._draw();
239
+ }
240
+ onMouseUp(e) {
241
+ if (this.onMouse) {
242
+ this.onMouse(e);
243
+ }
244
+ e.preventDefault();
245
+ delete this.dragging;
246
+ delete this.hovering;
247
+ if (!this.canvas || e.cancelBubble) {
248
+ return;
249
+ }
250
+ const canvas = this.canvas;
251
+ canvas.style.cursor = 'default';
252
+ }
253
+ onMouseMove(e) {
254
+ if (this.onMouse) {
255
+ this.onMouse(e);
256
+ }
257
+ if (!this.canvas || e.cancelBubble) {
258
+ return;
259
+ }
260
+ e.preventDefault();
261
+ const canvas = this.canvas;
262
+ // Process mouse
263
+ const x = e.target == canvas ? e.offsetX : e.clientX - canvas.offsetLeft;
264
+ e.target == canvas ? e.offsetY : e.clientY - canvas.offsetTop;
265
+ if (this.dragging) {
266
+ switch (this.dragging) {
267
+ case 'start':
268
+ this.startX = Math.max(this.position.x, Math.min(this.endX, x));
269
+ this.currentX = this.startX;
270
+ this.onSetStartValue(this.startX);
271
+ break;
272
+ case 'end':
273
+ this.endX = Math.max(this.startX, Math.min(this.position.x + this.lineWidth, x));
274
+ this.currentX = this.endX;
275
+ this.onSetEndValue(this.endX);
276
+ break;
277
+ default:
278
+ this.currentX = Math.max(this.startX, Math.min(this.endX, x));
279
+ break;
280
+ }
281
+ this.onSetCurrentValue(this.currentX);
282
+ }
283
+ else {
284
+ const threshold = this.markerWidth * 0.5;
285
+ if (Math.abs(this.startX - x) < threshold) {
286
+ this.hovering = 'start';
287
+ canvas.style.cursor = 'grab';
288
+ }
289
+ else if (Math.abs(this.endX - x) < threshold) {
290
+ this.hovering = 'end';
291
+ canvas.style.cursor = 'grab';
292
+ }
293
+ else if (Math.abs(this.currentX - x) < threshold) {
294
+ this.hovering = 'current';
295
+ canvas.style.cursor = 'grab';
296
+ }
297
+ else {
298
+ delete this.hovering;
299
+ canvas.style.cursor = 'default';
300
+ }
301
+ }
302
+ this._draw();
303
+ }
304
+ resize(size) {
305
+ this.canvas.width = Math.max(0, size[0]);
306
+ this.canvas.height = Math.max(0, size[1]);
307
+ let newWidth = size[0] - this.offset * 2;
308
+ newWidth = newWidth < 0.00001 ? 0.00001 : newWidth; // actual width of the line = canvas.width - offsetleft - offsetRight
309
+ const startRatio = (this.startX - this.offset) / this.lineWidth;
310
+ const currentRatio = (this.currentX - this.offset) / this.lineWidth;
311
+ const endRatio = (this.endX - this.offset) / this.lineWidth;
312
+ this.lineWidth = newWidth;
313
+ this.startX = Math.min(Math.max(newWidth * startRatio, 0), newWidth) + this.offset;
314
+ this.currentX = Math.min(Math.max(newWidth * currentRatio, 0), newWidth) + this.offset;
315
+ this.endX = Math.min(Math.max(newWidth * endRatio, 0), newWidth) + this.offset;
316
+ this._draw();
317
+ }
318
+ }
319
+ LX.TimeBar = TimeBar;
320
+ /**
321
+ * @class VideoEditor
322
+ */
323
+ class VideoEditor {
324
+ static CROP_HANDLE_L = 0x01;
325
+ static CROP_HANDLE_R = 0x02;
326
+ static CROP_HANDLE_T = 0x04;
327
+ static CROP_HANDLE_B = 0x08;
328
+ static CROP_HANDLE_TL = VideoEditor.CROP_HANDLE_L | VideoEditor.CROP_HANDLE_T;
329
+ static CROP_HANDLE_BL = VideoEditor.CROP_HANDLE_L | VideoEditor.CROP_HANDLE_B;
330
+ static CROP_HANDLE_TR = VideoEditor.CROP_HANDLE_R | VideoEditor.CROP_HANDLE_T;
331
+ static CROP_HANDLE_BR = VideoEditor.CROP_HANDLE_R | VideoEditor.CROP_HANDLE_B;
332
+ options = {};
333
+ playing = false;
334
+ videoReady = false;
335
+ controls = true;
336
+ startTimeString = '0:0';
337
+ endTimeString = '0:0';
338
+ speed = 1.0;
339
+ currentTime = 0.0;
340
+ startTime = 0.0;
341
+ endTime = 0.0;
342
+ requestId;
343
+ video;
344
+ loop = false;
345
+ isDragging = false;
346
+ isResizing = null; // holds the HTMLElement of the crop handle, if resizing
347
+ crop = false;
348
+ dragOffsetX = 0.0;
349
+ dragOffsetY = 0.0;
350
+ currentTimeString = '';
351
+ timebar;
352
+ mainArea;
353
+ cropArea; // HTMLElement with normCoord attribute;
354
+ controlsArea;
355
+ controlsPanelLeft;
356
+ controlsPanelRight;
357
+ controlsCurrentPanel;
358
+ onChangeCurrent;
359
+ onChangeStart;
360
+ onChangeEnd;
361
+ onKeyUp;
362
+ onSetTime;
363
+ onVideoLoaded;
364
+ onCropArea;
365
+ onResize;
366
+ onChangeSpeed;
367
+ _updateTime = true;
368
+ _onCropMouseUp;
369
+ _onCropMouseMove;
370
+ resize;
371
+ constructor(area, options = {}) {
372
+ this.options = options ?? {};
373
+ this.speed = options.speed ?? this.speed;
374
+ this.mainArea = area;
375
+ let videoArea = null;
376
+ let controlsArea = null;
377
+ if (options.controlsArea) {
378
+ videoArea = area;
379
+ controlsArea = options.controlsArea;
380
+ }
381
+ else {
382
+ [videoArea, controlsArea] = area.split({ type: 'vertical', sizes: ['85%', null], minimizable: false,
383
+ resize: false });
384
+ }
385
+ controlsArea.root.classList.add('lexconstrolsarea');
386
+ this.cropArea = document.createElement('div');
387
+ this.cropArea.id = 'cropArea';
388
+ this.cropArea.className = 'resize-area hidden';
389
+ this.cropArea.normCoords = { x: 0, y: 0, w: 1, h: 1 };
390
+ const flags = 0x0f;
391
+ this.setCropAreaHandles(flags);
392
+ this.crop = options.crop;
393
+ this.dragOffsetX = 0;
394
+ this.dragOffsetY = 0;
395
+ // Create video element and load it
396
+ let video = this.video = options.video ?? document.createElement('video');
397
+ this.loop = options.loop ?? this.loop;
398
+ if (options.src) {
399
+ this.video.src = options.src;
400
+ this.loadVideo(options);
401
+ }
402
+ if (options.videoArea) {
403
+ options.videoArea.root.classList.add('lexvideoeditor');
404
+ options.videoArea.attach(this.cropArea);
405
+ videoArea.attach(options.videoArea);
406
+ }
407
+ else {
408
+ videoArea.attach(video);
409
+ videoArea.attach(this.cropArea);
410
+ videoArea.root.classList.add('lexvideoeditor');
411
+ }
412
+ this.controlsArea = controlsArea;
413
+ // Create playing timeline area and attach panels
414
+ let [topArea, bottomArea] = controlsArea.split({ type: 'vertical', sizes: ['50%', null],
415
+ minimizable: false, resize: false });
416
+ bottomArea.setSize([bottomArea.size[0], 40]);
417
+ let [leftArea, controlsRight] = bottomArea.split({ type: 'horizontal', sizes: ['92%', null],
418
+ minimizable: false, resize: false });
419
+ let [controlsLeft, timeBarArea] = leftArea.split({ type: 'horizontal', sizes: ['10%', null],
420
+ minimizable: false, resize: false });
421
+ topArea.root.classList.add('lexbar');
422
+ bottomArea.root.classList.add('lexbar');
423
+ this.controlsCurrentPanel = new LX.Panel({ className: 'lexcontrolspanel lextime' });
424
+ this.controlsCurrentPanel.refresh = () => {
425
+ this.controlsCurrentPanel.clear();
426
+ this.controlsCurrentPanel.addLabel(this.currentTimeString, { float: 'center' });
427
+ };
428
+ topArea.root.classList.add('lexflexarea');
429
+ topArea.attach(this.controlsCurrentPanel);
430
+ this.controlsCurrentPanel.refresh();
431
+ const style = getComputedStyle(bottomArea.root);
432
+ let padding = Number(style.getPropertyValue('padding').replace('px', ''));
433
+ this.timebar = new TimeBar(timeBarArea, TimeBar.TIMEBAR_TRIM, { offset: padding });
434
+ // Create controls panel (play/pause button and start time)
435
+ this.controlsPanelLeft = new LX.Panel({ className: 'lexcontrolspanel' });
436
+ this.controlsPanelLeft.refresh = () => {
437
+ this.controlsPanelLeft.clear();
438
+ this.controlsPanelLeft.sameLine();
439
+ let playbtn = this.controlsPanelLeft.addButton('Play', '', (v) => {
440
+ this.playing = v;
441
+ if (this.playing) {
442
+ if (this.video.currentTime + 0.000001 >= this.endTime) {
443
+ this.video.currentTime = this.startTime;
444
+ }
445
+ this.video.play();
446
+ }
447
+ else {
448
+ this.video.pause();
449
+ }
450
+ }, { width: '40px', icon: 'Play@solid', swap: 'Pause@solid', hideName: true,
451
+ className: 'justify-center' });
452
+ playbtn.setState(this.playing, true);
453
+ this.controlsPanelLeft.addButton('', '', (v, e) => {
454
+ const panel = new LX.Panel();
455
+ panel.addRange('Speed', this.speed, (v) => {
456
+ this.speed = v;
457
+ this.video.playbackRate = v;
458
+ if (this.onChangeSpeed) {
459
+ this.onChangeSpeed(v);
460
+ }
461
+ }, { min: 0, max: 2.5, step: 0.01, hideName: true });
462
+ new LX.Popover(e.target, [panel], { align: 'start', side: 'top', sideOffset: 12 });
463
+ }, { width: '40px', title: 'speed', icon: 'Timer@solid', className: 'justify-center' });
464
+ this.controlsPanelLeft.addButton('', 'Loop', (v) => {
465
+ this.loop = v;
466
+ }, { width: '40px', title: 'loop', icon: ('Repeat@solid'), className: `justify-center`, selectable: true,
467
+ selected: this.loop });
468
+ this.controlsPanelLeft.addLabel(this.startTimeString, { width: '100px' });
469
+ this.controlsPanelLeft.endLine();
470
+ let availableWidth = leftArea.root.clientWidth - controlsLeft.root.clientWidth;
471
+ this.timebar.resize([availableWidth, timeBarArea.root.clientHeight]);
472
+ };
473
+ this.controlsPanelLeft.refresh();
474
+ controlsLeft.root.style.minWidth = 'fit-content';
475
+ // controlsLeft.root.classList.add();
476
+ controlsLeft.attach(this.controlsPanelLeft);
477
+ // Create right controls panel (ens time)
478
+ this.controlsPanelRight = new LX.Panel({ className: 'lexcontrolspanel' });
479
+ this.controlsPanelRight.refresh = () => {
480
+ this.controlsPanelRight.clear();
481
+ this.controlsPanelRight.addLabel(this.endTimeString, { width: 100 });
482
+ };
483
+ this.controlsPanelRight.refresh();
484
+ controlsRight.root.style.minWidth = 'fit-content';
485
+ controlsRight.attach(this.controlsPanelRight);
486
+ this.timebar.onChangeCurrent = this._setCurrentTime.bind(this);
487
+ this.timebar.onChangeStart = this._setStartTime.bind(this);
488
+ this.timebar.onChangeEnd = this._setEndTime.bind(this);
489
+ this.resize = () => {
490
+ bottomArea.setSize([this.controlsArea.root.clientWidth, 40]);
491
+ let availableWidth = this.controlsArea.root.clientWidth - controlsLeft.root.clientWidth
492
+ - controlsRight.root.clientWidth;
493
+ this.timebar.resize([availableWidth, timeBarArea.root.clientHeight]);
494
+ this.moveCropArea(this.cropArea.normCoords.x, this.cropArea.normCoords.y, true);
495
+ this.resizeCropArea(this.cropArea.normCoords.w, this.cropArea.normCoords.h, true);
496
+ if (this.onResize) {
497
+ this.onResize([videoArea.root.clientWidth, videoArea.root.clientHeight]);
498
+ }
499
+ };
500
+ area.onresize = this.resize.bind(this);
501
+ window.addEventListener('resize', area.onresize);
502
+ this.onKeyUp = (e) => {
503
+ if (this.controls && e.key == ' ') {
504
+ e.preventDefault();
505
+ e.stopPropagation();
506
+ this.playing = !this.playing;
507
+ if (this.playing) {
508
+ if (this.video.currentTime + 0.000001 >= this.endTime) {
509
+ this.video.currentTime = this.startTime;
510
+ }
511
+ this.video.play();
512
+ }
513
+ else {
514
+ this.video.pause();
515
+ }
516
+ this.controlsPanelLeft.refresh();
517
+ }
518
+ };
519
+ window.addEventListener('keyup', this.onKeyUp);
520
+ const parent = controlsArea.parentElement ? controlsArea.parentElement : controlsArea.root.parentElement;
521
+ // Add canvas event listeneres
522
+ parent.addEventListener('mousedown', (e) => {
523
+ // if( this.controls) {
524
+ // this.timebar.onMouseDown(e);
525
+ // }
526
+ });
527
+ this._onCropMouseUp = (event) => {
528
+ // if(this.controls) {
529
+ // this.timebar.onMouseUp(event);
530
+ // }
531
+ event.preventDefault();
532
+ event.stopPropagation();
533
+ if ((this.isDragging || this.isResizing) && this.onCropArea) {
534
+ this.onCropArea(this.getCroppedArea());
535
+ }
536
+ this.isDragging = false;
537
+ this.isResizing = false;
538
+ document.removeEventListener('mouseup', this._onCropMouseUp); // self destroy. Added during mouseDown on cropArea and handles
539
+ document.removeEventListener('mousemove', this._onCropMouseMove); // self destroy. Added during mouseDown on cropArea and handles
540
+ };
541
+ this._onCropMouseMove = (event) => {
542
+ // if(this.controls) {
543
+ // this.timebar.onMouseMove(event);
544
+ // }
545
+ window.getSelection()?.removeAllRanges();
546
+ event.preventDefault();
547
+ event.stopPropagation();
548
+ if (this.isResizing) {
549
+ const rectCrop = this.cropArea.getBoundingClientRect();
550
+ const rectVideo = this.video.getBoundingClientRect();
551
+ const mov = this.isResizing.movement;
552
+ let x = rectCrop.left, y = rectCrop.top, w = rectCrop.width, h = rectCrop.height;
553
+ if (mov & VideoEditor.CROP_HANDLE_L) {
554
+ let mouseX = Math.min(rectCrop.right - 4, Math.max(rectVideo.left, event.clientX)); // -4 because of border
555
+ w = rectCrop.left + rectCrop.width - mouseX;
556
+ x = mouseX;
557
+ if (mouseX < rectCrop.left) {
558
+ this.moveCropArea(x, y, false);
559
+ this.resizeCropArea(w, h, false);
560
+ }
561
+ else {
562
+ this.resizeCropArea(w, h, false);
563
+ this.moveCropArea(x, y, false);
564
+ }
565
+ }
566
+ if (mov & VideoEditor.CROP_HANDLE_R) {
567
+ w = event.clientX - rectCrop.left;
568
+ this.resizeCropArea(w, h, false);
569
+ }
570
+ if (mov & VideoEditor.CROP_HANDLE_T) {
571
+ const mouseY = Math.min(rectCrop.bottom - 4, Math.max(rectVideo.top, event.clientY));
572
+ h = rectCrop.top + rectCrop.height - mouseY;
573
+ y = mouseY;
574
+ if (mouseY < rectCrop.top) {
575
+ this.moveCropArea(x, y, false);
576
+ this.resizeCropArea(w, h, false);
577
+ }
578
+ else {
579
+ this.resizeCropArea(w, h, false);
580
+ this.moveCropArea(x, y, false);
581
+ }
582
+ }
583
+ if (mov & VideoEditor.CROP_HANDLE_B) {
584
+ h = event.clientY - rectCrop.top;
585
+ this.resizeCropArea(w, h, false);
586
+ }
587
+ }
588
+ if (this.isDragging) {
589
+ this.moveCropArea(event.clientX - this.dragOffsetX, event.clientY - this.dragOffsetY, false);
590
+ }
591
+ };
592
+ this.cropArea.addEventListener('mousedown', (e) => {
593
+ if (e.target === this.cropArea) {
594
+ const rect = this.cropArea.getBoundingClientRect();
595
+ this.isDragging = true;
596
+ this.dragOffsetX = e.clientX - rect.left;
597
+ this.dragOffsetY = e.clientY - rect.top;
598
+ document.addEventListener('mouseup', this._onCropMouseUp);
599
+ document.addEventListener('mousemove', this._onCropMouseMove);
600
+ }
601
+ });
602
+ this.onChangeStart = null;
603
+ this.onChangeEnd = null;
604
+ }
605
+ setCropAreaHandles(flags) {
606
+ // remove existing resizer handles
607
+ const resizers = this.cropArea.getElementsByClassName('resize-handle');
608
+ for (let i = resizers.length - 1; i > -1; --i) {
609
+ resizers[i].remove();
610
+ }
611
+ const buildResizer = (className, movement) => {
612
+ const handle = document.createElement('div');
613
+ handle.className = ' resize-handle ' + className;
614
+ handle.movement = movement;
615
+ if (this.options.handleStyle) {
616
+ Object.assign(handle.style, this.options.handleStyle);
617
+ }
618
+ this.cropArea.append(handle);
619
+ handle.addEventListener('mousedown', (e) => {
620
+ e.stopPropagation();
621
+ e.preventDefault();
622
+ this.isResizing = handle;
623
+ document.addEventListener('mouseup', this._onCropMouseUp);
624
+ document.addEventListener('mousemove', this._onCropMouseMove);
625
+ });
626
+ };
627
+ if (flags & VideoEditor.CROP_HANDLE_L)
628
+ buildResizer('l', VideoEditor.CROP_HANDLE_L);
629
+ if (flags & VideoEditor.CROP_HANDLE_R)
630
+ buildResizer('r', VideoEditor.CROP_HANDLE_R);
631
+ if (flags & VideoEditor.CROP_HANDLE_T)
632
+ buildResizer('t', VideoEditor.CROP_HANDLE_T);
633
+ if (flags & VideoEditor.CROP_HANDLE_B)
634
+ buildResizer('b', VideoEditor.CROP_HANDLE_B);
635
+ if ((flags & VideoEditor.CROP_HANDLE_TL) == VideoEditor.CROP_HANDLE_TL) {
636
+ buildResizer('tl', VideoEditor.CROP_HANDLE_TL);
637
+ }
638
+ if ((flags & VideoEditor.CROP_HANDLE_BL) == VideoEditor.CROP_HANDLE_BL) {
639
+ buildResizer('bl', VideoEditor.CROP_HANDLE_BL);
640
+ }
641
+ if ((flags & VideoEditor.CROP_HANDLE_TR) == VideoEditor.CROP_HANDLE_TR) {
642
+ buildResizer('tr', VideoEditor.CROP_HANDLE_TR);
643
+ }
644
+ if ((flags & VideoEditor.CROP_HANDLE_BR) == VideoEditor.CROP_HANDLE_BR) {
645
+ buildResizer('br', VideoEditor.CROP_HANDLE_BR);
646
+ }
647
+ }
648
+ resizeCropArea(sx, sy, isNormalized = true) {
649
+ const rectVideo = this.video.getBoundingClientRect();
650
+ if (!isNormalized) {
651
+ sx = (rectVideo.width) ? (sx / rectVideo.width) : 1;
652
+ sy = (rectVideo.height) ? (sy / rectVideo.height) : 1;
653
+ }
654
+ sx = Math.min(1 - this.cropArea.normCoords.x, Math.max(0, sx));
655
+ sy = Math.min(1 - this.cropArea.normCoords.y, Math.max(0, sy));
656
+ this.cropArea.normCoords.w = sx;
657
+ this.cropArea.normCoords.h = sy;
658
+ const widthPx = rectVideo.width * sx;
659
+ const heightPx = rectVideo.height * sy;
660
+ const xPx = rectVideo.width * this.cropArea.normCoords.x + rectVideo.left;
661
+ const yPx = rectVideo.height * this.cropArea.normCoords.y + rectVideo.top;
662
+ if (!this.cropArea.classList.contains('hidden')) {
663
+ const nodes = this.cropArea.parentElement.childNodes;
664
+ for (let i = 0; i < nodes.length; i++) {
665
+ if (nodes[i] != this.cropArea) {
666
+ const rectEl = nodes[i].getBoundingClientRect();
667
+ nodes[i].style.webkitMask = `linear-gradient(#000 0 0) ${xPx - rectEl.left}px ${yPx - rectEl.top}px / ${widthPx}px ${heightPx}px, linear-gradient(rgba(0, 0, 0, 0.3) 0 0)`;
668
+ nodes[i].style.webkitMaskRepeat = 'no-repeat';
669
+ }
670
+ }
671
+ }
672
+ this.cropArea.style.width = widthPx + 'px';
673
+ this.cropArea.style.height = heightPx + 'px';
674
+ }
675
+ // screen pixel (event.clientX) or video normalized (0 is top left of video, 1 bot right)
676
+ moveCropArea(x, y, isNormalized = true) {
677
+ const rectVideo = this.video.getBoundingClientRect();
678
+ if (!isNormalized) {
679
+ x = (rectVideo.width) ? ((x - rectVideo.left) / rectVideo.width) : 0;
680
+ y = (rectVideo.height) ? ((y - rectVideo.top) / rectVideo.height) : 0;
681
+ }
682
+ x = Math.max(0, Math.min(1 - this.cropArea.normCoords.w, x));
683
+ y = Math.max(0, Math.min(1 - this.cropArea.normCoords.h, y));
684
+ this.cropArea.normCoords.x = x;
685
+ this.cropArea.normCoords.y = y;
686
+ const xPx = rectVideo.width * x + rectVideo.left;
687
+ const yPx = rectVideo.height * y + rectVideo.top;
688
+ const widthPx = rectVideo.width * this.cropArea.normCoords.w;
689
+ const heightPx = rectVideo.height * this.cropArea.normCoords.h;
690
+ if (!this.cropArea.classList.contains('hidden')) {
691
+ const nodes = this.cropArea.parentElement.childNodes;
692
+ for (let i = 0; i < nodes.length; i++) {
693
+ if (nodes[i] != this.cropArea) {
694
+ const rectEl = nodes[i].getBoundingClientRect();
695
+ nodes[i].style.webkitMask = `linear-gradient(#000 0 0) ${xPx - rectEl.left}px ${yPx - rectEl.top}px / ${widthPx}px ${heightPx}px, linear-gradient(rgba(0, 0, 0, 0.3) 0 0)`;
696
+ nodes[i].style.webkitMaskRepeat = 'no-repeat';
697
+ }
698
+ }
699
+ }
700
+ const rectParent = this.cropArea.parentElement.getBoundingClientRect();
701
+ this.cropArea.style.left = xPx - rectParent.left + 'px';
702
+ this.cropArea.style.top = yPx - rectParent.top + 'px';
703
+ }
704
+ async loadVideo(options = {}) {
705
+ this.videoReady = false;
706
+ while (this.video.duration === Infinity || isNaN(this.video.duration) || !this.timebar) {
707
+ await new Promise((r) => setTimeout(r, 1000));
708
+ this.video.currentTime = 10000000 * Math.random();
709
+ }
710
+ this.video.currentTime = 0.01; // BUG: some videos will not play unless this line is present
711
+ // Duration can change if the video is dynamic (stream). This function is to ensure to load all buffer data
712
+ const forceLoadChunks = () => {
713
+ const state = this.videoReady;
714
+ if (this.video.readyState > 3) {
715
+ this.videoReady = true;
716
+ }
717
+ if (!state) {
718
+ this.video.currentTime = this.video.duration;
719
+ }
720
+ };
721
+ this.video.addEventListener('canplaythrough', forceLoadChunks, { passive: true });
722
+ this.video.ondurationchange = (v) => {
723
+ if (this.video.duration != this.endTime) {
724
+ this.video.currentTime = this.startTime;
725
+ console.log('duration changed from', this.endTime, ' to ', this.video.duration);
726
+ this.endTime = this.video.duration;
727
+ this.timebar.setDuration(this.endTime);
728
+ this.timebar.setEndTime(this.endTime);
729
+ }
730
+ this.video.currentTime = this.startTime;
731
+ this.timebar.setCurrentTime(this.video.currentTime);
732
+ };
733
+ this.timebar.startX = this.timebar.position.x;
734
+ this.timebar.endX = this.timebar.position.x + this.timebar.lineWidth;
735
+ this.startTime = 0;
736
+ this.endTime = this.video.duration;
737
+ this.timebar.setDuration(this.endTime);
738
+ this.timebar.setEndTime(this.video.duration);
739
+ this.timebar.setStartTime(this.startTime);
740
+ this.timebar.setCurrentTime(this.startTime);
741
+ // this.timebar.setStartValue( this.timebar.startX);
742
+ // this.timebar.currentX = this._timeToX( this.video.currentTime);
743
+ // this.timebar.setCurrentValue( this.timebar.currentX);
744
+ // this.timebar.update( this.timebar.currentX );
745
+ // only have one update on flight
746
+ if (!this.requestId) {
747
+ this._update();
748
+ }
749
+ this.controls = options.controls ?? true;
750
+ if (!this.controls) {
751
+ this.hideControls();
752
+ }
753
+ this.cropArea.style.height = this.video.clientHeight + 'px';
754
+ this.cropArea.style.width = this.video.clientWidth + 'px';
755
+ this.moveCropArea(0, 0, true);
756
+ this.resizeCropArea(1, 1, true);
757
+ if (this.crop) {
758
+ this.showCropArea();
759
+ }
760
+ else {
761
+ this.hideCropArea();
762
+ }
763
+ window.addEventListener('keyup', this.onKeyUp);
764
+ if (this.onVideoLoaded) {
765
+ this.onVideoLoaded(this.video);
766
+ }
767
+ }
768
+ _update() {
769
+ // if( this.onDraw ) {
770
+ // this.onDraw();
771
+ // }
772
+ if (this.playing) {
773
+ if (this.video.currentTime + 0.000001 >= this.endTime) {
774
+ this.video.pause();
775
+ if (!this.loop) {
776
+ this.playing = false;
777
+ this.controlsPanelLeft.refresh();
778
+ }
779
+ else {
780
+ this.video.currentTime = this.startTime;
781
+ this.video.play();
782
+ }
783
+ }
784
+ this._updateTime = false;
785
+ this.timebar.setCurrentTime(this.video.currentTime);
786
+ this._updateTime = true;
787
+ }
788
+ this.requestId = requestAnimationFrame(this._update.bind(this));
789
+ }
790
+ timeToString(t) {
791
+ let mzminutes = Math.floor(t / 60);
792
+ let mzseconds = Math.floor(t - (mzminutes * 60));
793
+ let mzmiliseconds = Math.floor((t - mzseconds) * 100);
794
+ let mzmilisecondsStr = mzmiliseconds < 10 ? ('0' + mzmiliseconds) : mzmiliseconds.toString();
795
+ let mzsecondsStr = mzseconds < 10 ? ('0' + mzseconds) : mzseconds.toString();
796
+ let mzminutesStr = mzminutes < 10 ? ('0' + mzminutes) : mzminutes.toString();
797
+ return `${mzminutesStr}:${mzsecondsStr}.${mzmilisecondsStr}`;
798
+ }
799
+ _setCurrentTime(t) {
800
+ if (this.video.currentTime != t && this._updateTime) {
801
+ this.video.currentTime = t;
802
+ }
803
+ this.currentTimeString = this.timeToString(t);
804
+ this.controlsCurrentPanel.refresh();
805
+ if (this.onSetTime) {
806
+ this.onSetTime(t);
807
+ }
808
+ if (this.onChangeCurrent) {
809
+ this.onChangeCurrent(t);
810
+ }
811
+ }
812
+ _setStartTime(t) {
813
+ this.startTime = this.video.currentTime = t;
814
+ this.startTimeString = this.timeToString(t);
815
+ this.controlsPanelLeft.refresh();
816
+ if (this.onSetTime) {
817
+ this.onSetTime(t);
818
+ }
819
+ if (this.onChangeStart) {
820
+ this.onChangeStart(t);
821
+ }
822
+ }
823
+ _setEndTime(t) {
824
+ this.endTime = this.video.currentTime = t;
825
+ this.endTimeString = this.timeToString(t);
826
+ this.controlsPanelRight.refresh();
827
+ if (this.onSetTime) {
828
+ this.onSetTime(t);
829
+ }
830
+ if (this.onChangeEnd) {
831
+ this.onChangeEnd(t);
832
+ }
833
+ }
834
+ getStartTime() {
835
+ return this.startTime;
836
+ }
837
+ getEndTime() {
838
+ return this.endTime;
839
+ }
840
+ getTrimedTimes() {
841
+ return { start: this.startTime, end: this.endTime };
842
+ }
843
+ getCroppedArea() {
844
+ return this.cropArea.getBoundingClientRect();
845
+ }
846
+ showCropArea() {
847
+ this.cropArea.classList.remove('hidden');
848
+ const nodes = this.cropArea.parentElement?.childNodes ?? [];
849
+ const rect = this.cropArea.getBoundingClientRect();
850
+ for (let i = 0; i < nodes.length; i++) {
851
+ const node = nodes[i];
852
+ if (node == this.cropArea)
853
+ continue;
854
+ const rectEl = node.getBoundingClientRect();
855
+ node.style.webkitMask = `linear-gradient(#000 0 0) ${rect.left - rectEl.left}px ${rect.top - rectEl.top}px / ${rect.width}px ${rect.height}px, linear-gradient(rgba(0, 0, 0, 0.3) 0 0)`;
856
+ node.style.webkitMaskRepeat = 'no-repeat';
857
+ }
858
+ }
859
+ hideCropArea() {
860
+ this.cropArea.classList.add('hidden');
861
+ const nodes = this.cropArea.parentElement?.childNodes ?? [];
862
+ for (let i = 0; i < nodes.length; i++) {
863
+ const node = nodes[i];
864
+ if (node == this.cropArea)
865
+ continue;
866
+ node.style.webkitMask = '';
867
+ node.style.webkitMaskRepeat = 'no-repeat';
868
+ }
869
+ }
870
+ showControls() {
871
+ this.controls = true;
872
+ this.controlsArea.show();
873
+ }
874
+ hideControls() {
875
+ this.controls = false;
876
+ this.controlsArea.hide();
877
+ }
878
+ stopUpdates() {
879
+ if (this.requestId) {
880
+ cancelAnimationFrame(this.requestId);
881
+ this.requestId = null;
882
+ }
883
+ }
884
+ unbind() {
885
+ this.stopUpdates();
886
+ this.video.pause();
887
+ this.playing = false;
888
+ this.controlsPanelLeft.refresh();
889
+ this.video.src = '';
890
+ window.removeEventListener('keyup', this.onKeyUp);
891
+ document.removeEventListener('mouseup', this._onCropMouseUp);
892
+ document.removeEventListener('mousemove', this._onCropMouseMove);
893
+ }
894
+ }
895
+ LX.VideoEditor = VideoEditor;
896
+
897
+ export { TimeBar, VideoEditor };
898
+ //# sourceMappingURL=VideoEditor.js.map