ugcinc-render 1.3.12 → 1.3.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.d.mts +31 -2
- package/dist/index.d.ts +31 -2
- package/dist/index.js +188 -55
- package/dist/index.mjs +186 -55
- package/package.json +1 -1
package/dist/index.d.mts
CHANGED
|
@@ -320,6 +320,10 @@ interface ImageEditorNodeConfig {
|
|
|
320
320
|
dimensionPreset: DimensionPresetKey;
|
|
321
321
|
/** Elements to render */
|
|
322
322
|
elements: ImageEditorElement[];
|
|
323
|
+
/** Background type: 'image' for image input, 'color' for solid color */
|
|
324
|
+
backgroundType?: 'image' | 'color';
|
|
325
|
+
/** Background color (hex) when backgroundType is 'color' */
|
|
326
|
+
backgroundColor?: string;
|
|
323
327
|
/** How the background image fits the canvas */
|
|
324
328
|
backgroundFit?: FitMode;
|
|
325
329
|
/** Cached background image URL for consistent preview */
|
|
@@ -740,6 +744,10 @@ interface ImageEditorCompositionProps {
|
|
|
740
744
|
width?: number;
|
|
741
745
|
/** Canvas height (required when using elements) */
|
|
742
746
|
height?: number;
|
|
747
|
+
/** Background type: 'image' for image input, 'color' for solid color */
|
|
748
|
+
backgroundType?: 'image' | 'color';
|
|
749
|
+
/** Background color (hex) when backgroundType is 'color' */
|
|
750
|
+
backgroundColor?: string;
|
|
743
751
|
/** Background fit mode (when using elements) */
|
|
744
752
|
backgroundFit?: FitMode;
|
|
745
753
|
/** Background image URL (when using elements) */
|
|
@@ -748,6 +756,8 @@ interface ImageEditorCompositionProps {
|
|
|
748
756
|
imageUrls?: Record<string, string | null>;
|
|
749
757
|
/** Text values keyed by textInputId (when using elements, for autoWidth calculation) */
|
|
750
758
|
textValues?: Record<string, string>;
|
|
759
|
+
/** Dynamic crop configuration */
|
|
760
|
+
dynamicCrop?: DynamicCropConfig;
|
|
751
761
|
}
|
|
752
762
|
/**
|
|
753
763
|
* ImageEditorComposition renders a complete image editor configuration.
|
|
@@ -782,7 +792,7 @@ interface ImageEditorCompositionProps {
|
|
|
782
792
|
* />
|
|
783
793
|
* ```
|
|
784
794
|
*/
|
|
785
|
-
declare function ImageEditorComposition({ config, sources, scale, elements, width, height, backgroundFit, backgroundUrl, imageUrls, textValues, }: ImageEditorCompositionProps): react_jsx_runtime.JSX.Element;
|
|
795
|
+
declare function ImageEditorComposition({ config, sources, scale, elements, width, height, backgroundType, backgroundColor, backgroundFit, backgroundUrl, imageUrls, textValues, dynamicCrop, }: ImageEditorCompositionProps): react_jsx_runtime.JSX.Element;
|
|
786
796
|
|
|
787
797
|
interface VideoEditorCompositionProps {
|
|
788
798
|
/** The editor configuration to render */
|
|
@@ -1136,6 +1146,25 @@ declare function getReferenceElementX(elements: ImageEditorElement[], elementId:
|
|
|
1136
1146
|
*/
|
|
1137
1147
|
declare function getReferenceElementY(elements: ImageEditorElement[], elementId: string): ImageEditorElement | null;
|
|
1138
1148
|
|
|
1149
|
+
/**
|
|
1150
|
+
* Utility functions for calculating dynamic crop bounds
|
|
1151
|
+
*/
|
|
1152
|
+
|
|
1153
|
+
/**
|
|
1154
|
+
* Calculate dynamic crop bounds based on element positions
|
|
1155
|
+
*
|
|
1156
|
+
* @param elements - Array of resolved elements with absolute positions
|
|
1157
|
+
* @param dynamicCrop - Crop configuration
|
|
1158
|
+
* @param canvasWidth - Original canvas width
|
|
1159
|
+
* @param canvasHeight - Original canvas height
|
|
1160
|
+
* @returns CropBounds with x, y, width, height
|
|
1161
|
+
*/
|
|
1162
|
+
declare function calculateCropBounds(elements: ImageEditorElement[], dynamicCrop: DynamicCropConfig | undefined, canvasWidth: number, canvasHeight: number): CropBounds;
|
|
1163
|
+
/**
|
|
1164
|
+
* Check if dynamic crop is enabled (either vertical or horizontal)
|
|
1165
|
+
*/
|
|
1166
|
+
declare function isDynamicCropEnabled(dynamicCrop: DynamicCropConfig | undefined): boolean;
|
|
1167
|
+
|
|
1139
1168
|
/**
|
|
1140
1169
|
* Hook exports for ugcinc-render
|
|
1141
1170
|
*
|
|
@@ -1195,4 +1224,4 @@ declare function useResolvedPositions(elements: ImageEditorElement[], textValues
|
|
|
1195
1224
|
|
|
1196
1225
|
declare const RenderRoot: React.FC;
|
|
1197
1226
|
|
|
1198
|
-
export { type AudioSegment, type BaseEditorConfig, type BaseSegment, type BorderRadiusConfig, type Channel, type CropAxisConfig, type CropBoundary, type CropBounds, DIMENSION_PRESETS, type DimensionPreset, type DimensionPresetKey, type DynamicCropConfig, type EditorConfig, type EditorSegment, FONT_FAMILIES, FONT_URLS, type FitDimensions, type FitMode, type FontType, type FontWeight, type HorizontalAnchor, type HorizontalSelfAnchor, type Hyphenation, IMAGE_DEFAULTS, ImageEditorComposition, type ImageEditorCompositionProps, type ImageEditorConfig, type ImageEditorElement, type ImageEditorNodeConfig, ImageElement, type ImageElementProps, type ImageSegment, type PictureSegment, type PositionResolutionError, type PositionResolutionResult, type RelativePositionConfigX, type RelativePositionConfigY, RenderRoot, type Segment, type SegmentType, type StaticSegment, TEXT_DEFAULTS, type TextAlignment, type TextDirection, TextElement, type TextElementProps, type TextOverflow, type TextSegment, type TextWrap, type TimeMode, type TimeValue, VIDEO_DEFAULTS, VISUAL_DEFAULTS, type VerticalAlignment, type VerticalAnchor, type VerticalSelfAnchor, type VideoEditorAudioSegment, type VideoEditorBaseSegment, type VideoEditorChannel, VideoEditorComposition, type VideoEditorCompositionProps, type VideoEditorConfig, type VideoEditorImageSegment, type VideoEditorNodeConfig, type VideoEditorSegment, type VideoEditorTextSegment, type VideoEditorVideoSegment, type VideoEditorVisualSegment, VideoElement, type VideoElementProps, type VideoSegment, type VisualSegment, type VisualSegmentUnion, type WordBreak, applyImageDefaults, applyTextDefaults, applyVideoDefaults, areFontsLoaded, buildFontString, calculateAutoWidthDimensions, calculateFitDimensions, calculateLineWidth, canSetAsReference, getBorderRadii, getDependentElements, getFontFamily, getReferenceElementX, getReferenceElementY, hexToRgba, parseHexColor, preloadFonts, resolveElementPositions, useFontsLoaded, useImageLoader, useImagePreloader, useResolvedPositions, wrapText };
|
|
1227
|
+
export { type AudioSegment, type BaseEditorConfig, type BaseSegment, type BorderRadiusConfig, type Channel, type CropAxisConfig, type CropBoundary, type CropBounds, DIMENSION_PRESETS, type DimensionPreset, type DimensionPresetKey, type DynamicCropConfig, type EditorConfig, type EditorSegment, FONT_FAMILIES, FONT_URLS, type FitDimensions, type FitMode, type FontType, type FontWeight, type HorizontalAnchor, type HorizontalSelfAnchor, type Hyphenation, IMAGE_DEFAULTS, ImageEditorComposition, type ImageEditorCompositionProps, type ImageEditorConfig, type ImageEditorElement, type ImageEditorNodeConfig, ImageElement, type ImageElementProps, type ImageSegment, type PictureSegment, type PositionResolutionError, type PositionResolutionResult, type RelativePositionConfigX, type RelativePositionConfigY, RenderRoot, type Segment, type SegmentType, type StaticSegment, TEXT_DEFAULTS, type TextAlignment, type TextDirection, TextElement, type TextElementProps, type TextOverflow, type TextSegment, type TextWrap, type TimeMode, type TimeValue, VIDEO_DEFAULTS, VISUAL_DEFAULTS, type VerticalAlignment, type VerticalAnchor, type VerticalSelfAnchor, type VideoEditorAudioSegment, type VideoEditorBaseSegment, type VideoEditorChannel, VideoEditorComposition, type VideoEditorCompositionProps, type VideoEditorConfig, type VideoEditorImageSegment, type VideoEditorNodeConfig, type VideoEditorSegment, type VideoEditorTextSegment, type VideoEditorVideoSegment, type VideoEditorVisualSegment, VideoElement, type VideoElementProps, type VideoSegment, type VisualSegment, type VisualSegmentUnion, type WordBreak, applyImageDefaults, applyTextDefaults, applyVideoDefaults, areFontsLoaded, buildFontString, calculateAutoWidthDimensions, calculateCropBounds, calculateFitDimensions, calculateLineWidth, canSetAsReference, getBorderRadii, getDependentElements, getFontFamily, getReferenceElementX, getReferenceElementY, hexToRgba, isDynamicCropEnabled, parseHexColor, preloadFonts, resolveElementPositions, useFontsLoaded, useImageLoader, useImagePreloader, useResolvedPositions, wrapText };
|
package/dist/index.d.ts
CHANGED
|
@@ -320,6 +320,10 @@ interface ImageEditorNodeConfig {
|
|
|
320
320
|
dimensionPreset: DimensionPresetKey;
|
|
321
321
|
/** Elements to render */
|
|
322
322
|
elements: ImageEditorElement[];
|
|
323
|
+
/** Background type: 'image' for image input, 'color' for solid color */
|
|
324
|
+
backgroundType?: 'image' | 'color';
|
|
325
|
+
/** Background color (hex) when backgroundType is 'color' */
|
|
326
|
+
backgroundColor?: string;
|
|
323
327
|
/** How the background image fits the canvas */
|
|
324
328
|
backgroundFit?: FitMode;
|
|
325
329
|
/** Cached background image URL for consistent preview */
|
|
@@ -740,6 +744,10 @@ interface ImageEditorCompositionProps {
|
|
|
740
744
|
width?: number;
|
|
741
745
|
/** Canvas height (required when using elements) */
|
|
742
746
|
height?: number;
|
|
747
|
+
/** Background type: 'image' for image input, 'color' for solid color */
|
|
748
|
+
backgroundType?: 'image' | 'color';
|
|
749
|
+
/** Background color (hex) when backgroundType is 'color' */
|
|
750
|
+
backgroundColor?: string;
|
|
743
751
|
/** Background fit mode (when using elements) */
|
|
744
752
|
backgroundFit?: FitMode;
|
|
745
753
|
/** Background image URL (when using elements) */
|
|
@@ -748,6 +756,8 @@ interface ImageEditorCompositionProps {
|
|
|
748
756
|
imageUrls?: Record<string, string | null>;
|
|
749
757
|
/** Text values keyed by textInputId (when using elements, for autoWidth calculation) */
|
|
750
758
|
textValues?: Record<string, string>;
|
|
759
|
+
/** Dynamic crop configuration */
|
|
760
|
+
dynamicCrop?: DynamicCropConfig;
|
|
751
761
|
}
|
|
752
762
|
/**
|
|
753
763
|
* ImageEditorComposition renders a complete image editor configuration.
|
|
@@ -782,7 +792,7 @@ interface ImageEditorCompositionProps {
|
|
|
782
792
|
* />
|
|
783
793
|
* ```
|
|
784
794
|
*/
|
|
785
|
-
declare function ImageEditorComposition({ config, sources, scale, elements, width, height, backgroundFit, backgroundUrl, imageUrls, textValues, }: ImageEditorCompositionProps): react_jsx_runtime.JSX.Element;
|
|
795
|
+
declare function ImageEditorComposition({ config, sources, scale, elements, width, height, backgroundType, backgroundColor, backgroundFit, backgroundUrl, imageUrls, textValues, dynamicCrop, }: ImageEditorCompositionProps): react_jsx_runtime.JSX.Element;
|
|
786
796
|
|
|
787
797
|
interface VideoEditorCompositionProps {
|
|
788
798
|
/** The editor configuration to render */
|
|
@@ -1136,6 +1146,25 @@ declare function getReferenceElementX(elements: ImageEditorElement[], elementId:
|
|
|
1136
1146
|
*/
|
|
1137
1147
|
declare function getReferenceElementY(elements: ImageEditorElement[], elementId: string): ImageEditorElement | null;
|
|
1138
1148
|
|
|
1149
|
+
/**
|
|
1150
|
+
* Utility functions for calculating dynamic crop bounds
|
|
1151
|
+
*/
|
|
1152
|
+
|
|
1153
|
+
/**
|
|
1154
|
+
* Calculate dynamic crop bounds based on element positions
|
|
1155
|
+
*
|
|
1156
|
+
* @param elements - Array of resolved elements with absolute positions
|
|
1157
|
+
* @param dynamicCrop - Crop configuration
|
|
1158
|
+
* @param canvasWidth - Original canvas width
|
|
1159
|
+
* @param canvasHeight - Original canvas height
|
|
1160
|
+
* @returns CropBounds with x, y, width, height
|
|
1161
|
+
*/
|
|
1162
|
+
declare function calculateCropBounds(elements: ImageEditorElement[], dynamicCrop: DynamicCropConfig | undefined, canvasWidth: number, canvasHeight: number): CropBounds;
|
|
1163
|
+
/**
|
|
1164
|
+
* Check if dynamic crop is enabled (either vertical or horizontal)
|
|
1165
|
+
*/
|
|
1166
|
+
declare function isDynamicCropEnabled(dynamicCrop: DynamicCropConfig | undefined): boolean;
|
|
1167
|
+
|
|
1139
1168
|
/**
|
|
1140
1169
|
* Hook exports for ugcinc-render
|
|
1141
1170
|
*
|
|
@@ -1195,4 +1224,4 @@ declare function useResolvedPositions(elements: ImageEditorElement[], textValues
|
|
|
1195
1224
|
|
|
1196
1225
|
declare const RenderRoot: React.FC;
|
|
1197
1226
|
|
|
1198
|
-
export { type AudioSegment, type BaseEditorConfig, type BaseSegment, type BorderRadiusConfig, type Channel, type CropAxisConfig, type CropBoundary, type CropBounds, DIMENSION_PRESETS, type DimensionPreset, type DimensionPresetKey, type DynamicCropConfig, type EditorConfig, type EditorSegment, FONT_FAMILIES, FONT_URLS, type FitDimensions, type FitMode, type FontType, type FontWeight, type HorizontalAnchor, type HorizontalSelfAnchor, type Hyphenation, IMAGE_DEFAULTS, ImageEditorComposition, type ImageEditorCompositionProps, type ImageEditorConfig, type ImageEditorElement, type ImageEditorNodeConfig, ImageElement, type ImageElementProps, type ImageSegment, type PictureSegment, type PositionResolutionError, type PositionResolutionResult, type RelativePositionConfigX, type RelativePositionConfigY, RenderRoot, type Segment, type SegmentType, type StaticSegment, TEXT_DEFAULTS, type TextAlignment, type TextDirection, TextElement, type TextElementProps, type TextOverflow, type TextSegment, type TextWrap, type TimeMode, type TimeValue, VIDEO_DEFAULTS, VISUAL_DEFAULTS, type VerticalAlignment, type VerticalAnchor, type VerticalSelfAnchor, type VideoEditorAudioSegment, type VideoEditorBaseSegment, type VideoEditorChannel, VideoEditorComposition, type VideoEditorCompositionProps, type VideoEditorConfig, type VideoEditorImageSegment, type VideoEditorNodeConfig, type VideoEditorSegment, type VideoEditorTextSegment, type VideoEditorVideoSegment, type VideoEditorVisualSegment, VideoElement, type VideoElementProps, type VideoSegment, type VisualSegment, type VisualSegmentUnion, type WordBreak, applyImageDefaults, applyTextDefaults, applyVideoDefaults, areFontsLoaded, buildFontString, calculateAutoWidthDimensions, calculateFitDimensions, calculateLineWidth, canSetAsReference, getBorderRadii, getDependentElements, getFontFamily, getReferenceElementX, getReferenceElementY, hexToRgba, parseHexColor, preloadFonts, resolveElementPositions, useFontsLoaded, useImageLoader, useImagePreloader, useResolvedPositions, wrapText };
|
|
1227
|
+
export { type AudioSegment, type BaseEditorConfig, type BaseSegment, type BorderRadiusConfig, type Channel, type CropAxisConfig, type CropBoundary, type CropBounds, DIMENSION_PRESETS, type DimensionPreset, type DimensionPresetKey, type DynamicCropConfig, type EditorConfig, type EditorSegment, FONT_FAMILIES, FONT_URLS, type FitDimensions, type FitMode, type FontType, type FontWeight, type HorizontalAnchor, type HorizontalSelfAnchor, type Hyphenation, IMAGE_DEFAULTS, ImageEditorComposition, type ImageEditorCompositionProps, type ImageEditorConfig, type ImageEditorElement, type ImageEditorNodeConfig, ImageElement, type ImageElementProps, type ImageSegment, type PictureSegment, type PositionResolutionError, type PositionResolutionResult, type RelativePositionConfigX, type RelativePositionConfigY, RenderRoot, type Segment, type SegmentType, type StaticSegment, TEXT_DEFAULTS, type TextAlignment, type TextDirection, TextElement, type TextElementProps, type TextOverflow, type TextSegment, type TextWrap, type TimeMode, type TimeValue, VIDEO_DEFAULTS, VISUAL_DEFAULTS, type VerticalAlignment, type VerticalAnchor, type VerticalSelfAnchor, type VideoEditorAudioSegment, type VideoEditorBaseSegment, type VideoEditorChannel, VideoEditorComposition, type VideoEditorCompositionProps, type VideoEditorConfig, type VideoEditorImageSegment, type VideoEditorNodeConfig, type VideoEditorSegment, type VideoEditorTextSegment, type VideoEditorVideoSegment, type VideoEditorVisualSegment, VideoElement, type VideoElementProps, type VideoSegment, type VisualSegment, type VisualSegmentUnion, type WordBreak, applyImageDefaults, applyTextDefaults, applyVideoDefaults, areFontsLoaded, buildFontString, calculateAutoWidthDimensions, calculateCropBounds, calculateFitDimensions, calculateLineWidth, canSetAsReference, getBorderRadii, getDependentElements, getFontFamily, getReferenceElementX, getReferenceElementY, hexToRgba, isDynamicCropEnabled, parseHexColor, preloadFonts, resolveElementPositions, useFontsLoaded, useImageLoader, useImagePreloader, useResolvedPositions, wrapText };
|
package/dist/index.js
CHANGED
|
@@ -39,6 +39,7 @@ __export(index_exports, {
|
|
|
39
39
|
areFontsLoaded: () => areFontsLoaded,
|
|
40
40
|
buildFontString: () => buildFontString,
|
|
41
41
|
calculateAutoWidthDimensions: () => calculateAutoWidthDimensions,
|
|
42
|
+
calculateCropBounds: () => calculateCropBounds,
|
|
42
43
|
calculateFitDimensions: () => calculateFitDimensions,
|
|
43
44
|
calculateLineWidth: () => calculateLineWidth,
|
|
44
45
|
canSetAsReference: () => canSetAsReference,
|
|
@@ -48,6 +49,7 @@ __export(index_exports, {
|
|
|
48
49
|
getReferenceElementX: () => getReferenceElementX,
|
|
49
50
|
getReferenceElementY: () => getReferenceElementY,
|
|
50
51
|
hexToRgba: () => hexToRgba,
|
|
52
|
+
isDynamicCropEnabled: () => isDynamicCropEnabled,
|
|
51
53
|
parseHexColor: () => parseHexColor,
|
|
52
54
|
preloadFonts: () => preloadFonts,
|
|
53
55
|
resolveElementPositions: () => resolveElementPositions,
|
|
@@ -799,6 +801,113 @@ function getReferenceElementY(elements, elementId) {
|
|
|
799
801
|
return elements.find((e) => e.id === element.relativePositionY.elementId) ?? null;
|
|
800
802
|
}
|
|
801
803
|
|
|
804
|
+
// src/utils/cropBounds.ts
|
|
805
|
+
function calculateCropBounds(elements, dynamicCrop, canvasWidth, canvasHeight) {
|
|
806
|
+
if (!dynamicCrop) {
|
|
807
|
+
return { x: 0, y: 0, width: canvasWidth, height: canvasHeight };
|
|
808
|
+
}
|
|
809
|
+
const elementMap = /* @__PURE__ */ new Map();
|
|
810
|
+
for (const elem of elements) {
|
|
811
|
+
elementMap.set(elem.id, elem);
|
|
812
|
+
}
|
|
813
|
+
const resolveBoundary = (boundary) => {
|
|
814
|
+
if (!boundary) return void 0;
|
|
815
|
+
if (boundary.elementId) return boundary.elementId;
|
|
816
|
+
return void 0;
|
|
817
|
+
};
|
|
818
|
+
let cropY = 0;
|
|
819
|
+
let cropHeight = canvasHeight;
|
|
820
|
+
if (dynamicCrop.vertical?.enabled) {
|
|
821
|
+
const vCrop = dynamicCrop.vertical;
|
|
822
|
+
const paddingStart = vCrop.paddingStart ?? 0;
|
|
823
|
+
const paddingEnd = vCrop.paddingEnd ?? 0;
|
|
824
|
+
if (vCrop.mode === "all-elements") {
|
|
825
|
+
let minY = canvasHeight;
|
|
826
|
+
let maxY = 0;
|
|
827
|
+
for (const elem of elements) {
|
|
828
|
+
minY = Math.min(minY, elem.y);
|
|
829
|
+
maxY = Math.max(maxY, elem.y + elem.height);
|
|
830
|
+
}
|
|
831
|
+
if (elements.length > 0) {
|
|
832
|
+
cropY = Math.max(0, minY - paddingStart);
|
|
833
|
+
const bottomY = Math.min(canvasHeight, maxY + paddingEnd);
|
|
834
|
+
cropHeight = bottomY - cropY;
|
|
835
|
+
}
|
|
836
|
+
} else if (vCrop.mode === "between-elements") {
|
|
837
|
+
const startElementId = resolveBoundary(vCrop.startBoundary);
|
|
838
|
+
const endElementId = resolveBoundary(vCrop.endBoundary);
|
|
839
|
+
let topY = 0;
|
|
840
|
+
let bottomY = canvasHeight;
|
|
841
|
+
if (startElementId) {
|
|
842
|
+
const startElem = elementMap.get(startElementId);
|
|
843
|
+
if (startElem) {
|
|
844
|
+
topY = startElem.y;
|
|
845
|
+
}
|
|
846
|
+
}
|
|
847
|
+
if (endElementId) {
|
|
848
|
+
const endElem = elementMap.get(endElementId);
|
|
849
|
+
if (endElem) {
|
|
850
|
+
bottomY = endElem.y + endElem.height;
|
|
851
|
+
}
|
|
852
|
+
}
|
|
853
|
+
cropY = Math.max(0, topY - paddingStart);
|
|
854
|
+
const adjustedBottom = Math.min(canvasHeight, bottomY + paddingEnd);
|
|
855
|
+
cropHeight = adjustedBottom - cropY;
|
|
856
|
+
}
|
|
857
|
+
if (vCrop.minSize && cropHeight < vCrop.minSize) {
|
|
858
|
+
cropHeight = vCrop.minSize;
|
|
859
|
+
}
|
|
860
|
+
}
|
|
861
|
+
let cropX = 0;
|
|
862
|
+
let cropWidth = canvasWidth;
|
|
863
|
+
if (dynamicCrop.horizontal?.enabled) {
|
|
864
|
+
const hCrop = dynamicCrop.horizontal;
|
|
865
|
+
const paddingStart = hCrop.paddingStart ?? 0;
|
|
866
|
+
const paddingEnd = hCrop.paddingEnd ?? 0;
|
|
867
|
+
if (hCrop.mode === "all-elements") {
|
|
868
|
+
let minX = canvasWidth;
|
|
869
|
+
let maxX = 0;
|
|
870
|
+
for (const elem of elements) {
|
|
871
|
+
minX = Math.min(minX, elem.x);
|
|
872
|
+
maxX = Math.max(maxX, elem.x + elem.width);
|
|
873
|
+
}
|
|
874
|
+
if (elements.length > 0) {
|
|
875
|
+
cropX = Math.max(0, minX - paddingStart);
|
|
876
|
+
const rightX = Math.min(canvasWidth, maxX + paddingEnd);
|
|
877
|
+
cropWidth = rightX - cropX;
|
|
878
|
+
}
|
|
879
|
+
} else if (hCrop.mode === "between-elements") {
|
|
880
|
+
const startElementId = resolveBoundary(hCrop.startBoundary);
|
|
881
|
+
const endElementId = resolveBoundary(hCrop.endBoundary);
|
|
882
|
+
let leftX = 0;
|
|
883
|
+
let rightX = canvasWidth;
|
|
884
|
+
if (startElementId) {
|
|
885
|
+
const startElem = elementMap.get(startElementId);
|
|
886
|
+
if (startElem) {
|
|
887
|
+
leftX = startElem.x;
|
|
888
|
+
}
|
|
889
|
+
}
|
|
890
|
+
if (endElementId) {
|
|
891
|
+
const endElem = elementMap.get(endElementId);
|
|
892
|
+
if (endElem) {
|
|
893
|
+
rightX = endElem.x + endElem.width;
|
|
894
|
+
}
|
|
895
|
+
}
|
|
896
|
+
cropX = Math.max(0, leftX - paddingStart);
|
|
897
|
+
const adjustedRight = Math.min(canvasWidth, rightX + paddingEnd);
|
|
898
|
+
cropWidth = adjustedRight - cropX;
|
|
899
|
+
}
|
|
900
|
+
if (hCrop.minSize && cropWidth < hCrop.minSize) {
|
|
901
|
+
cropWidth = hCrop.minSize;
|
|
902
|
+
}
|
|
903
|
+
}
|
|
904
|
+
return { x: cropX, y: cropY, width: cropWidth, height: cropHeight };
|
|
905
|
+
}
|
|
906
|
+
function isDynamicCropEnabled(dynamicCrop) {
|
|
907
|
+
if (!dynamicCrop) return false;
|
|
908
|
+
return !!(dynamicCrop.vertical?.enabled || dynamicCrop.horizontal?.enabled);
|
|
909
|
+
}
|
|
910
|
+
|
|
802
911
|
// src/compositions/ImageEditorComposition.tsx
|
|
803
912
|
var import_jsx_runtime3 = require("react/jsx-runtime");
|
|
804
913
|
function getSortedSegments(config) {
|
|
@@ -874,11 +983,16 @@ function ImageEditorComposition({
|
|
|
874
983
|
elements,
|
|
875
984
|
width,
|
|
876
985
|
height,
|
|
986
|
+
backgroundType = "image",
|
|
987
|
+
backgroundColor,
|
|
877
988
|
backgroundFit = "cover",
|
|
878
989
|
backgroundUrl,
|
|
879
990
|
imageUrls = {},
|
|
880
|
-
textValues = {}
|
|
991
|
+
textValues = {},
|
|
992
|
+
dynamicCrop
|
|
881
993
|
}) {
|
|
994
|
+
const canvasWidth = width ?? config?.width ?? 1080;
|
|
995
|
+
const canvasHeight = height ?? config?.height ?? 1920;
|
|
882
996
|
const resolvedElements = (0, import_react3.useMemo)(() => {
|
|
883
997
|
if (!elements) return null;
|
|
884
998
|
const result = resolveElementPositions(elements, textValues);
|
|
@@ -887,6 +1001,10 @@ function ImageEditorComposition({
|
|
|
887
1001
|
}
|
|
888
1002
|
return result.elements;
|
|
889
1003
|
}, [elements, textValues]);
|
|
1004
|
+
const cropBounds = (0, import_react3.useMemo)(() => {
|
|
1005
|
+
if (!isDynamicCropEnabled(dynamicCrop) || !resolvedElements) return null;
|
|
1006
|
+
return calculateCropBounds(resolvedElements, dynamicCrop, canvasWidth, canvasHeight);
|
|
1007
|
+
}, [resolvedElements, dynamicCrop, canvasWidth, canvasHeight]);
|
|
890
1008
|
const segmentsFromElements = (0, import_react3.useMemo)(() => {
|
|
891
1009
|
if (!resolvedElements) return null;
|
|
892
1010
|
const segments = [];
|
|
@@ -903,10 +1021,10 @@ function ImageEditorComposition({
|
|
|
903
1021
|
}
|
|
904
1022
|
return segments.sort((a, b) => (a.zIndex ?? 0) - (b.zIndex ?? 0));
|
|
905
1023
|
}, [resolvedElements, imageUrls, textValues]);
|
|
906
|
-
const canvasWidth = width ?? config?.width ?? 1080;
|
|
907
|
-
const canvasHeight = height ?? config?.height ?? 1920;
|
|
908
1024
|
const bgFit = backgroundFit ?? "cover";
|
|
909
1025
|
const bgUrl = backgroundUrl ?? sources.background;
|
|
1026
|
+
const cropOffsetX = cropBounds?.x ?? 0;
|
|
1027
|
+
const cropOffsetY = cropBounds?.y ?? 0;
|
|
910
1028
|
const contentSegments = segmentsFromElements ?? (() => {
|
|
911
1029
|
if (!config) return [];
|
|
912
1030
|
const sorted = getSortedSegments(config);
|
|
@@ -926,61 +1044,74 @@ function ImageEditorComposition({
|
|
|
926
1044
|
}
|
|
927
1045
|
return void 0;
|
|
928
1046
|
};
|
|
929
|
-
|
|
930
|
-
|
|
931
|
-
|
|
932
|
-
|
|
933
|
-
|
|
934
|
-
|
|
935
|
-
|
|
936
|
-
|
|
937
|
-
|
|
938
|
-
|
|
939
|
-
|
|
940
|
-
|
|
941
|
-
|
|
942
|
-
|
|
943
|
-
),
|
|
944
|
-
legacyBackgroundSegment && !segmentsFromElements && /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(
|
|
945
|
-
BackgroundImage,
|
|
946
|
-
{
|
|
947
|
-
segment: legacyBackgroundSegment,
|
|
948
|
-
src: getSource(legacyBackgroundSegment),
|
|
949
|
-
width: canvasWidth,
|
|
950
|
-
height: canvasHeight,
|
|
951
|
-
scale
|
|
952
|
-
}
|
|
953
|
-
),
|
|
954
|
-
contentSegments.map((segment) => {
|
|
955
|
-
if (segment.type === "text") {
|
|
956
|
-
return /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(
|
|
957
|
-
TextElement,
|
|
1047
|
+
const containerBgColor = backgroundType === "color" && backgroundColor ? backgroundColor : "#000000";
|
|
1048
|
+
return /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(import_remotion2.AbsoluteFill, { style: { backgroundColor: containerBgColor }, children: /* @__PURE__ */ (0, import_jsx_runtime3.jsxs)(
|
|
1049
|
+
"div",
|
|
1050
|
+
{
|
|
1051
|
+
style: {
|
|
1052
|
+
position: "absolute",
|
|
1053
|
+
left: -cropOffsetX * scale,
|
|
1054
|
+
top: -cropOffsetY * scale,
|
|
1055
|
+
width: canvasWidth * scale,
|
|
1056
|
+
height: canvasHeight * scale
|
|
1057
|
+
},
|
|
1058
|
+
children: [
|
|
1059
|
+
backgroundType === "image" && bgUrl && segmentsFromElements && /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(
|
|
1060
|
+
import_remotion2.Img,
|
|
958
1061
|
{
|
|
959
|
-
|
|
960
|
-
|
|
961
|
-
|
|
962
|
-
|
|
963
|
-
|
|
964
|
-
|
|
965
|
-
|
|
966
|
-
|
|
967
|
-
|
|
968
|
-
|
|
969
|
-
|
|
970
|
-
|
|
971
|
-
|
|
972
|
-
ImageElement,
|
|
1062
|
+
src: bgUrl,
|
|
1063
|
+
style: {
|
|
1064
|
+
position: "absolute",
|
|
1065
|
+
left: 0,
|
|
1066
|
+
top: 0,
|
|
1067
|
+
width: canvasWidth * scale,
|
|
1068
|
+
height: canvasHeight * scale,
|
|
1069
|
+
objectFit: bgFit
|
|
1070
|
+
}
|
|
1071
|
+
}
|
|
1072
|
+
),
|
|
1073
|
+
legacyBackgroundSegment && !segmentsFromElements && /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(
|
|
1074
|
+
BackgroundImage,
|
|
973
1075
|
{
|
|
974
|
-
segment,
|
|
975
|
-
src,
|
|
1076
|
+
segment: legacyBackgroundSegment,
|
|
1077
|
+
src: getSource(legacyBackgroundSegment),
|
|
1078
|
+
width: canvasWidth,
|
|
1079
|
+
height: canvasHeight,
|
|
976
1080
|
scale
|
|
977
|
-
}
|
|
978
|
-
|
|
979
|
-
)
|
|
980
|
-
|
|
981
|
-
|
|
982
|
-
|
|
983
|
-
|
|
1081
|
+
}
|
|
1082
|
+
),
|
|
1083
|
+
contentSegments.map((segment) => {
|
|
1084
|
+
if (segment.type === "text") {
|
|
1085
|
+
return /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(
|
|
1086
|
+
TextElement,
|
|
1087
|
+
{
|
|
1088
|
+
segment,
|
|
1089
|
+
scale
|
|
1090
|
+
},
|
|
1091
|
+
segment.id
|
|
1092
|
+
);
|
|
1093
|
+
}
|
|
1094
|
+
if (segment.type === "image") {
|
|
1095
|
+
const src = segment.source || getSource(segment);
|
|
1096
|
+
if (!src) {
|
|
1097
|
+
console.warn(`No source found for image segment: ${segment.id}`);
|
|
1098
|
+
return null;
|
|
1099
|
+
}
|
|
1100
|
+
return /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(
|
|
1101
|
+
ImageElement,
|
|
1102
|
+
{
|
|
1103
|
+
segment,
|
|
1104
|
+
src,
|
|
1105
|
+
scale
|
|
1106
|
+
},
|
|
1107
|
+
segment.id
|
|
1108
|
+
);
|
|
1109
|
+
}
|
|
1110
|
+
return null;
|
|
1111
|
+
})
|
|
1112
|
+
]
|
|
1113
|
+
}
|
|
1114
|
+
) });
|
|
984
1115
|
}
|
|
985
1116
|
function BackgroundImage({
|
|
986
1117
|
segment,
|
|
@@ -1486,6 +1617,7 @@ var RenderRoot = () => {
|
|
|
1486
1617
|
areFontsLoaded,
|
|
1487
1618
|
buildFontString,
|
|
1488
1619
|
calculateAutoWidthDimensions,
|
|
1620
|
+
calculateCropBounds,
|
|
1489
1621
|
calculateFitDimensions,
|
|
1490
1622
|
calculateLineWidth,
|
|
1491
1623
|
canSetAsReference,
|
|
@@ -1495,6 +1627,7 @@ var RenderRoot = () => {
|
|
|
1495
1627
|
getReferenceElementX,
|
|
1496
1628
|
getReferenceElementY,
|
|
1497
1629
|
hexToRgba,
|
|
1630
|
+
isDynamicCropEnabled,
|
|
1498
1631
|
parseHexColor,
|
|
1499
1632
|
preloadFonts,
|
|
1500
1633
|
resolveElementPositions,
|
package/dist/index.mjs
CHANGED
|
@@ -738,6 +738,113 @@ function getReferenceElementY(elements, elementId) {
|
|
|
738
738
|
return elements.find((e) => e.id === element.relativePositionY.elementId) ?? null;
|
|
739
739
|
}
|
|
740
740
|
|
|
741
|
+
// src/utils/cropBounds.ts
|
|
742
|
+
function calculateCropBounds(elements, dynamicCrop, canvasWidth, canvasHeight) {
|
|
743
|
+
if (!dynamicCrop) {
|
|
744
|
+
return { x: 0, y: 0, width: canvasWidth, height: canvasHeight };
|
|
745
|
+
}
|
|
746
|
+
const elementMap = /* @__PURE__ */ new Map();
|
|
747
|
+
for (const elem of elements) {
|
|
748
|
+
elementMap.set(elem.id, elem);
|
|
749
|
+
}
|
|
750
|
+
const resolveBoundary = (boundary) => {
|
|
751
|
+
if (!boundary) return void 0;
|
|
752
|
+
if (boundary.elementId) return boundary.elementId;
|
|
753
|
+
return void 0;
|
|
754
|
+
};
|
|
755
|
+
let cropY = 0;
|
|
756
|
+
let cropHeight = canvasHeight;
|
|
757
|
+
if (dynamicCrop.vertical?.enabled) {
|
|
758
|
+
const vCrop = dynamicCrop.vertical;
|
|
759
|
+
const paddingStart = vCrop.paddingStart ?? 0;
|
|
760
|
+
const paddingEnd = vCrop.paddingEnd ?? 0;
|
|
761
|
+
if (vCrop.mode === "all-elements") {
|
|
762
|
+
let minY = canvasHeight;
|
|
763
|
+
let maxY = 0;
|
|
764
|
+
for (const elem of elements) {
|
|
765
|
+
minY = Math.min(minY, elem.y);
|
|
766
|
+
maxY = Math.max(maxY, elem.y + elem.height);
|
|
767
|
+
}
|
|
768
|
+
if (elements.length > 0) {
|
|
769
|
+
cropY = Math.max(0, minY - paddingStart);
|
|
770
|
+
const bottomY = Math.min(canvasHeight, maxY + paddingEnd);
|
|
771
|
+
cropHeight = bottomY - cropY;
|
|
772
|
+
}
|
|
773
|
+
} else if (vCrop.mode === "between-elements") {
|
|
774
|
+
const startElementId = resolveBoundary(vCrop.startBoundary);
|
|
775
|
+
const endElementId = resolveBoundary(vCrop.endBoundary);
|
|
776
|
+
let topY = 0;
|
|
777
|
+
let bottomY = canvasHeight;
|
|
778
|
+
if (startElementId) {
|
|
779
|
+
const startElem = elementMap.get(startElementId);
|
|
780
|
+
if (startElem) {
|
|
781
|
+
topY = startElem.y;
|
|
782
|
+
}
|
|
783
|
+
}
|
|
784
|
+
if (endElementId) {
|
|
785
|
+
const endElem = elementMap.get(endElementId);
|
|
786
|
+
if (endElem) {
|
|
787
|
+
bottomY = endElem.y + endElem.height;
|
|
788
|
+
}
|
|
789
|
+
}
|
|
790
|
+
cropY = Math.max(0, topY - paddingStart);
|
|
791
|
+
const adjustedBottom = Math.min(canvasHeight, bottomY + paddingEnd);
|
|
792
|
+
cropHeight = adjustedBottom - cropY;
|
|
793
|
+
}
|
|
794
|
+
if (vCrop.minSize && cropHeight < vCrop.minSize) {
|
|
795
|
+
cropHeight = vCrop.minSize;
|
|
796
|
+
}
|
|
797
|
+
}
|
|
798
|
+
let cropX = 0;
|
|
799
|
+
let cropWidth = canvasWidth;
|
|
800
|
+
if (dynamicCrop.horizontal?.enabled) {
|
|
801
|
+
const hCrop = dynamicCrop.horizontal;
|
|
802
|
+
const paddingStart = hCrop.paddingStart ?? 0;
|
|
803
|
+
const paddingEnd = hCrop.paddingEnd ?? 0;
|
|
804
|
+
if (hCrop.mode === "all-elements") {
|
|
805
|
+
let minX = canvasWidth;
|
|
806
|
+
let maxX = 0;
|
|
807
|
+
for (const elem of elements) {
|
|
808
|
+
minX = Math.min(minX, elem.x);
|
|
809
|
+
maxX = Math.max(maxX, elem.x + elem.width);
|
|
810
|
+
}
|
|
811
|
+
if (elements.length > 0) {
|
|
812
|
+
cropX = Math.max(0, minX - paddingStart);
|
|
813
|
+
const rightX = Math.min(canvasWidth, maxX + paddingEnd);
|
|
814
|
+
cropWidth = rightX - cropX;
|
|
815
|
+
}
|
|
816
|
+
} else if (hCrop.mode === "between-elements") {
|
|
817
|
+
const startElementId = resolveBoundary(hCrop.startBoundary);
|
|
818
|
+
const endElementId = resolveBoundary(hCrop.endBoundary);
|
|
819
|
+
let leftX = 0;
|
|
820
|
+
let rightX = canvasWidth;
|
|
821
|
+
if (startElementId) {
|
|
822
|
+
const startElem = elementMap.get(startElementId);
|
|
823
|
+
if (startElem) {
|
|
824
|
+
leftX = startElem.x;
|
|
825
|
+
}
|
|
826
|
+
}
|
|
827
|
+
if (endElementId) {
|
|
828
|
+
const endElem = elementMap.get(endElementId);
|
|
829
|
+
if (endElem) {
|
|
830
|
+
rightX = endElem.x + endElem.width;
|
|
831
|
+
}
|
|
832
|
+
}
|
|
833
|
+
cropX = Math.max(0, leftX - paddingStart);
|
|
834
|
+
const adjustedRight = Math.min(canvasWidth, rightX + paddingEnd);
|
|
835
|
+
cropWidth = adjustedRight - cropX;
|
|
836
|
+
}
|
|
837
|
+
if (hCrop.minSize && cropWidth < hCrop.minSize) {
|
|
838
|
+
cropWidth = hCrop.minSize;
|
|
839
|
+
}
|
|
840
|
+
}
|
|
841
|
+
return { x: cropX, y: cropY, width: cropWidth, height: cropHeight };
|
|
842
|
+
}
|
|
843
|
+
function isDynamicCropEnabled(dynamicCrop) {
|
|
844
|
+
if (!dynamicCrop) return false;
|
|
845
|
+
return !!(dynamicCrop.vertical?.enabled || dynamicCrop.horizontal?.enabled);
|
|
846
|
+
}
|
|
847
|
+
|
|
741
848
|
// src/compositions/ImageEditorComposition.tsx
|
|
742
849
|
import { jsx as jsx3, jsxs } from "react/jsx-runtime";
|
|
743
850
|
function getSortedSegments(config) {
|
|
@@ -813,11 +920,16 @@ function ImageEditorComposition({
|
|
|
813
920
|
elements,
|
|
814
921
|
width,
|
|
815
922
|
height,
|
|
923
|
+
backgroundType = "image",
|
|
924
|
+
backgroundColor,
|
|
816
925
|
backgroundFit = "cover",
|
|
817
926
|
backgroundUrl,
|
|
818
927
|
imageUrls = {},
|
|
819
|
-
textValues = {}
|
|
928
|
+
textValues = {},
|
|
929
|
+
dynamicCrop
|
|
820
930
|
}) {
|
|
931
|
+
const canvasWidth = width ?? config?.width ?? 1080;
|
|
932
|
+
const canvasHeight = height ?? config?.height ?? 1920;
|
|
821
933
|
const resolvedElements = useMemo3(() => {
|
|
822
934
|
if (!elements) return null;
|
|
823
935
|
const result = resolveElementPositions(elements, textValues);
|
|
@@ -826,6 +938,10 @@ function ImageEditorComposition({
|
|
|
826
938
|
}
|
|
827
939
|
return result.elements;
|
|
828
940
|
}, [elements, textValues]);
|
|
941
|
+
const cropBounds = useMemo3(() => {
|
|
942
|
+
if (!isDynamicCropEnabled(dynamicCrop) || !resolvedElements) return null;
|
|
943
|
+
return calculateCropBounds(resolvedElements, dynamicCrop, canvasWidth, canvasHeight);
|
|
944
|
+
}, [resolvedElements, dynamicCrop, canvasWidth, canvasHeight]);
|
|
829
945
|
const segmentsFromElements = useMemo3(() => {
|
|
830
946
|
if (!resolvedElements) return null;
|
|
831
947
|
const segments = [];
|
|
@@ -842,10 +958,10 @@ function ImageEditorComposition({
|
|
|
842
958
|
}
|
|
843
959
|
return segments.sort((a, b) => (a.zIndex ?? 0) - (b.zIndex ?? 0));
|
|
844
960
|
}, [resolvedElements, imageUrls, textValues]);
|
|
845
|
-
const canvasWidth = width ?? config?.width ?? 1080;
|
|
846
|
-
const canvasHeight = height ?? config?.height ?? 1920;
|
|
847
961
|
const bgFit = backgroundFit ?? "cover";
|
|
848
962
|
const bgUrl = backgroundUrl ?? sources.background;
|
|
963
|
+
const cropOffsetX = cropBounds?.x ?? 0;
|
|
964
|
+
const cropOffsetY = cropBounds?.y ?? 0;
|
|
849
965
|
const contentSegments = segmentsFromElements ?? (() => {
|
|
850
966
|
if (!config) return [];
|
|
851
967
|
const sorted = getSortedSegments(config);
|
|
@@ -865,61 +981,74 @@ function ImageEditorComposition({
|
|
|
865
981
|
}
|
|
866
982
|
return void 0;
|
|
867
983
|
};
|
|
868
|
-
|
|
869
|
-
|
|
870
|
-
|
|
871
|
-
|
|
872
|
-
|
|
873
|
-
|
|
874
|
-
|
|
875
|
-
|
|
876
|
-
|
|
877
|
-
|
|
878
|
-
|
|
879
|
-
|
|
880
|
-
|
|
881
|
-
|
|
882
|
-
),
|
|
883
|
-
legacyBackgroundSegment && !segmentsFromElements && /* @__PURE__ */ jsx3(
|
|
884
|
-
BackgroundImage,
|
|
885
|
-
{
|
|
886
|
-
segment: legacyBackgroundSegment,
|
|
887
|
-
src: getSource(legacyBackgroundSegment),
|
|
888
|
-
width: canvasWidth,
|
|
889
|
-
height: canvasHeight,
|
|
890
|
-
scale
|
|
891
|
-
}
|
|
892
|
-
),
|
|
893
|
-
contentSegments.map((segment) => {
|
|
894
|
-
if (segment.type === "text") {
|
|
895
|
-
return /* @__PURE__ */ jsx3(
|
|
896
|
-
TextElement,
|
|
984
|
+
const containerBgColor = backgroundType === "color" && backgroundColor ? backgroundColor : "#000000";
|
|
985
|
+
return /* @__PURE__ */ jsx3(AbsoluteFill, { style: { backgroundColor: containerBgColor }, children: /* @__PURE__ */ jsxs(
|
|
986
|
+
"div",
|
|
987
|
+
{
|
|
988
|
+
style: {
|
|
989
|
+
position: "absolute",
|
|
990
|
+
left: -cropOffsetX * scale,
|
|
991
|
+
top: -cropOffsetY * scale,
|
|
992
|
+
width: canvasWidth * scale,
|
|
993
|
+
height: canvasHeight * scale
|
|
994
|
+
},
|
|
995
|
+
children: [
|
|
996
|
+
backgroundType === "image" && bgUrl && segmentsFromElements && /* @__PURE__ */ jsx3(
|
|
997
|
+
Img2,
|
|
897
998
|
{
|
|
898
|
-
|
|
899
|
-
|
|
900
|
-
|
|
901
|
-
|
|
902
|
-
|
|
903
|
-
|
|
904
|
-
|
|
905
|
-
|
|
906
|
-
|
|
907
|
-
|
|
908
|
-
|
|
909
|
-
|
|
910
|
-
|
|
911
|
-
ImageElement,
|
|
999
|
+
src: bgUrl,
|
|
1000
|
+
style: {
|
|
1001
|
+
position: "absolute",
|
|
1002
|
+
left: 0,
|
|
1003
|
+
top: 0,
|
|
1004
|
+
width: canvasWidth * scale,
|
|
1005
|
+
height: canvasHeight * scale,
|
|
1006
|
+
objectFit: bgFit
|
|
1007
|
+
}
|
|
1008
|
+
}
|
|
1009
|
+
),
|
|
1010
|
+
legacyBackgroundSegment && !segmentsFromElements && /* @__PURE__ */ jsx3(
|
|
1011
|
+
BackgroundImage,
|
|
912
1012
|
{
|
|
913
|
-
segment,
|
|
914
|
-
src,
|
|
1013
|
+
segment: legacyBackgroundSegment,
|
|
1014
|
+
src: getSource(legacyBackgroundSegment),
|
|
1015
|
+
width: canvasWidth,
|
|
1016
|
+
height: canvasHeight,
|
|
915
1017
|
scale
|
|
916
|
-
}
|
|
917
|
-
|
|
918
|
-
)
|
|
919
|
-
|
|
920
|
-
|
|
921
|
-
|
|
922
|
-
|
|
1018
|
+
}
|
|
1019
|
+
),
|
|
1020
|
+
contentSegments.map((segment) => {
|
|
1021
|
+
if (segment.type === "text") {
|
|
1022
|
+
return /* @__PURE__ */ jsx3(
|
|
1023
|
+
TextElement,
|
|
1024
|
+
{
|
|
1025
|
+
segment,
|
|
1026
|
+
scale
|
|
1027
|
+
},
|
|
1028
|
+
segment.id
|
|
1029
|
+
);
|
|
1030
|
+
}
|
|
1031
|
+
if (segment.type === "image") {
|
|
1032
|
+
const src = segment.source || getSource(segment);
|
|
1033
|
+
if (!src) {
|
|
1034
|
+
console.warn(`No source found for image segment: ${segment.id}`);
|
|
1035
|
+
return null;
|
|
1036
|
+
}
|
|
1037
|
+
return /* @__PURE__ */ jsx3(
|
|
1038
|
+
ImageElement,
|
|
1039
|
+
{
|
|
1040
|
+
segment,
|
|
1041
|
+
src,
|
|
1042
|
+
scale
|
|
1043
|
+
},
|
|
1044
|
+
segment.id
|
|
1045
|
+
);
|
|
1046
|
+
}
|
|
1047
|
+
return null;
|
|
1048
|
+
})
|
|
1049
|
+
]
|
|
1050
|
+
}
|
|
1051
|
+
) });
|
|
923
1052
|
}
|
|
924
1053
|
function BackgroundImage({
|
|
925
1054
|
segment,
|
|
@@ -1424,6 +1553,7 @@ export {
|
|
|
1424
1553
|
areFontsLoaded,
|
|
1425
1554
|
buildFontString,
|
|
1426
1555
|
calculateAutoWidthDimensions,
|
|
1556
|
+
calculateCropBounds,
|
|
1427
1557
|
calculateFitDimensions,
|
|
1428
1558
|
calculateLineWidth,
|
|
1429
1559
|
canSetAsReference,
|
|
@@ -1433,6 +1563,7 @@ export {
|
|
|
1433
1563
|
getReferenceElementX,
|
|
1434
1564
|
getReferenceElementY,
|
|
1435
1565
|
hexToRgba,
|
|
1566
|
+
isDynamicCropEnabled,
|
|
1436
1567
|
parseHexColor,
|
|
1437
1568
|
preloadFonts,
|
|
1438
1569
|
resolveElementPositions,
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "ugcinc-render",
|
|
3
|
-
"version": "1.3.
|
|
3
|
+
"version": "1.3.14",
|
|
4
4
|
"description": "Unified rendering package for UGC Inc - shared types, components, and compositions for pixel-perfect client/server rendering",
|
|
5
5
|
"main": "dist/index.js",
|
|
6
6
|
"module": "dist/index.mjs",
|