@twick/canvas 0.15.26 → 0.15.28

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
@@ -1,7 +1,7 @@
1
1
  var __defProp = Object.defineProperty;
2
2
  var __defNormalProp = (obj, key, value) => key in obj ? __defProp(obj, key, { enumerable: true, configurable: true, writable: true, value }) : obj[key] = value;
3
3
  var __publicField = (obj, key, value) => __defNormalProp(obj, typeof key !== "symbol" ? key + "" : key, value);
4
- import { Canvas, Control, controlsUtils, FabricImage, Rect, Textbox, Shadow, Group, Circle, Triangle, ActiveSelection } from "fabric";
4
+ import { Canvas, Control, controlsUtils, filters, setFilterBackend, Canvas2dFilterBackend, FabricImage, Rect, Textbox, Shadow, Group, Circle, Triangle, ActiveSelection } from "fabric";
5
5
  import { useState, useRef, useCallback } from "react";
6
6
  const DEFAULT_TEXT_PROPS = {
7
7
  /** Font family for text elements */
@@ -70,6 +70,8 @@ const ELEMENT_TYPES = {
70
70
  CIRCLE: "circle",
71
71
  /** Icon element type */
72
72
  ICON: "icon",
73
+ /** Emoji sticker element type */
74
+ EMOJI: "emoji",
73
75
  /** Arrow annotation element type */
74
76
  ARROW: "arrow",
75
77
  /** Line annotation / shape element type */
@@ -320,6 +322,24 @@ const rotateControl = new Control({
320
322
  /** Whether to show connection line */
321
323
  withConnection: true
322
324
  });
325
+ const COLOR_FILTERS = {
326
+ SATURATED: "saturated",
327
+ BRIGHT: "bright",
328
+ VIBRANT: "vibrant",
329
+ RETRO: "retro",
330
+ BLACK_WHITE: "blackWhite",
331
+ SEPIA: "sepia",
332
+ COOL: "cool",
333
+ WARM: "warm",
334
+ CINEMATIC: "cinematic",
335
+ SOFT_GLOW: "softGlow",
336
+ MOODY: "moody",
337
+ DREAMY: "dreamy",
338
+ INVERTED: "inverted",
339
+ VINTAGE: "vintage",
340
+ DRAMATIC: "dramatic",
341
+ FADED: "faded"
342
+ };
323
343
  class LRUCache {
324
344
  constructor(maxSize = 100) {
325
345
  if (maxSize <= 0) {
@@ -703,6 +723,275 @@ const getObjectFitSize = (objectFit, elementSize, containerSize) => {
703
723
  };
704
724
  }
705
725
  };
726
+ const {
727
+ Blur,
728
+ Brightness,
729
+ ColorMatrix,
730
+ Contrast,
731
+ Grayscale,
732
+ HueRotation,
733
+ Invert,
734
+ Saturation,
735
+ Sepia
736
+ } = filters;
737
+ let canvas2dFilterBackendInstalled = false;
738
+ function ensureCanvas2dImageFilterBackend() {
739
+ if (canvas2dFilterBackendInstalled) return;
740
+ canvas2dFilterBackendInstalled = true;
741
+ setFilterBackend(new Canvas2dFilterBackend());
742
+ }
743
+ function getSourceBitmapSize(img) {
744
+ const el = img.getElement();
745
+ if (!el) return null;
746
+ const w = "naturalWidth" in el && el.naturalWidth > 0 ? el.naturalWidth : el.width;
747
+ const h = "naturalHeight" in el && el.naturalHeight > 0 ? el.naturalHeight : el.height;
748
+ if (!w || !h) return null;
749
+ return { w, h };
750
+ }
751
+ function applyFiltersSafe(img) {
752
+ ensureCanvas2dImageFilterBackend();
753
+ img.applyFilters();
754
+ }
755
+ const bright = (m) => Math.min(1, Math.max(-1, (m - 1) * 0.48));
756
+ const contr = (m) => Math.min(1, Math.max(-1, (m - 1) * 0.55));
757
+ const sat = (m) => Math.min(1, Math.max(-1, (m - 1) * 0.72));
758
+ const IDENTITY = [
759
+ 1,
760
+ 0,
761
+ 0,
762
+ 0,
763
+ 0,
764
+ 0,
765
+ 1,
766
+ 0,
767
+ 0,
768
+ 0,
769
+ 0,
770
+ 0,
771
+ 1,
772
+ 0,
773
+ 0,
774
+ 0,
775
+ 0,
776
+ 0,
777
+ 1,
778
+ 0
779
+ ];
780
+ const SEPIA_MATRIX = [
781
+ 0.393,
782
+ 0.769,
783
+ 0.189,
784
+ 0,
785
+ 0,
786
+ 0.349,
787
+ 0.686,
788
+ 0.168,
789
+ 0,
790
+ 0,
791
+ 0.272,
792
+ 0.534,
793
+ 0.131,
794
+ 0,
795
+ 0,
796
+ 0,
797
+ 0,
798
+ 0,
799
+ 1,
800
+ 0
801
+ ];
802
+ function sepiaMix(strength) {
803
+ const t = Math.min(1, Math.max(0, strength));
804
+ const m = IDENTITY.map((v, i) => v + (SEPIA_MATRIX[i] - v) * t);
805
+ return new ColorMatrix({ matrix: m, colorsOnly: true });
806
+ }
807
+ const twickBlurToFabric = (v) => Math.min(0.22, Math.max(0, v * 0.045));
808
+ function buildFilters(filterType) {
809
+ switch (filterType) {
810
+ case COLOR_FILTERS.SATURATED:
811
+ return {
812
+ filters: [
813
+ new Saturation({ saturation: sat(1.4) }),
814
+ new Contrast({ contrast: contr(1.1) })
815
+ ],
816
+ opacityFactor: 1
817
+ };
818
+ case COLOR_FILTERS.BRIGHT:
819
+ return {
820
+ filters: [
821
+ new Brightness({ brightness: bright(1.3) }),
822
+ new Contrast({ contrast: contr(1.05) })
823
+ ],
824
+ opacityFactor: 1
825
+ };
826
+ case COLOR_FILTERS.VIBRANT:
827
+ return {
828
+ filters: [
829
+ new Saturation({ saturation: sat(1.6) }),
830
+ new Brightness({ brightness: bright(1.15) }),
831
+ new Contrast({ contrast: contr(1.1) })
832
+ ],
833
+ opacityFactor: 1
834
+ };
835
+ case COLOR_FILTERS.RETRO:
836
+ return {
837
+ filters: [
838
+ sepiaMix(0.8),
839
+ new Contrast({ contrast: contr(1.3) }),
840
+ new Brightness({ brightness: bright(0.85) }),
841
+ new Saturation({ saturation: sat(0.8) })
842
+ ],
843
+ opacityFactor: 1
844
+ };
845
+ case COLOR_FILTERS.BLACK_WHITE:
846
+ return {
847
+ filters: [
848
+ new Grayscale(),
849
+ new Contrast({ contrast: contr(1.25) }),
850
+ new Brightness({ brightness: bright(1.05) })
851
+ ],
852
+ opacityFactor: 1
853
+ };
854
+ case COLOR_FILTERS.SEPIA:
855
+ return {
856
+ filters: [
857
+ new Sepia(),
858
+ new Contrast({ contrast: contr(1.08) })
859
+ ],
860
+ opacityFactor: 1
861
+ };
862
+ case COLOR_FILTERS.COOL:
863
+ return {
864
+ filters: [
865
+ new HueRotation({ rotation: 15 / 180 }),
866
+ new Brightness({ brightness: bright(1.1) }),
867
+ new Saturation({ saturation: sat(1.3) }),
868
+ new Contrast({ contrast: contr(1.05) })
869
+ ],
870
+ opacityFactor: 1
871
+ };
872
+ case COLOR_FILTERS.WARM:
873
+ return {
874
+ filters: [
875
+ new HueRotation({ rotation: -15 / 180 }),
876
+ new Brightness({ brightness: bright(1.15) }),
877
+ new Saturation({ saturation: sat(1.3) }),
878
+ new Contrast({ contrast: contr(1.05) })
879
+ ],
880
+ opacityFactor: 1
881
+ };
882
+ case COLOR_FILTERS.CINEMATIC:
883
+ return {
884
+ filters: [
885
+ new Contrast({ contrast: contr(1.4) }),
886
+ new Brightness({ brightness: bright(0.95) }),
887
+ new Saturation({ saturation: sat(0.85) }),
888
+ sepiaMix(0.2)
889
+ ],
890
+ opacityFactor: 1
891
+ };
892
+ case COLOR_FILTERS.SOFT_GLOW:
893
+ return {
894
+ filters: [
895
+ new Brightness({ brightness: bright(1.2) }),
896
+ new Contrast({ contrast: contr(0.95) }),
897
+ new Blur({ blur: twickBlurToFabric(1.2) }),
898
+ new Saturation({ saturation: sat(1.1) })
899
+ ],
900
+ opacityFactor: 1
901
+ };
902
+ case COLOR_FILTERS.MOODY:
903
+ return {
904
+ filters: [
905
+ new Brightness({ brightness: bright(1.05) }),
906
+ new Contrast({ contrast: contr(1.4) }),
907
+ new Saturation({ saturation: sat(0.65) }),
908
+ sepiaMix(0.2)
909
+ ],
910
+ opacityFactor: 1
911
+ };
912
+ case COLOR_FILTERS.DREAMY:
913
+ return {
914
+ filters: [
915
+ new Brightness({ brightness: bright(1.3) }),
916
+ new Blur({ blur: twickBlurToFabric(2) }),
917
+ new Saturation({ saturation: sat(1.4) }),
918
+ new Contrast({ contrast: contr(0.95) })
919
+ ],
920
+ opacityFactor: 1
921
+ };
922
+ case COLOR_FILTERS.INVERTED:
923
+ return {
924
+ filters: [
925
+ new Invert({ invert: true, alpha: false }),
926
+ new HueRotation({ rotation: 1 })
927
+ ],
928
+ opacityFactor: 1
929
+ };
930
+ case COLOR_FILTERS.VINTAGE:
931
+ return {
932
+ filters: [
933
+ sepiaMix(0.4),
934
+ new Saturation({ saturation: sat(1.4) }),
935
+ new Contrast({ contrast: contr(1.2) }),
936
+ new Brightness({ brightness: bright(1.1) })
937
+ ],
938
+ opacityFactor: 1
939
+ };
940
+ case COLOR_FILTERS.DRAMATIC:
941
+ return {
942
+ filters: [
943
+ new Contrast({ contrast: contr(1.5) }),
944
+ new Brightness({ brightness: bright(0.9) }),
945
+ new Saturation({ saturation: sat(1.2) })
946
+ ],
947
+ opacityFactor: 1
948
+ };
949
+ case COLOR_FILTERS.FADED:
950
+ return {
951
+ filters: [
952
+ new Brightness({ brightness: bright(1.2) }),
953
+ new Saturation({ saturation: sat(0.8) }),
954
+ new Contrast({ contrast: contr(0.9) })
955
+ ],
956
+ opacityFactor: 0.9
957
+ };
958
+ default:
959
+ return { filters: [], opacityFactor: 1 };
960
+ }
961
+ }
962
+ function applyFabricMediaColorFilters(img, mediaFilter, elementOpacity) {
963
+ const key = (mediaFilter == null ? void 0 : mediaFilter.trim()) || "none";
964
+ if (key === "none") {
965
+ img.filters = [];
966
+ img.set("opacity", elementOpacity);
967
+ applyFiltersSafe(img);
968
+ return;
969
+ }
970
+ const { filters: filterList, opacityFactor } = buildFilters(key);
971
+ if (filterList.length === 0) {
972
+ img.filters = [];
973
+ img.set("opacity", elementOpacity);
974
+ applyFiltersSafe(img);
975
+ return;
976
+ }
977
+ if (!getSourceBitmapSize(img)) {
978
+ img.filters = [];
979
+ img.set("opacity", elementOpacity);
980
+ return;
981
+ }
982
+ img.filters = filterList;
983
+ img.set("opacity", elementOpacity * opacityFactor);
984
+ try {
985
+ applyFiltersSafe(img);
986
+ } catch {
987
+ img.filters = [];
988
+ img.set("opacity", elementOpacity);
989
+ try {
990
+ applyFiltersSafe(img);
991
+ } catch {
992
+ }
993
+ }
994
+ }
706
995
  const MARGIN = 10;
707
996
  const addTextElement = ({
708
997
  element,
@@ -793,7 +1082,7 @@ const setImageProps = ({
793
1082
  canvasMetadata,
794
1083
  lockAspectRatio = true
795
1084
  }) => {
796
- var _a, _b, _c, _d, _e;
1085
+ var _a, _b, _c, _d, _e, _f;
797
1086
  const width = (((_a = element.props) == null ? void 0 : _a.width) || 0) * canvasMetadata.scaleX || canvasMetadata.width;
798
1087
  const height = (((_b = element.props) == null ? void 0 : _b.height) || 0) * canvasMetadata.scaleY || canvasMetadata.height;
799
1088
  const { x, y } = convertToCanvasPosition(
@@ -807,11 +1096,15 @@ const setImageProps = ({
807
1096
  img.set("height", height);
808
1097
  img.set("left", x);
809
1098
  img.set("top", y);
810
- img.set("opacity", ((_e = element.props) == null ? void 0 : _e.opacity) ?? 1);
811
1099
  img.set("selectable", true);
812
1100
  img.set("hasControls", true);
813
1101
  img.set("touchAction", "all");
814
1102
  img.set("lockUniScaling", lockAspectRatio);
1103
+ applyFabricMediaColorFilters(
1104
+ img,
1105
+ (_e = element.props) == null ? void 0 : _e.mediaFilter,
1106
+ ((_f = element.props) == null ? void 0 : _f.opacity) ?? 1
1107
+ );
815
1108
  };
816
1109
  const addCaptionElement = ({
817
1110
  element,
@@ -821,48 +1114,52 @@ const addCaptionElement = ({
821
1114
  canvasMetadata,
822
1115
  lockAspectRatio = false
823
1116
  }) => {
824
- var _a, _b, _c, _d, _e, _f, _g, _h, _i, _j, _k, _l, _m, _n, _o, _p, _q, _r, _s, _t, _u, _v, _w, _x, _y, _z, _A, _B, _C, _D, _E, _F, _G, _H, _I, _J, _K, _L;
825
- const applyToAll = (captionProps == null ? void 0 : captionProps.applyToAll) ?? false;
826
- const captionTextColor = ((_a = captionProps == null ? void 0 : captionProps.colors) == null ? void 0 : _a.text) ?? ((_b = captionProps == null ? void 0 : captionProps.color) == null ? void 0 : _b.text);
1117
+ var _a, _b, _c, _d, _e, _f, _g, _h, _i, _j, _k, _l, _m, _n, _o, _p, _q, _r, _s, _t, _u, _v, _w, _x, _y;
1118
+ const useTrackDefaults = ((_a = element.props) == null ? void 0 : _a.useTrackDefaults) ?? true;
1119
+ const trackColors = captionProps == null ? void 0 : captionProps.colors;
1120
+ const elementColors = (_b = element.props) == null ? void 0 : _b.colors;
1121
+ const resolvedColors = useTrackDefaults ? trackColors : { ...trackColors ?? {}, ...elementColors ?? {} };
1122
+ const captionTextColor = (resolvedColors == null ? void 0 : resolvedColors.text) ?? ((_c = captionProps == null ? void 0 : captionProps.color) == null ? void 0 : _c.text);
827
1123
  const { x, y } = convertToCanvasPosition(
828
- (applyToAll ? captionProps == null ? void 0 : captionProps.x : ((_c = element.props) == null ? void 0 : _c.x) ?? (captionProps == null ? void 0 : captionProps.x)) ?? 0,
829
- (applyToAll ? captionProps == null ? void 0 : captionProps.y : ((_d = element.props) == null ? void 0 : _d.y) ?? (captionProps == null ? void 0 : captionProps.y)) ?? 0,
1124
+ (useTrackDefaults ? captionProps == null ? void 0 : captionProps.x : (_d = element.props) == null ? void 0 : _d.x) ?? (captionProps == null ? void 0 : captionProps.x) ?? 0,
1125
+ (useTrackDefaults ? captionProps == null ? void 0 : captionProps.y : (_e = element.props) == null ? void 0 : _e.y) ?? (captionProps == null ? void 0 : captionProps.y) ?? 0,
830
1126
  canvasMetadata
831
1127
  );
832
- let width = ((_e = element.props) == null ? void 0 : _e.width) ? element.props.width * canvasMetadata.scaleX : canvasMetadata.width - 2 * MARGIN;
833
- if ((_f = element.props) == null ? void 0 : _f.maxWidth) {
1128
+ let width = ((_f = element.props) == null ? void 0 : _f.width) ? element.props.width * canvasMetadata.scaleX : canvasMetadata.width - 2 * MARGIN;
1129
+ if ((_g = element.props) == null ? void 0 : _g.maxWidth) {
834
1130
  width = Math.min(width, element.props.maxWidth * canvasMetadata.scaleX);
835
1131
  }
836
- const elementColors = (_g = element.props) == null ? void 0 : _g.colors;
837
- const resolvedFill = (applyToAll ? captionTextColor : ((_h = element.props) == null ? void 0 : _h.fill) ?? (elementColors == null ? void 0 : elementColors.text) ?? captionTextColor) ?? DEFAULT_CAPTION_PROPS.fill;
838
- const trackColors = captionProps == null ? void 0 : captionProps.colors;
1132
+ const resolvedFill = (useTrackDefaults ? void 0 : (_h = element.props) == null ? void 0 : _h.fill) ?? captionTextColor ?? DEFAULT_CAPTION_PROPS.fill;
839
1133
  const trackStroke = trackColors == null ? void 0 : trackColors.outlineColor;
840
1134
  const elementStroke = (elementColors == null ? void 0 : elementColors.outlineColor) ?? ((_i = element.props) == null ? void 0 : _i.stroke);
841
- const resolvedStroke = (applyToAll ? trackStroke ?? elementStroke : elementStroke ?? trackStroke) ?? void 0;
842
- const caption = new Textbox(((_j = element.props) == null ? void 0 : _j.text) || element.t || "", {
1135
+ const resolvedStroke = (useTrackDefaults ? trackStroke : elementStroke ?? trackStroke) ?? void 0;
1136
+ const trackFont = (captionProps == null ? void 0 : captionProps.font) ?? {};
1137
+ const elementFont = ((_j = element.props) == null ? void 0 : _j.font) ?? {};
1138
+ const resolvedFont = useTrackDefaults ? trackFont : { ...trackFont, ...elementFont };
1139
+ const caption = new Textbox(((_k = element.props) == null ? void 0 : _k.text) || element.t || "", {
843
1140
  left: x,
844
1141
  top: y,
845
1142
  originX: "center",
846
1143
  originY: "center",
847
- angle: ((_k = element.props) == null ? void 0 : _k.rotation) || 0,
1144
+ angle: ((_l = element.props) == null ? void 0 : _l.rotation) || 0,
848
1145
  fontSize: Math.round(
849
- ((applyToAll ? (_l = captionProps == null ? void 0 : captionProps.font) == null ? void 0 : _l.size : ((_n = (_m = element.props) == null ? void 0 : _m.font) == null ? void 0 : _n.size) ?? ((_o = captionProps == null ? void 0 : captionProps.font) == null ? void 0 : _o.size)) ?? DEFAULT_CAPTION_PROPS.size) * canvasMetadata.scaleX
1146
+ ((resolvedFont == null ? void 0 : resolvedFont.size) ?? DEFAULT_CAPTION_PROPS.size) * canvasMetadata.scaleX
850
1147
  ),
851
- fontFamily: (applyToAll ? (_p = captionProps == null ? void 0 : captionProps.font) == null ? void 0 : _p.family : ((_r = (_q = element.props) == null ? void 0 : _q.font) == null ? void 0 : _r.family) ?? ((_s = captionProps == null ? void 0 : captionProps.font) == null ? void 0 : _s.family)) ?? DEFAULT_CAPTION_PROPS.family,
1148
+ fontFamily: (resolvedFont == null ? void 0 : resolvedFont.family) ?? DEFAULT_CAPTION_PROPS.family,
852
1149
  fill: resolvedFill,
853
- fontWeight: (applyToAll ? (_t = captionProps == null ? void 0 : captionProps.font) == null ? void 0 : _t.weight : ((_v = (_u = element.props) == null ? void 0 : _u.font) == null ? void 0 : _v.weight) ?? ((_w = captionProps == null ? void 0 : captionProps.font) == null ? void 0 : _w.weight)) ?? DEFAULT_CAPTION_PROPS.fontWeight,
1150
+ fontWeight: (resolvedFont == null ? void 0 : resolvedFont.weight) ?? DEFAULT_CAPTION_PROPS.fontWeight,
854
1151
  ...resolvedStroke ? { stroke: resolvedStroke } : {},
855
- opacity: (applyToAll ? captionProps == null ? void 0 : captionProps.opacity : ((_x = element.props) == null ? void 0 : _x.opacity) ?? (captionProps == null ? void 0 : captionProps.opacity)) ?? 1,
1152
+ opacity: (useTrackDefaults ? void 0 : (_m = element.props) == null ? void 0 : _m.opacity) ?? (captionProps == null ? void 0 : captionProps.opacity) ?? 1,
856
1153
  width,
857
1154
  splitByGrapheme: false,
858
- textAlign: ((_y = element.props) == null ? void 0 : _y.textAlign) ?? "center",
1155
+ textAlign: ((_n = element.props) == null ? void 0 : _n.textAlign) ?? "center",
859
1156
  shadow: new Shadow({
860
- offsetX: (applyToAll ? (_z = captionProps == null ? void 0 : captionProps.shadowOffset) == null ? void 0 : _z[0] : ((_B = (_A = element.props) == null ? void 0 : _A.shadowOffset) == null ? void 0 : _B[0]) ?? ((_C = captionProps == null ? void 0 : captionProps.shadowOffset) == null ? void 0 : _C[0])) ?? ((_D = DEFAULT_CAPTION_PROPS.shadowOffset) == null ? void 0 : _D[0]),
861
- offsetY: (applyToAll ? (_E = captionProps == null ? void 0 : captionProps.shadowOffset) == null ? void 0 : _E[1] : ((_G = (_F = element.props) == null ? void 0 : _F.shadowOffset) == null ? void 0 : _G[1]) ?? ((_H = captionProps == null ? void 0 : captionProps.shadowOffset) == null ? void 0 : _H[1])) ?? ((_I = DEFAULT_CAPTION_PROPS.shadowOffset) == null ? void 0 : _I[1]),
862
- blur: (applyToAll ? captionProps == null ? void 0 : captionProps.shadowBlur : ((_J = element.props) == null ? void 0 : _J.shadowBlur) ?? (captionProps == null ? void 0 : captionProps.shadowBlur)) ?? DEFAULT_CAPTION_PROPS.shadowBlur,
863
- color: (applyToAll ? captionProps == null ? void 0 : captionProps.shadowColor : ((_K = element.props) == null ? void 0 : _K.shadowColor) ?? (captionProps == null ? void 0 : captionProps.shadowColor)) ?? DEFAULT_CAPTION_PROPS.shadowColor
1157
+ offsetX: (useTrackDefaults ? void 0 : (_p = (_o = element.props) == null ? void 0 : _o.shadowOffset) == null ? void 0 : _p[0]) ?? ((_q = captionProps == null ? void 0 : captionProps.shadowOffset) == null ? void 0 : _q[0]) ?? ((_r = DEFAULT_CAPTION_PROPS.shadowOffset) == null ? void 0 : _r[0]),
1158
+ offsetY: (useTrackDefaults ? void 0 : (_t = (_s = element.props) == null ? void 0 : _s.shadowOffset) == null ? void 0 : _t[1]) ?? ((_u = captionProps == null ? void 0 : captionProps.shadowOffset) == null ? void 0 : _u[1]) ?? ((_v = DEFAULT_CAPTION_PROPS.shadowOffset) == null ? void 0 : _v[1]),
1159
+ blur: (useTrackDefaults ? void 0 : (_w = element.props) == null ? void 0 : _w.shadowBlur) ?? (captionProps == null ? void 0 : captionProps.shadowBlur) ?? DEFAULT_CAPTION_PROPS.shadowBlur,
1160
+ color: (useTrackDefaults ? void 0 : (_x = element.props) == null ? void 0 : _x.shadowColor) ?? (captionProps == null ? void 0 : captionProps.shadowColor) ?? DEFAULT_CAPTION_PROPS.shadowColor
864
1161
  }),
865
- strokeWidth: ((applyToAll ? captionProps == null ? void 0 : captionProps.lineWidth : ((_L = element.props) == null ? void 0 : _L.lineWidth) ?? (captionProps == null ? void 0 : captionProps.lineWidth)) ?? DEFAULT_CAPTION_PROPS.lineWidth) * 0.025
1162
+ strokeWidth: ((useTrackDefaults ? void 0 : (_y = element.props) == null ? void 0 : _y.lineWidth) ?? (captionProps == null ? void 0 : captionProps.lineWidth) ?? DEFAULT_CAPTION_PROPS.lineWidth) * 0.025
866
1163
  });
867
1164
  caption.set("id", element.id);
868
1165
  caption.set("zIndex", index);
@@ -917,8 +1214,13 @@ const addImageElement = async ({
917
1214
  currentFrameEffect,
918
1215
  lockAspectRatio = true
919
1216
  }) => {
1217
+ var _a, _b;
920
1218
  try {
921
- const img = await FabricImage.fromURL(imageUrl || element.props.src || "");
1219
+ const rawSrc = imageUrl || element.props.src || "";
1220
+ const mediaFilter = (_b = (_a = element.props) == null ? void 0 : _a.mediaFilter) == null ? void 0 : _b.trim();
1221
+ const useFilter = !!mediaFilter && mediaFilter !== "none";
1222
+ const fromUrlOpts = useFilter && /^https?:\/\//i.test(rawSrc) ? { crossOrigin: "anonymous" } : {};
1223
+ const img = await FabricImage.fromURL(rawSrc, fromUrlOpts);
922
1224
  img.set({
923
1225
  originX: "center",
924
1226
  originY: "center",
@@ -955,7 +1257,7 @@ const addMediaGroup = ({
955
1257
  currentFrameEffect,
956
1258
  lockAspectRatio = true
957
1259
  }) => {
958
- var _a, _b, _c, _d, _e, _f, _g, _h, _i, _j, _k, _l, _m, _n;
1260
+ var _a, _b, _c, _d, _e, _f, _g, _h, _i, _j, _k, _l, _m, _n, _o;
959
1261
  let frameSize;
960
1262
  let angle;
961
1263
  let framePosition;
@@ -1010,9 +1312,13 @@ const addMediaGroup = ({
1010
1312
  originX: "center",
1011
1313
  originY: "center",
1012
1314
  scaleX: newSize.width / img.width,
1013
- scaleY: newSize.height / img.height,
1014
- opacity: ((_n = element.props) == null ? void 0 : _n.opacity) ?? 1
1315
+ scaleY: newSize.height / img.height
1015
1316
  });
1317
+ applyFabricMediaColorFilters(
1318
+ img,
1319
+ (_n = element.props) == null ? void 0 : _n.mediaFilter,
1320
+ ((_o = element.props) == null ? void 0 : _o.opacity) ?? 1
1321
+ );
1016
1322
  const { x, y } = convertToCanvasPosition(
1017
1323
  (framePosition == null ? void 0 : framePosition.x) || 0,
1018
1324
  (framePosition == null ? void 0 : framePosition.y) || 0,
@@ -1498,7 +1804,8 @@ const CaptionElement = {
1498
1804
  context.canvasMetadata,
1499
1805
  context.videoSize
1500
1806
  );
1501
- if ((_a = context.captionPropsRef.current) == null ? void 0 : _a.applyToAll) {
1807
+ const useTrackDefaults = ((_a = element.props) == null ? void 0 : _a.useTrackDefaults) ?? true;
1808
+ if (useTrackDefaults) {
1502
1809
  return {
1503
1810
  element,
1504
1811
  operation: CANVAS_OPERATIONS.CAPTION_PROPS_UPDATED,
@@ -1715,6 +2022,72 @@ const EffectElement = {
1715
2022
  return;
1716
2023
  }
1717
2024
  };
2025
+ const EmojiElement = {
2026
+ name: ELEMENT_TYPES.EMOJI,
2027
+ async add(params) {
2028
+ var _a;
2029
+ const { element, index, canvas, canvasMetadata, lockAspectRatio } = params;
2030
+ await addImageElement({
2031
+ element,
2032
+ index,
2033
+ canvas,
2034
+ canvasMetadata,
2035
+ lockAspectRatio: lockAspectRatio ?? ((_a = element.props) == null ? void 0 : _a.lockAspectRatio) ?? true
2036
+ });
2037
+ },
2038
+ updateFromFabricObject(object, element, context) {
2039
+ const canvasCenter = getObjectCanvasCenter(object);
2040
+ const { x, y } = convertToVideoPosition(
2041
+ canvasCenter.x,
2042
+ canvasCenter.y,
2043
+ context.canvasMetadata,
2044
+ context.videoSize
2045
+ );
2046
+ if (object.type === "group") {
2047
+ const scaledW2 = (object.width ?? 0) * (object.scaleX ?? 1);
2048
+ const scaledH2 = (object.height ?? 0) * (object.scaleY ?? 1);
2049
+ const { width: fw, height: fh } = convertToVideoDimensions(
2050
+ scaledW2,
2051
+ scaledH2,
2052
+ context.canvasMetadata
2053
+ );
2054
+ const updatedFrameSize = [fw, fh];
2055
+ const frame = element.frame;
2056
+ return {
2057
+ element: {
2058
+ ...element,
2059
+ frame: {
2060
+ ...frame,
2061
+ rotation: getObjectCanvasAngle(object),
2062
+ size: updatedFrameSize,
2063
+ x,
2064
+ y
2065
+ }
2066
+ }
2067
+ };
2068
+ }
2069
+ const scaledW = (object.width ?? 0) * (object.scaleX ?? 1);
2070
+ const scaledH = (object.height ?? 0) * (object.scaleY ?? 1);
2071
+ const { width, height } = convertToVideoDimensions(
2072
+ scaledW,
2073
+ scaledH,
2074
+ context.canvasMetadata
2075
+ );
2076
+ return {
2077
+ element: {
2078
+ ...element,
2079
+ props: {
2080
+ ...element.props,
2081
+ rotation: getObjectCanvasAngle(object),
2082
+ width,
2083
+ height,
2084
+ x,
2085
+ y
2086
+ }
2087
+ }
2088
+ };
2089
+ }
2090
+ };
1718
2091
  class ElementController {
1719
2092
  constructor() {
1720
2093
  __publicField(this, "elements", /* @__PURE__ */ new Map());
@@ -1736,6 +2109,7 @@ function registerElements() {
1736
2109
  elementController.register(RectElement);
1737
2110
  elementController.register(CircleElement);
1738
2111
  elementController.register(TextElement);
2112
+ elementController.register(EmojiElement);
1739
2113
  elementController.register(CaptionElement);
1740
2114
  elementController.register(WatermarkElement);
1741
2115
  elementController.register(ArrowElement);