@twick/video-editor 0.15.13 → 0.15.14

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.mjs CHANGED
@@ -3,7 +3,7 @@ var __defNormalProp = (obj, key, value) => key in obj ? __defProp(obj, key, { en
3
3
  var __publicField = (obj, key, value) => __defNormalProp(obj, typeof key !== "symbol" ? key + "" : key, value);
4
4
  import { jsxs, jsx } from "react/jsx-runtime";
5
5
  import { useLivePlayerContext, PLAYER_STATE, LivePlayer } from "@twick/live-player";
6
- import { useTimelineContext, TIMELINE_ACTION, getCurrentElements, CaptionElement, ElementDeserializer, Track, getDecimalNumber, VideoElement, AudioElement, TrackElement, ValidationError, VALIDATION_ERROR_CODE } from "@twick/timeline";
6
+ import { useTimelineContext, TIMELINE_ACTION, getCurrentElements, CaptionElement as CaptionElement$1, ElementDeserializer, Track, getDecimalNumber, VideoElement as VideoElement$1, AudioElement, TrackElement, ValidationError, VALIDATION_ERROR_CODE } from "@twick/timeline";
7
7
  import React, { useState, useRef, useEffect, useMemo, forwardRef, createElement, createContext, useContext, useId, useCallback, useLayoutEffect, useInsertionEffect, Fragment, Component } from "react";
8
8
  function t(t2, e3, s2) {
9
9
  return (e3 = function(t3) {
@@ -6839,6 +6839,9 @@ class bh extends Va {
6839
6839
  }
6840
6840
  }
6841
6841
  t(bh, "type", "Vibrance"), t(bh, "defaults", { vibrance: 0 }), t(bh, "uniformLocations", ["uVibrance"]), tt.setClass(bh);
6842
+ var __defProp2 = Object.defineProperty;
6843
+ var __defNormalProp2 = (obj, key, value) => key in obj ? __defProp2(obj, key, { enumerable: true, configurable: true, writable: true, value }) : obj[key] = value;
6844
+ var __publicField2 = (obj, key, value) => __defNormalProp2(obj, key + "", value);
6842
6845
  const DEFAULT_TEXT_PROPS = {
6843
6846
  /** Font family for text elements */
6844
6847
  family: "Poppins",
@@ -6877,7 +6880,9 @@ const CANVAS_OPERATIONS = {
6877
6880
  /** An item has been updated/modified on the canvas */
6878
6881
  ITEM_UPDATED: "ITEM_UPDATED",
6879
6882
  /** Caption properties have been updated */
6880
- CAPTION_PROPS_UPDATED: "CAPTION_PROPS_UPDATED"
6883
+ CAPTION_PROPS_UPDATED: "CAPTION_PROPS_UPDATED",
6884
+ /** Watermark has been updated */
6885
+ WATERMARK_UPDATED: "WATERMARK_UPDATED"
6881
6886
  };
6882
6887
  const ELEMENT_TYPES = {
6883
6888
  /** Text element type */
@@ -6953,6 +6958,26 @@ const createCanvas = ({
6953
6958
  canvasMetadata
6954
6959
  };
6955
6960
  };
6961
+ function measureTextWidth(text, options) {
6962
+ if (typeof document === "undefined" || !text) return 0;
6963
+ const canvas = document.createElement("canvas");
6964
+ const ctx = canvas.getContext("2d");
6965
+ if (!ctx) return 0;
6966
+ const {
6967
+ fontSize,
6968
+ fontFamily,
6969
+ fontStyle = "normal",
6970
+ fontWeight = "normal"
6971
+ } = options;
6972
+ ctx.font = `${fontStyle} ${String(fontWeight)} ${fontSize}px ${fontFamily}`;
6973
+ const lines = text.split("\n");
6974
+ let maxWidth = 0;
6975
+ for (const line of lines) {
6976
+ const { width } = ctx.measureText(line);
6977
+ if (width > maxWidth) maxWidth = width;
6978
+ }
6979
+ return Math.ceil(maxWidth);
6980
+ }
6956
6981
  const reorderElementsByZIndex = (canvas) => {
6957
6982
  if (!canvas) return;
6958
6983
  const backgroundColor = canvas.backgroundColor;
@@ -7000,6 +7025,17 @@ const getCurrentFrameEffect = (item, seekTime) => {
7000
7025
  }
7001
7026
  return currentFrameEffect;
7002
7027
  };
7028
+ const hexToRgba = (hex2, alpha2) => {
7029
+ const color2 = hex2.replace(/^#/, "");
7030
+ const fullHex = color2.length === 3 ? color2.split("").map((c2) => c2 + c2).join("") : color2;
7031
+ if (fullHex.length !== 6) {
7032
+ return hex2;
7033
+ }
7034
+ const r2 = parseInt(fullHex.slice(0, 2), 16);
7035
+ const g2 = parseInt(fullHex.slice(2, 4), 16);
7036
+ const b2 = parseInt(fullHex.slice(4, 6), 16);
7037
+ return `rgba(${r2}, ${g2}, ${b2}, ${alpha2})`;
7038
+ };
7003
7039
  const disabledControl = new ai({
7004
7040
  /** X position offset */
7005
7041
  x: 0,
@@ -7431,40 +7467,66 @@ const addTextElement = ({
7431
7467
  canvas,
7432
7468
  canvasMetadata
7433
7469
  }) => {
7434
- var _a, _b, _c, _d, _e2, _f, _g, _h2, _i2, _j, _k, _l, _m, _n2, _o2, _p, _q, _r2, _s2, _t2, _u, _v, _w, _x, _y;
7470
+ var _a, _b, _c, _d, _e2, _f, _g, _h2, _i2, _j, _k, _l, _m, _n2, _o2, _p, _q, _r2, _s2, _t2, _u, _v, _w, _x, _y, _z, _A, _B, _C;
7435
7471
  const { x: x2, y: y2 } = convertToCanvasPosition(
7436
7472
  ((_a = element.props) == null ? void 0 : _a.x) || 0,
7437
7473
  ((_b = element.props) == null ? void 0 : _b.y) || 0,
7438
7474
  canvasMetadata
7439
7475
  );
7440
- let width = ((_c = element.props) == null ? void 0 : _c.width) ? element.props.width * canvasMetadata.scaleX : canvasMetadata.width - 2 * MARGIN;
7441
- if ((_d = element.props) == null ? void 0 : _d.maxWidth) {
7442
- width = Math.min(width, element.props.maxWidth * canvasMetadata.scaleX);
7443
- }
7444
- const text = new Uo(((_e2 = element.props) == null ? void 0 : _e2.text) || element.t || "", {
7476
+ const fontSize = Math.floor(
7477
+ (((_c = element.props) == null ? void 0 : _c.fontSize) || DEFAULT_TEXT_PROPS.size) * canvasMetadata.scaleX
7478
+ );
7479
+ const fontFamily = ((_d = element.props) == null ? void 0 : _d.fontFamily) || DEFAULT_TEXT_PROPS.family;
7480
+ const fontStyle = ((_e2 = element.props) == null ? void 0 : _e2.fontStyle) || "normal";
7481
+ const fontWeight = ((_f = element.props) == null ? void 0 : _f.fontWeight) || "normal";
7482
+ let width;
7483
+ if (((_g = element.props) == null ? void 0 : _g.width) != null && element.props.width > 0) {
7484
+ width = element.props.width * canvasMetadata.scaleX;
7485
+ if ((_h2 = element.props) == null ? void 0 : _h2.maxWidth) {
7486
+ width = Math.min(width, element.props.maxWidth * canvasMetadata.scaleX);
7487
+ }
7488
+ } else {
7489
+ const textContent = ((_i2 = element.props) == null ? void 0 : _i2.text) ?? element.t ?? "";
7490
+ width = measureTextWidth(textContent, {
7491
+ fontSize,
7492
+ fontFamily,
7493
+ fontStyle,
7494
+ fontWeight
7495
+ });
7496
+ const padding = 4;
7497
+ width = width + padding * 2;
7498
+ if ((_j = element.props) == null ? void 0 : _j.maxWidth) {
7499
+ width = Math.min(width, element.props.maxWidth * canvasMetadata.scaleX);
7500
+ }
7501
+ if (width <= 0) width = 100;
7502
+ }
7503
+ const backgroundColor = ((_k = element.props) == null ? void 0 : _k.backgroundColor) ? hexToRgba(
7504
+ element.props.backgroundColor,
7505
+ ((_l = element.props) == null ? void 0 : _l.backgroundOpacity) ?? 1
7506
+ ) : void 0;
7507
+ const text = new Uo(((_m = element.props) == null ? void 0 : _m.text) || element.t || "", {
7445
7508
  left: x2,
7446
7509
  top: y2,
7447
7510
  originX: "center",
7448
7511
  originY: "center",
7449
- angle: ((_f = element.props) == null ? void 0 : _f.rotation) || 0,
7450
- fontSize: Math.floor(
7451
- (((_g = element.props) == null ? void 0 : _g.fontSize) || DEFAULT_TEXT_PROPS.size) * canvasMetadata.scaleX
7452
- ),
7453
- fontFamily: ((_h2 = element.props) == null ? void 0 : _h2.fontFamily) || DEFAULT_TEXT_PROPS.family,
7454
- fontStyle: ((_i2 = element.props) == null ? void 0 : _i2.fontStyle) || "normal",
7455
- fontWeight: ((_j = element.props) == null ? void 0 : _j.fontWeight) || "normal",
7456
- fill: ((_k = element.props) == null ? void 0 : _k.fill) || DEFAULT_TEXT_PROPS.fill,
7457
- opacity: ((_l = element.props) == null ? void 0 : _l.opacity) ?? 1,
7512
+ angle: ((_n2 = element.props) == null ? void 0 : _n2.rotation) || 0,
7513
+ fontSize,
7514
+ fontFamily,
7515
+ fontStyle,
7516
+ fontWeight,
7517
+ fill: ((_o2 = element.props) == null ? void 0 : _o2.fill) || DEFAULT_TEXT_PROPS.fill,
7518
+ opacity: ((_p = element.props) == null ? void 0 : _p.opacity) ?? 1,
7458
7519
  width,
7459
7520
  splitByGrapheme: false,
7460
- textAlign: ((_m = element.props) == null ? void 0 : _m.textAlign) || "center",
7461
- stroke: ((_n2 = element.props) == null ? void 0 : _n2.stroke) || DEFAULT_TEXT_PROPS.stroke,
7462
- strokeWidth: ((_o2 = element.props) == null ? void 0 : _o2.lineWidth) || DEFAULT_TEXT_PROPS.lineWidth,
7463
- shadow: ((_p = element.props) == null ? void 0 : _p.shadowColor) ? new Ds({
7464
- offsetX: ((_r2 = (_q = element.props) == null ? void 0 : _q.shadowOffset) == null ? void 0 : _r2.length) && ((_t2 = (_s2 = element.props) == null ? void 0 : _s2.shadowOffset) == null ? void 0 : _t2.length) > 1 ? element.props.shadowOffset[0] / 2 : 1,
7465
- offsetY: ((_v = (_u = element.props) == null ? void 0 : _u.shadowOffset) == null ? void 0 : _v.length) && ((_w = element.props) == null ? void 0 : _w.shadowOffset.length) > 1 ? element.props.shadowOffset[1] / 2 : 1,
7466
- blur: (((_x = element.props) == null ? void 0 : _x.shadowBlur) || 2) / 2,
7467
- color: (_y = element.props) == null ? void 0 : _y.shadowColor
7521
+ textAlign: ((_q = element.props) == null ? void 0 : _q.textAlign) || "center",
7522
+ stroke: ((_r2 = element.props) == null ? void 0 : _r2.stroke) || DEFAULT_TEXT_PROPS.stroke,
7523
+ strokeWidth: ((_s2 = element.props) == null ? void 0 : _s2.lineWidth) || DEFAULT_TEXT_PROPS.lineWidth,
7524
+ ...backgroundColor && { backgroundColor },
7525
+ shadow: ((_t2 = element.props) == null ? void 0 : _t2.shadowColor) ? new Ds({
7526
+ offsetX: ((_v = (_u = element.props) == null ? void 0 : _u.shadowOffset) == null ? void 0 : _v.length) && ((_x = (_w = element.props) == null ? void 0 : _w.shadowOffset) == null ? void 0 : _x.length) > 1 ? element.props.shadowOffset[0] / 2 : 1,
7527
+ offsetY: ((_z = (_y = element.props) == null ? void 0 : _y.shadowOffset) == null ? void 0 : _z.length) && ((_A = element.props) == null ? void 0 : _A.shadowOffset.length) > 1 ? element.props.shadowOffset[1] / 2 : 1,
7528
+ blur: (((_B = element.props) == null ? void 0 : _B.shadowBlur) || 2) / 2,
7529
+ color: (_C = element.props) == null ? void 0 : _C.shadowColor
7468
7530
  }) : void 0
7469
7531
  });
7470
7532
  text.set("id", element.id);
@@ -7836,12 +7898,419 @@ const addBackgroundColor = ({
7836
7898
  canvas.add(bgRect);
7837
7899
  return bgRect;
7838
7900
  };
7901
+ const VideoElement = {
7902
+ name: ELEMENT_TYPES.VIDEO,
7903
+ async add(params) {
7904
+ var _a, _b;
7905
+ const {
7906
+ element,
7907
+ index,
7908
+ canvas,
7909
+ canvasMetadata,
7910
+ seekTime = 0,
7911
+ elementFrameMapRef,
7912
+ getCurrentFrameEffect: getFrameEffect
7913
+ } = params;
7914
+ if (!getFrameEffect || !elementFrameMapRef) return;
7915
+ const currentFrameEffect = getFrameEffect(element, seekTime);
7916
+ elementFrameMapRef.current[element.id] = currentFrameEffect;
7917
+ const snapTime = (seekTime - ((element == null ? void 0 : element.s) ?? 0)) * (((_a = element == null ? void 0 : element.props) == null ? void 0 : _a.playbackRate) ?? 1) + (((_b = element == null ? void 0 : element.props) == null ? void 0 : _b.time) ?? 0);
7918
+ await addVideoElement({
7919
+ element,
7920
+ index,
7921
+ canvas,
7922
+ canvasMetadata,
7923
+ currentFrameEffect,
7924
+ snapTime
7925
+ });
7926
+ if (element.timelineType === "scene") {
7927
+ await addBackgroundColor({
7928
+ element,
7929
+ index,
7930
+ canvas,
7931
+ canvasMetadata
7932
+ });
7933
+ }
7934
+ },
7935
+ updateFromFabricObject(object, element, context) {
7936
+ const { x: x2, y: y2 } = convertToVideoPosition(
7937
+ object.left,
7938
+ object.top,
7939
+ context.canvasMetadata,
7940
+ context.videoSize
7941
+ );
7942
+ const currentFrameEffect = context.elementFrameMapRef.current[element.id];
7943
+ let updatedFrameSize;
7944
+ if (currentFrameEffect) {
7945
+ updatedFrameSize = [
7946
+ currentFrameEffect.props.frameSize[0] * object.scaleX,
7947
+ currentFrameEffect.props.frameSize[1] * object.scaleY
7948
+ ];
7949
+ context.elementFrameMapRef.current[element.id] = {
7950
+ ...currentFrameEffect,
7951
+ props: {
7952
+ ...currentFrameEffect.props,
7953
+ framePosition: { x: x2, y: y2 },
7954
+ frameSize: updatedFrameSize
7955
+ }
7956
+ };
7957
+ return {
7958
+ element: {
7959
+ ...element,
7960
+ frameEffects: (element.frameEffects || []).map(
7961
+ (fe2) => fe2.id === (currentFrameEffect == null ? void 0 : currentFrameEffect.id) ? {
7962
+ ...fe2,
7963
+ props: {
7964
+ ...fe2.props,
7965
+ framePosition: { x: x2, y: y2 },
7966
+ frameSize: updatedFrameSize
7967
+ }
7968
+ } : fe2
7969
+ )
7970
+ }
7971
+ };
7972
+ }
7973
+ const frame2 = element.frame;
7974
+ updatedFrameSize = [
7975
+ (frame2.size[0] ?? 0) * object.scaleX,
7976
+ (frame2.size[1] ?? 0) * object.scaleY
7977
+ ];
7978
+ return {
7979
+ element: {
7980
+ ...element,
7981
+ frame: {
7982
+ ...frame2,
7983
+ rotation: object.angle,
7984
+ size: updatedFrameSize,
7985
+ x: x2,
7986
+ y: y2
7987
+ }
7988
+ }
7989
+ };
7990
+ }
7991
+ };
7992
+ const ImageElement = {
7993
+ name: ELEMENT_TYPES.IMAGE,
7994
+ async add(params) {
7995
+ const { element, index, canvas, canvasMetadata } = params;
7996
+ await addImageElement({
7997
+ element,
7998
+ index,
7999
+ canvas,
8000
+ canvasMetadata
8001
+ });
8002
+ if (element.timelineType === "scene") {
8003
+ await addBackgroundColor({
8004
+ element,
8005
+ index,
8006
+ canvas,
8007
+ canvasMetadata
8008
+ });
8009
+ }
8010
+ },
8011
+ updateFromFabricObject(object, element, context) {
8012
+ var _a, _b;
8013
+ const { x: x2, y: y2 } = convertToVideoPosition(
8014
+ object.left,
8015
+ object.top,
8016
+ context.canvasMetadata,
8017
+ context.videoSize
8018
+ );
8019
+ const currentFrameEffect = context.elementFrameMapRef.current[element.id];
8020
+ if (object.type === "group") {
8021
+ let updatedFrameSize;
8022
+ if (currentFrameEffect) {
8023
+ updatedFrameSize = [
8024
+ currentFrameEffect.props.frameSize[0] * object.scaleX,
8025
+ currentFrameEffect.props.frameSize[1] * object.scaleY
8026
+ ];
8027
+ context.elementFrameMapRef.current[element.id] = {
8028
+ ...currentFrameEffect,
8029
+ props: {
8030
+ ...currentFrameEffect.props,
8031
+ framePosition: { x: x2, y: y2 },
8032
+ frameSize: updatedFrameSize
8033
+ }
8034
+ };
8035
+ return {
8036
+ element: {
8037
+ ...element,
8038
+ frameEffects: (element.frameEffects || []).map(
8039
+ (fe2) => fe2.id === (currentFrameEffect == null ? void 0 : currentFrameEffect.id) ? {
8040
+ ...fe2,
8041
+ props: {
8042
+ ...fe2.props,
8043
+ framePosition: { x: x2, y: y2 },
8044
+ frameSize: updatedFrameSize
8045
+ }
8046
+ } : fe2
8047
+ )
8048
+ }
8049
+ };
8050
+ }
8051
+ const frame2 = element.frame;
8052
+ updatedFrameSize = [
8053
+ (frame2.size[0] ?? 0) * object.scaleX,
8054
+ (frame2.size[1] ?? 0) * object.scaleY
8055
+ ];
8056
+ return {
8057
+ element: {
8058
+ ...element,
8059
+ frame: {
8060
+ ...frame2,
8061
+ rotation: object.angle,
8062
+ size: updatedFrameSize,
8063
+ x: x2,
8064
+ y: y2
8065
+ }
8066
+ }
8067
+ };
8068
+ }
8069
+ return {
8070
+ element: {
8071
+ ...element,
8072
+ props: {
8073
+ ...element.props,
8074
+ rotation: object.angle,
8075
+ width: (((_a = element.props) == null ? void 0 : _a.width) ?? 0) * object.scaleX,
8076
+ height: (((_b = element.props) == null ? void 0 : _b.height) ?? 0) * object.scaleY,
8077
+ x: x2,
8078
+ y: y2
8079
+ }
8080
+ }
8081
+ };
8082
+ }
8083
+ };
8084
+ const RectElement = {
8085
+ name: ELEMENT_TYPES.RECT,
8086
+ async add(params) {
8087
+ const { element, index, canvas, canvasMetadata } = params;
8088
+ await addRectElement({
8089
+ element,
8090
+ index,
8091
+ canvas,
8092
+ canvasMetadata
8093
+ });
8094
+ },
8095
+ updateFromFabricObject(object, element, context) {
8096
+ var _a, _b;
8097
+ const { x: x2, y: y2 } = convertToVideoPosition(
8098
+ object.left,
8099
+ object.top,
8100
+ context.canvasMetadata,
8101
+ context.videoSize
8102
+ );
8103
+ return {
8104
+ element: {
8105
+ ...element,
8106
+ props: {
8107
+ ...element.props,
8108
+ rotation: object.angle,
8109
+ width: (((_a = element.props) == null ? void 0 : _a.width) ?? 0) * object.scaleX,
8110
+ height: (((_b = element.props) == null ? void 0 : _b.height) ?? 0) * object.scaleY,
8111
+ x: x2,
8112
+ y: y2
8113
+ }
8114
+ }
8115
+ };
8116
+ }
8117
+ };
8118
+ const CircleElement = {
8119
+ name: ELEMENT_TYPES.CIRCLE,
8120
+ async add(params) {
8121
+ const { element, index, canvas, canvasMetadata } = params;
8122
+ await addCircleElement({
8123
+ element,
8124
+ index,
8125
+ canvas,
8126
+ canvasMetadata
8127
+ });
8128
+ },
8129
+ updateFromFabricObject(object, element, context) {
8130
+ var _a;
8131
+ const { x: x2, y: y2 } = convertToVideoPosition(
8132
+ object.left,
8133
+ object.top,
8134
+ context.canvasMetadata,
8135
+ context.videoSize
8136
+ );
8137
+ const radius = Number(
8138
+ ((((_a = element.props) == null ? void 0 : _a.radius) ?? 0) * object.scaleX).toFixed(2)
8139
+ );
8140
+ return {
8141
+ element: {
8142
+ ...element,
8143
+ props: {
8144
+ ...element.props,
8145
+ rotation: object.angle,
8146
+ radius,
8147
+ height: radius * 2,
8148
+ width: radius * 2,
8149
+ x: x2,
8150
+ y: y2
8151
+ }
8152
+ }
8153
+ };
8154
+ }
8155
+ };
8156
+ const TextElement = {
8157
+ name: ELEMENT_TYPES.TEXT,
8158
+ async add(params) {
8159
+ const { element, index, canvas, canvasMetadata } = params;
8160
+ await addTextElement({
8161
+ element,
8162
+ index,
8163
+ canvas,
8164
+ canvasMetadata
8165
+ });
8166
+ },
8167
+ updateFromFabricObject(object, element, context) {
8168
+ const { x: x2, y: y2 } = convertToVideoPosition(
8169
+ object.left,
8170
+ object.top,
8171
+ context.canvasMetadata,
8172
+ context.videoSize
8173
+ );
8174
+ return {
8175
+ element: {
8176
+ ...element,
8177
+ props: {
8178
+ ...element.props,
8179
+ rotation: object.angle,
8180
+ x: x2,
8181
+ y: y2
8182
+ }
8183
+ }
8184
+ };
8185
+ }
8186
+ };
8187
+ const CaptionElement = {
8188
+ name: ELEMENT_TYPES.CAPTION,
8189
+ async add(params) {
8190
+ const { element, index, canvas, captionProps, canvasMetadata } = params;
8191
+ await addCaptionElement({
8192
+ element,
8193
+ index,
8194
+ canvas,
8195
+ captionProps: captionProps ?? {},
8196
+ canvasMetadata
8197
+ });
8198
+ },
8199
+ updateFromFabricObject(object, element, context) {
8200
+ var _a;
8201
+ const { x: x2, y: y2 } = convertToVideoPosition(
8202
+ object.left,
8203
+ object.top,
8204
+ context.canvasMetadata,
8205
+ context.videoSize
8206
+ );
8207
+ if ((_a = context.captionPropsRef.current) == null ? void 0 : _a.applyToAll) {
8208
+ return {
8209
+ element,
8210
+ operation: CANVAS_OPERATIONS.CAPTION_PROPS_UPDATED,
8211
+ payload: {
8212
+ element,
8213
+ props: {
8214
+ ...context.captionPropsRef.current,
8215
+ x: x2,
8216
+ y: y2
8217
+ }
8218
+ }
8219
+ };
8220
+ }
8221
+ return {
8222
+ element: {
8223
+ ...element,
8224
+ props: {
8225
+ ...element.props,
8226
+ x: x2,
8227
+ y: y2
8228
+ }
8229
+ }
8230
+ };
8231
+ }
8232
+ };
8233
+ const WatermarkElement = {
8234
+ name: "watermark",
8235
+ async add(params) {
8236
+ const { element, index, canvas, canvasMetadata, watermarkPropsRef } = params;
8237
+ if (element.type === ELEMENT_TYPES.TEXT) {
8238
+ if (watermarkPropsRef) watermarkPropsRef.current = element.props;
8239
+ await addTextElement({
8240
+ element,
8241
+ index,
8242
+ canvas,
8243
+ canvasMetadata
8244
+ });
8245
+ } else if (element.type === ELEMENT_TYPES.IMAGE) {
8246
+ await addImageElement({
8247
+ element,
8248
+ index,
8249
+ canvas,
8250
+ canvasMetadata
8251
+ });
8252
+ }
8253
+ },
8254
+ updateFromFabricObject(object, element, context) {
8255
+ const { x: x2, y: y2 } = convertToVideoPosition(
8256
+ object.left,
8257
+ object.top,
8258
+ context.canvasMetadata,
8259
+ context.videoSize
8260
+ );
8261
+ const rotation = object.angle != null ? object.angle : void 0;
8262
+ const opacity = object.opacity != null ? object.opacity : void 0;
8263
+ const baseProps = element.type === ELEMENT_TYPES.TEXT ? context.watermarkPropsRef.current ?? element.props ?? {} : { ...element.props };
8264
+ const props = element.type === ELEMENT_TYPES.IMAGE && (object.scaleX != null || object.scaleY != null) ? {
8265
+ ...baseProps,
8266
+ width: baseProps.width != null && object.scaleX != null ? baseProps.width * object.scaleX : baseProps.width,
8267
+ height: baseProps.height != null && object.scaleY != null ? baseProps.height * object.scaleY : baseProps.height
8268
+ } : baseProps;
8269
+ const payload = {
8270
+ position: { x: x2, y: y2 },
8271
+ ...rotation != null && { rotation },
8272
+ ...opacity != null && { opacity },
8273
+ ...Object.keys(props).length > 0 && { props }
8274
+ };
8275
+ return {
8276
+ element: { ...element, props: { ...element.props, x: x2, y: y2, rotation, opacity, ...props } },
8277
+ operation: CANVAS_OPERATIONS.WATERMARK_UPDATED,
8278
+ payload
8279
+ };
8280
+ }
8281
+ };
8282
+ class ElementController {
8283
+ constructor() {
8284
+ __publicField2(this, "elements", /* @__PURE__ */ new Map());
8285
+ }
8286
+ register(handler) {
8287
+ this.elements.set(handler.name, handler);
8288
+ }
8289
+ get(name) {
8290
+ return this.elements.get(name);
8291
+ }
8292
+ list() {
8293
+ return Array.from(this.elements.keys());
8294
+ }
8295
+ }
8296
+ const elementController = new ElementController();
8297
+ function registerElements() {
8298
+ elementController.register(VideoElement);
8299
+ elementController.register(ImageElement);
8300
+ elementController.register(RectElement);
8301
+ elementController.register(CircleElement);
8302
+ elementController.register(TextElement);
8303
+ elementController.register(CaptionElement);
8304
+ elementController.register(WatermarkElement);
8305
+ }
8306
+ registerElements();
7839
8307
  const useTwickCanvas = ({
7840
8308
  onCanvasReady,
7841
8309
  onCanvasOperation
7842
8310
  }) => {
7843
8311
  const [twickCanvas, setTwickCanvas] = useState(null);
7844
8312
  const elementMap = useRef({});
8313
+ const watermarkPropsRef = useRef(null);
7845
8314
  const elementFrameMap = useRef({});
7846
8315
  const twickCanvasRef = useRef(null);
7847
8316
  const videoSizeRef = useRef({ width: 1, height: 1 });
@@ -7938,141 +8407,33 @@ const useTwickCanvas = ({
7938
8407
  case "scale":
7939
8408
  case "scaleX":
7940
8409
  case "scaleY":
7941
- case "rotate":
7942
- const { x: x2, y: y2 } = convertToVideoPosition(
7943
- object.left,
7944
- object.top,
7945
- canvasMetadataRef.current,
7946
- videoSizeRef.current
8410
+ case "rotate": {
8411
+ const currentElement = elementMap.current[elementId];
8412
+ const handler = elementController.get(
8413
+ elementId === "e-watermark" ? "watermark" : currentElement == null ? void 0 : currentElement.type
7947
8414
  );
7948
- if (elementMap.current[elementId].type === "caption") {
7949
- if ((_c = captionPropsRef.current) == null ? void 0 : _c.applyToAll) {
7950
- onCanvasOperation == null ? void 0 : onCanvasOperation(CANVAS_OPERATIONS.CAPTION_PROPS_UPDATED, {
7951
- element: elementMap.current[elementId],
7952
- props: {
7953
- ...captionPropsRef.current,
7954
- x: x2,
7955
- y: y2
7956
- }
7957
- });
7958
- } else {
7959
- elementMap.current[elementId] = {
7960
- ...elementMap.current[elementId],
7961
- props: {
7962
- ...elementMap.current[elementId].props,
7963
- x: x2,
7964
- y: y2
7965
- }
7966
- };
7967
- onCanvasOperation == null ? void 0 : onCanvasOperation(
7968
- CANVAS_OPERATIONS.ITEM_UPDATED,
7969
- elementMap.current[elementId]
7970
- );
7971
- }
7972
- } else {
7973
- if ((object == null ? void 0 : object.type) === "group") {
7974
- const currentFrameEffect = elementFrameMap.current[elementId];
7975
- let updatedFrameSize;
7976
- if (currentFrameEffect) {
7977
- updatedFrameSize = [
7978
- currentFrameEffect.props.frameSize[0] * object.scaleX,
7979
- currentFrameEffect.props.frameSize[1] * object.scaleY
7980
- ];
7981
- } else {
7982
- updatedFrameSize = [
7983
- elementMap.current[elementId].frame.size[0] * object.scaleX,
7984
- elementMap.current[elementId].frame.size[1] * object.scaleY
7985
- ];
7986
- }
7987
- if (currentFrameEffect) {
7988
- elementMap.current[elementId] = {
7989
- ...elementMap.current[elementId],
7990
- frameEffects: (elementMap.current[elementId].frameEffects || []).map(
7991
- (frameEffect) => frameEffect.id === (currentFrameEffect == null ? void 0 : currentFrameEffect.id) ? {
7992
- ...frameEffect,
7993
- props: {
7994
- ...frameEffect.props,
7995
- framePosition: {
7996
- x: x2,
7997
- y: y2
7998
- },
7999
- frameSize: updatedFrameSize
8000
- }
8001
- } : frameEffect
8002
- )
8003
- };
8004
- elementFrameMap.current[elementId] = {
8005
- ...elementFrameMap.current[elementId],
8006
- framePosition: {
8007
- x: x2,
8008
- y: y2
8009
- },
8010
- frameSize: updatedFrameSize
8011
- };
8012
- } else {
8013
- elementMap.current[elementId] = {
8014
- ...elementMap.current[elementId],
8015
- frame: {
8016
- ...elementMap.current[elementId].frame,
8017
- rotation: object.angle,
8018
- size: updatedFrameSize,
8019
- x: x2,
8020
- y: y2
8021
- }
8022
- };
8023
- }
8024
- } else {
8025
- if ((object == null ? void 0 : object.type) === "text") {
8026
- elementMap.current[elementId] = {
8027
- ...elementMap.current[elementId],
8028
- props: {
8029
- ...elementMap.current[elementId].props,
8030
- rotation: object.angle,
8031
- x: x2,
8032
- y: y2
8033
- }
8034
- };
8035
- } else if ((object == null ? void 0 : object.type) === "circle") {
8036
- const radius = Number(
8037
- (elementMap.current[elementId].props.radius * object.scaleX).toFixed(2)
8038
- );
8039
- elementMap.current[elementId] = {
8040
- ...elementMap.current[elementId],
8041
- props: {
8042
- ...elementMap.current[elementId].props,
8043
- rotation: object.angle,
8044
- radius,
8045
- height: radius * 2,
8046
- width: radius * 2,
8047
- x: x2,
8048
- y: y2
8049
- }
8050
- };
8051
- } else {
8052
- elementMap.current[elementId] = {
8053
- ...elementMap.current[elementId],
8054
- props: {
8055
- ...elementMap.current[elementId].props,
8056
- rotation: object.angle,
8057
- width: elementMap.current[elementId].props.width * object.scaleX,
8058
- height: elementMap.current[elementId].props.height * object.scaleY,
8059
- x: x2,
8060
- y: y2
8061
- }
8062
- };
8063
- }
8064
- }
8415
+ const result = (_c = handler == null ? void 0 : handler.updateFromFabricObject) == null ? void 0 : _c.call(handler, object, currentElement ?? { id: elementId, type: "text", props: {} }, {
8416
+ canvasMetadata: canvasMetadataRef.current,
8417
+ videoSize: videoSizeRef.current,
8418
+ elementFrameMapRef: elementFrameMap,
8419
+ captionPropsRef,
8420
+ watermarkPropsRef
8421
+ });
8422
+ if (result) {
8423
+ elementMap.current[elementId] = result.element;
8065
8424
  onCanvasOperation == null ? void 0 : onCanvasOperation(
8066
- CANVAS_OPERATIONS.ITEM_UPDATED,
8067
- elementMap.current[elementId]
8425
+ result.operation ?? CANVAS_OPERATIONS.ITEM_UPDATED,
8426
+ result.payload ?? result.element
8068
8427
  );
8069
8428
  }
8070
8429
  break;
8430
+ }
8071
8431
  }
8072
8432
  }
8073
8433
  };
8074
8434
  const setCanvasElements = async ({
8075
8435
  elements,
8436
+ watermark,
8076
8437
  seekTime = 0,
8077
8438
  captionProps,
8078
8439
  cleanAndAdd = false
@@ -8103,6 +8464,11 @@ const useTwickCanvas = ({
8103
8464
  }
8104
8465
  })
8105
8466
  );
8467
+ if (watermark) {
8468
+ addWatermarkToCanvas({
8469
+ element: watermark
8470
+ });
8471
+ }
8106
8472
  reorderElementsByZIndex(twickCanvas);
8107
8473
  } catch {
8108
8474
  }
@@ -8114,92 +8480,46 @@ const useTwickCanvas = ({
8114
8480
  seekTime,
8115
8481
  captionProps
8116
8482
  }) => {
8117
- var _a, _b;
8118
8483
  if (!twickCanvas) return;
8119
- switch (element.type) {
8120
- case ELEMENT_TYPES.VIDEO:
8121
- const currentFrameEffect = getCurrentFrameEffect(
8122
- element,
8123
- seekTime || 0
8124
- );
8125
- elementFrameMap.current[element.id] = currentFrameEffect;
8126
- const snapTime = ((seekTime || 0) - ((element == null ? void 0 : element.s) || 0)) * (((_a = element == null ? void 0 : element.props) == null ? void 0 : _a.playbackRate) || 1) + (((_b = element == null ? void 0 : element.props) == null ? void 0 : _b.time) || 0);
8127
- await addVideoElement({
8128
- element,
8129
- index,
8130
- canvas: twickCanvas,
8131
- canvasMetadata: canvasMetadataRef.current,
8132
- currentFrameEffect,
8133
- snapTime
8134
- });
8135
- if (element.timelineType === "scene") {
8136
- await addBackgroundColor({
8137
- element,
8138
- index,
8139
- canvas: twickCanvas,
8140
- canvasMetadata: canvasMetadataRef.current
8141
- });
8142
- }
8143
- break;
8144
- case ELEMENT_TYPES.IMAGE:
8145
- await addImageElement({
8146
- element,
8147
- index,
8148
- canvas: twickCanvas,
8149
- canvasMetadata: canvasMetadataRef.current
8150
- });
8151
- if (element.timelineType === "scene") {
8152
- await addBackgroundColor({
8153
- element,
8154
- index,
8155
- canvas: twickCanvas,
8156
- canvasMetadata: canvasMetadataRef.current
8157
- });
8158
- }
8159
- break;
8160
- case ELEMENT_TYPES.RECT:
8161
- await addRectElement({
8162
- element,
8163
- index,
8164
- canvas: twickCanvas,
8165
- canvasMetadata: canvasMetadataRef.current
8166
- });
8167
- break;
8168
- case ELEMENT_TYPES.CIRCLE:
8169
- await addCircleElement({
8170
- element,
8171
- index,
8172
- canvas: twickCanvas,
8173
- canvasMetadata: canvasMetadataRef.current
8174
- });
8175
- break;
8176
- case ELEMENT_TYPES.TEXT:
8177
- await addTextElement({
8178
- element,
8179
- index,
8180
- canvas: twickCanvas,
8181
- canvasMetadata: canvasMetadataRef.current
8182
- });
8183
- break;
8184
- case ELEMENT_TYPES.CAPTION:
8185
- await addCaptionElement({
8186
- element,
8187
- index,
8188
- canvas: twickCanvas,
8189
- captionProps,
8190
- canvasMetadata: canvasMetadataRef.current
8191
- });
8192
- break;
8484
+ const handler = elementController.get(element.type);
8485
+ if (handler) {
8486
+ await handler.add({
8487
+ element,
8488
+ index,
8489
+ canvas: twickCanvas,
8490
+ canvasMetadata: canvasMetadataRef.current,
8491
+ seekTime,
8492
+ captionProps: captionProps ?? null,
8493
+ elementFrameMapRef: elementFrameMap,
8494
+ getCurrentFrameEffect
8495
+ });
8193
8496
  }
8194
8497
  elementMap.current[element.id] = element;
8195
8498
  if (reorder) {
8196
8499
  reorderElementsByZIndex(twickCanvas);
8197
8500
  }
8198
8501
  };
8502
+ const addWatermarkToCanvas = ({
8503
+ element
8504
+ }) => {
8505
+ if (!twickCanvas) return;
8506
+ const handler = elementController.get("watermark");
8507
+ if (handler) {
8508
+ handler.add({
8509
+ element,
8510
+ index: Object.keys(elementMap.current).length,
8511
+ canvas: twickCanvas,
8512
+ canvasMetadata: canvasMetadataRef.current,
8513
+ watermarkPropsRef
8514
+ });
8515
+ elementMap.current[element.id] = element;
8516
+ }
8517
+ };
8199
8518
  return {
8200
8519
  twickCanvas,
8201
8520
  buildCanvas,
8202
8521
  onVideoSizeChange,
8522
+ addWatermarkToCanvas,
8203
8523
  addElementToCanvas,
8204
8524
  setCanvasElements
8205
8525
  };
@@ -8222,10 +8542,20 @@ const usePlayerManager = ({
8222
8542
  };
8223
8543
  const handleCanvasOperation = (operation, data) => {
8224
8544
  if (operation === CANVAS_OPERATIONS.CAPTION_PROPS_UPDATED) {
8225
- const subtitlesTrack = editor.getSubtiltesTrack();
8545
+ const subtitlesTrack = editor.getSubtitlesTrack();
8226
8546
  subtitlesTrack == null ? void 0 : subtitlesTrack.setProps(data.props);
8227
8547
  setSelectedItem(data.element);
8228
8548
  editor.refresh();
8549
+ } else if (operation === CANVAS_OPERATIONS.WATERMARK_UPDATED) {
8550
+ const w2 = editor.getWatermark();
8551
+ if (w2 && data) {
8552
+ if (data.position) w2.setPosition(data.position);
8553
+ if (data.rotation != null) w2.setRotation(data.rotation);
8554
+ if (data.opacity != null) w2.setOpacity(data.opacity);
8555
+ if (data.props) w2.setProps(data.props);
8556
+ editor.setWatermark(w2);
8557
+ currentChangeLog.current = currentChangeLog.current + 1;
8558
+ }
8229
8559
  } else {
8230
8560
  const element = ElementDeserializer.fromJSON(data);
8231
8561
  switch (operation) {
@@ -8258,13 +8588,30 @@ const usePlayerManager = ({
8258
8588
  );
8259
8589
  let captionProps = {};
8260
8590
  (elements || []).forEach((element) => {
8261
- if (element instanceof CaptionElement) {
8591
+ if (element instanceof CaptionElement$1) {
8262
8592
  const track = editor.getTrackById(element.getTrackId());
8263
8593
  captionProps = (track == null ? void 0 : track.getProps()) ?? {};
8264
8594
  }
8265
8595
  });
8596
+ const watermark = editor.getWatermark();
8597
+ let watermarkElement;
8598
+ if (watermark) {
8599
+ const position = watermark.getPosition();
8600
+ watermarkElement = {
8601
+ id: watermark.getId(),
8602
+ type: watermark.getType(),
8603
+ props: {
8604
+ ...watermark.getProps() || {},
8605
+ x: (position == null ? void 0 : position.x) ?? 0,
8606
+ y: (position == null ? void 0 : position.y) ?? 0,
8607
+ rotation: watermark.getRotation() ?? 0,
8608
+ opacity: watermark.getOpacity() ?? 1
8609
+ }
8610
+ };
8611
+ }
8266
8612
  setCanvasElements({
8267
8613
  elements,
8614
+ watermark: watermarkElement,
8268
8615
  seekTime,
8269
8616
  captionProps,
8270
8617
  cleanAndAdd: true
@@ -17939,7 +18286,7 @@ const useTimelineManager = () => {
17939
18286
  updates
17940
18287
  }) => {
17941
18288
  if (dragType === DRAG_TYPE.START) {
17942
- if (element instanceof VideoElement || element instanceof AudioElement) {
18289
+ if (element instanceof VideoElement$1 || element instanceof AudioElement) {
17943
18290
  const elementProps = element.getProps();
17944
18291
  const delta = updates.start - element.getStart() * ((elementProps == null ? void 0 : elementProps.playbackRate) || 1);
17945
18292
  if (element instanceof AudioElement) {