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