ugcinc-render 1.5.24 → 1.5.26

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 CHANGED
@@ -1239,9 +1239,10 @@ declare function getReferenceElementY(elements: ImageEditorElement[], elementId:
1239
1239
  * @param dynamicCrop - Crop configuration
1240
1240
  * @param canvasWidth - Original canvas width
1241
1241
  * @param canvasHeight - Original canvas height
1242
+ * @param textValues - Optional map of textInputId -> text content for height calculation
1242
1243
  * @returns CropBounds with x, y, width, height
1243
1244
  */
1244
- declare function calculateCropBounds(elements: ImageEditorElement[], dynamicCrop: DynamicCropConfig | undefined, canvasWidth: number, canvasHeight: number): CropBounds;
1245
+ declare function calculateCropBounds(elements: ImageEditorElement[], dynamicCrop: DynamicCropConfig | undefined, canvasWidth: number, canvasHeight: number, textValues?: Record<string, string>): CropBounds;
1245
1246
  /**
1246
1247
  * Check if dynamic crop is enabled (either vertical or horizontal)
1247
1248
  */
@@ -1364,6 +1365,9 @@ declare function useResolvedPositions(elements: ImageEditorElement[], textValues
1364
1365
  *
1365
1366
  * This file registers all available compositions with the renderer.
1366
1367
  * It serves as the entry point for the renderer bundler.
1368
+ *
1369
+ * Uses calculateMetadata for ImageEditorComposition to determine
1370
+ * dynamic crop dimensions in the browser environment (with DOM access).
1367
1371
  */
1368
1372
 
1369
1373
  declare const RenderRoot: React.FC;
package/dist/index.d.ts CHANGED
@@ -1239,9 +1239,10 @@ declare function getReferenceElementY(elements: ImageEditorElement[], elementId:
1239
1239
  * @param dynamicCrop - Crop configuration
1240
1240
  * @param canvasWidth - Original canvas width
1241
1241
  * @param canvasHeight - Original canvas height
1242
+ * @param textValues - Optional map of textInputId -> text content for height calculation
1242
1243
  * @returns CropBounds with x, y, width, height
1243
1244
  */
1244
- declare function calculateCropBounds(elements: ImageEditorElement[], dynamicCrop: DynamicCropConfig | undefined, canvasWidth: number, canvasHeight: number): CropBounds;
1245
+ declare function calculateCropBounds(elements: ImageEditorElement[], dynamicCrop: DynamicCropConfig | undefined, canvasWidth: number, canvasHeight: number, textValues?: Record<string, string>): CropBounds;
1245
1246
  /**
1246
1247
  * Check if dynamic crop is enabled (either vertical or horizontal)
1247
1248
  */
@@ -1364,6 +1365,9 @@ declare function useResolvedPositions(elements: ImageEditorElement[], textValues
1364
1365
  *
1365
1366
  * This file registers all available compositions with the renderer.
1366
1367
  * It serves as the entry point for the renderer bundler.
1368
+ *
1369
+ * Uses calculateMetadata for ImageEditorComposition to determine
1370
+ * dynamic crop dimensions in the browser environment (with DOM access).
1367
1371
  */
1368
1372
 
1369
1373
  declare const RenderRoot: React.FC;
package/dist/index.js CHANGED
@@ -1167,7 +1167,16 @@ function getReferenceElementY(elements, elementId) {
1167
1167
  }
1168
1168
 
1169
1169
  // src/utils/cropBounds.ts
1170
- function calculateCropBounds(elements, dynamicCrop, canvasWidth, canvasHeight) {
1170
+ function getActualElementHeight(elem, textValues, measureCtx) {
1171
+ if (elem.type !== "text") return elem.height;
1172
+ let textContent = elem.text ?? "Text";
1173
+ if (elem.textInputId && textValues?.[elem.textInputId]) {
1174
+ textContent = textValues[elem.textInputId];
1175
+ }
1176
+ const result = calculateAutoWidthDimensions(elem, textContent, measureCtx);
1177
+ return result?.actualHeight ?? elem.height;
1178
+ }
1179
+ function calculateCropBounds(elements, dynamicCrop, canvasWidth, canvasHeight, textValues) {
1171
1180
  if (!dynamicCrop) {
1172
1181
  return { x: 0, y: 0, width: canvasWidth, height: canvasHeight };
1173
1182
  }
@@ -1180,6 +1189,12 @@ function calculateCropBounds(elements, dynamicCrop, canvasWidth, canvasHeight) {
1180
1189
  if (boundary.elementId) return boundary.elementId;
1181
1190
  return void 0;
1182
1191
  };
1192
+ let measureCtx = null;
1193
+ const hasTextElements = elements.some((e) => e.type === "text");
1194
+ if (hasTextElements && typeof document !== "undefined") {
1195
+ const canvas = document.createElement("canvas");
1196
+ measureCtx = canvas.getContext("2d");
1197
+ }
1183
1198
  let cropY = 0;
1184
1199
  let cropHeight = canvasHeight;
1185
1200
  if (dynamicCrop.vertical?.enabled) {
@@ -1190,8 +1205,9 @@ function calculateCropBounds(elements, dynamicCrop, canvasWidth, canvasHeight) {
1190
1205
  let minY = canvasHeight;
1191
1206
  let maxY = 0;
1192
1207
  for (const elem of elements) {
1208
+ const actualHeight = getActualElementHeight(elem, textValues, measureCtx);
1193
1209
  minY = Math.min(minY, elem.y);
1194
- maxY = Math.max(maxY, elem.y + elem.height);
1210
+ maxY = Math.max(maxY, elem.y + actualHeight);
1195
1211
  }
1196
1212
  if (elements.length > 0) {
1197
1213
  cropY = Math.max(0, minY - paddingStart);
@@ -1212,7 +1228,8 @@ function calculateCropBounds(elements, dynamicCrop, canvasWidth, canvasHeight) {
1212
1228
  if (endElementId) {
1213
1229
  const endElem = elementMap.get(endElementId);
1214
1230
  if (endElem) {
1215
- bottomY = endElem.y + endElem.height;
1231
+ const actualHeight = getActualElementHeight(endElem, textValues, measureCtx);
1232
+ bottomY = endElem.y + actualHeight;
1216
1233
  }
1217
1234
  }
1218
1235
  cropY = Math.max(0, topY - paddingStart);
@@ -1446,8 +1463,8 @@ function ImageEditorComposition({
1446
1463
  }, [elements, textValues]);
1447
1464
  const cropBounds = (0, import_react3.useMemo)(() => {
1448
1465
  if (!isDynamicCropEnabled(dynamicCrop) || !resolvedElements) return null;
1449
- return calculateCropBounds(resolvedElements, dynamicCrop, canvasWidth, canvasHeight);
1450
- }, [resolvedElements, dynamicCrop, canvasWidth, canvasHeight]);
1466
+ return calculateCropBounds(resolvedElements, dynamicCrop, canvasWidth, canvasHeight, textValues);
1467
+ }, [resolvedElements, dynamicCrop, canvasWidth, canvasHeight, textValues]);
1451
1468
  const segmentsFromElements = (0, import_react3.useMemo)(() => {
1452
1469
  if (!resolvedElements) return null;
1453
1470
  const segments = [];
@@ -2109,6 +2126,55 @@ var defaultVideoProps = {
2109
2126
  };
2110
2127
  var ImageComp = ImageEditorComposition;
2111
2128
  var VideoComp = VideoEditorComposition;
2129
+ var calculateImageMetadata = async ({ props }) => {
2130
+ console.log("[calculateMetadata] Starting metadata calculation...");
2131
+ const canvasWidth = props.width ?? props.config?.width ?? 1080;
2132
+ const canvasHeight = props.height ?? props.config?.height ?? 1920;
2133
+ const defaultResult = {
2134
+ width: canvasWidth,
2135
+ height: canvasHeight,
2136
+ fps: 30,
2137
+ durationInFrames: 1
2138
+ };
2139
+ if (!props.elements || !props.dynamicCrop) {
2140
+ console.log("[calculateMetadata] No elements or dynamicCrop, using default dimensions:", canvasWidth, "x", canvasHeight);
2141
+ return defaultResult;
2142
+ }
2143
+ if (!isDynamicCropEnabled(props.dynamicCrop)) {
2144
+ console.log("[calculateMetadata] Dynamic crop not enabled, using default dimensions:", canvasWidth, "x", canvasHeight);
2145
+ return defaultResult;
2146
+ }
2147
+ console.log("[calculateMetadata] Dynamic crop enabled, loading fonts for accurate measurement...");
2148
+ try {
2149
+ await preloadFonts();
2150
+ console.log("[calculateMetadata] Fonts loaded successfully");
2151
+ } catch (err) {
2152
+ console.error("[calculateMetadata] Font loading failed:", err);
2153
+ }
2154
+ await new Promise((resolve) => setTimeout(resolve, 50));
2155
+ console.log("[calculateMetadata] Resolving element positions with DOM measurement...");
2156
+ const { elements: resolvedElements } = resolveElementPositions(
2157
+ props.elements,
2158
+ props.textValues ?? {}
2159
+ );
2160
+ console.log("[calculateMetadata] Element positions resolved");
2161
+ const cropBounds = calculateCropBounds(
2162
+ resolvedElements,
2163
+ props.dynamicCrop,
2164
+ canvasWidth,
2165
+ canvasHeight,
2166
+ props.textValues
2167
+ );
2168
+ const outputWidth = Math.round(cropBounds.width);
2169
+ const outputHeight = Math.round(cropBounds.height);
2170
+ console.log(`[calculateMetadata] Crop bounds calculated: ${canvasWidth}x${canvasHeight} -> ${outputWidth}x${outputHeight} (offset: ${cropBounds.x}, ${cropBounds.y})`);
2171
+ return {
2172
+ width: outputWidth,
2173
+ height: outputHeight,
2174
+ fps: 30,
2175
+ durationInFrames: 1
2176
+ };
2177
+ };
2112
2178
  var RenderRoot = () => {
2113
2179
  return /* @__PURE__ */ (0, import_jsx_runtime6.jsxs)(import_jsx_runtime6.Fragment, { children: [
2114
2180
  /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(
@@ -2116,8 +2182,9 @@ var RenderRoot = () => {
2116
2182
  {
2117
2183
  id: "ImageEditorComposition",
2118
2184
  component: ImageComp,
2185
+ calculateMetadata: calculateImageMetadata,
2119
2186
  durationInFrames: 1,
2120
- fps: 1,
2187
+ fps: 30,
2121
2188
  width: 1080,
2122
2189
  height: 1920,
2123
2190
  defaultProps: defaultImageProps
package/dist/index.mjs CHANGED
@@ -1081,7 +1081,16 @@ function getReferenceElementY(elements, elementId) {
1081
1081
  }
1082
1082
 
1083
1083
  // src/utils/cropBounds.ts
1084
- function calculateCropBounds(elements, dynamicCrop, canvasWidth, canvasHeight) {
1084
+ function getActualElementHeight(elem, textValues, measureCtx) {
1085
+ if (elem.type !== "text") return elem.height;
1086
+ let textContent = elem.text ?? "Text";
1087
+ if (elem.textInputId && textValues?.[elem.textInputId]) {
1088
+ textContent = textValues[elem.textInputId];
1089
+ }
1090
+ const result = calculateAutoWidthDimensions(elem, textContent, measureCtx);
1091
+ return result?.actualHeight ?? elem.height;
1092
+ }
1093
+ function calculateCropBounds(elements, dynamicCrop, canvasWidth, canvasHeight, textValues) {
1085
1094
  if (!dynamicCrop) {
1086
1095
  return { x: 0, y: 0, width: canvasWidth, height: canvasHeight };
1087
1096
  }
@@ -1094,6 +1103,12 @@ function calculateCropBounds(elements, dynamicCrop, canvasWidth, canvasHeight) {
1094
1103
  if (boundary.elementId) return boundary.elementId;
1095
1104
  return void 0;
1096
1105
  };
1106
+ let measureCtx = null;
1107
+ const hasTextElements = elements.some((e) => e.type === "text");
1108
+ if (hasTextElements && typeof document !== "undefined") {
1109
+ const canvas = document.createElement("canvas");
1110
+ measureCtx = canvas.getContext("2d");
1111
+ }
1097
1112
  let cropY = 0;
1098
1113
  let cropHeight = canvasHeight;
1099
1114
  if (dynamicCrop.vertical?.enabled) {
@@ -1104,8 +1119,9 @@ function calculateCropBounds(elements, dynamicCrop, canvasWidth, canvasHeight) {
1104
1119
  let minY = canvasHeight;
1105
1120
  let maxY = 0;
1106
1121
  for (const elem of elements) {
1122
+ const actualHeight = getActualElementHeight(elem, textValues, measureCtx);
1107
1123
  minY = Math.min(minY, elem.y);
1108
- maxY = Math.max(maxY, elem.y + elem.height);
1124
+ maxY = Math.max(maxY, elem.y + actualHeight);
1109
1125
  }
1110
1126
  if (elements.length > 0) {
1111
1127
  cropY = Math.max(0, minY - paddingStart);
@@ -1126,7 +1142,8 @@ function calculateCropBounds(elements, dynamicCrop, canvasWidth, canvasHeight) {
1126
1142
  if (endElementId) {
1127
1143
  const endElem = elementMap.get(endElementId);
1128
1144
  if (endElem) {
1129
- bottomY = endElem.y + endElem.height;
1145
+ const actualHeight = getActualElementHeight(endElem, textValues, measureCtx);
1146
+ bottomY = endElem.y + actualHeight;
1130
1147
  }
1131
1148
  }
1132
1149
  cropY = Math.max(0, topY - paddingStart);
@@ -1360,8 +1377,8 @@ function ImageEditorComposition({
1360
1377
  }, [elements, textValues]);
1361
1378
  const cropBounds = useMemo3(() => {
1362
1379
  if (!isDynamicCropEnabled(dynamicCrop) || !resolvedElements) return null;
1363
- return calculateCropBounds(resolvedElements, dynamicCrop, canvasWidth, canvasHeight);
1364
- }, [resolvedElements, dynamicCrop, canvasWidth, canvasHeight]);
1380
+ return calculateCropBounds(resolvedElements, dynamicCrop, canvasWidth, canvasHeight, textValues);
1381
+ }, [resolvedElements, dynamicCrop, canvasWidth, canvasHeight, textValues]);
1365
1382
  const segmentsFromElements = useMemo3(() => {
1366
1383
  if (!resolvedElements) return null;
1367
1384
  const segments = [];
@@ -2023,6 +2040,55 @@ var defaultVideoProps = {
2023
2040
  };
2024
2041
  var ImageComp = ImageEditorComposition;
2025
2042
  var VideoComp = VideoEditorComposition;
2043
+ var calculateImageMetadata = async ({ props }) => {
2044
+ console.log("[calculateMetadata] Starting metadata calculation...");
2045
+ const canvasWidth = props.width ?? props.config?.width ?? 1080;
2046
+ const canvasHeight = props.height ?? props.config?.height ?? 1920;
2047
+ const defaultResult = {
2048
+ width: canvasWidth,
2049
+ height: canvasHeight,
2050
+ fps: 30,
2051
+ durationInFrames: 1
2052
+ };
2053
+ if (!props.elements || !props.dynamicCrop) {
2054
+ console.log("[calculateMetadata] No elements or dynamicCrop, using default dimensions:", canvasWidth, "x", canvasHeight);
2055
+ return defaultResult;
2056
+ }
2057
+ if (!isDynamicCropEnabled(props.dynamicCrop)) {
2058
+ console.log("[calculateMetadata] Dynamic crop not enabled, using default dimensions:", canvasWidth, "x", canvasHeight);
2059
+ return defaultResult;
2060
+ }
2061
+ console.log("[calculateMetadata] Dynamic crop enabled, loading fonts for accurate measurement...");
2062
+ try {
2063
+ await preloadFonts();
2064
+ console.log("[calculateMetadata] Fonts loaded successfully");
2065
+ } catch (err) {
2066
+ console.error("[calculateMetadata] Font loading failed:", err);
2067
+ }
2068
+ await new Promise((resolve) => setTimeout(resolve, 50));
2069
+ console.log("[calculateMetadata] Resolving element positions with DOM measurement...");
2070
+ const { elements: resolvedElements } = resolveElementPositions(
2071
+ props.elements,
2072
+ props.textValues ?? {}
2073
+ );
2074
+ console.log("[calculateMetadata] Element positions resolved");
2075
+ const cropBounds = calculateCropBounds(
2076
+ resolvedElements,
2077
+ props.dynamicCrop,
2078
+ canvasWidth,
2079
+ canvasHeight,
2080
+ props.textValues
2081
+ );
2082
+ const outputWidth = Math.round(cropBounds.width);
2083
+ const outputHeight = Math.round(cropBounds.height);
2084
+ console.log(`[calculateMetadata] Crop bounds calculated: ${canvasWidth}x${canvasHeight} -> ${outputWidth}x${outputHeight} (offset: ${cropBounds.x}, ${cropBounds.y})`);
2085
+ return {
2086
+ width: outputWidth,
2087
+ height: outputHeight,
2088
+ fps: 30,
2089
+ durationInFrames: 1
2090
+ };
2091
+ };
2026
2092
  var RenderRoot = () => {
2027
2093
  return /* @__PURE__ */ jsxs4(Fragment, { children: [
2028
2094
  /* @__PURE__ */ jsx6(
@@ -2030,8 +2096,9 @@ var RenderRoot = () => {
2030
2096
  {
2031
2097
  id: "ImageEditorComposition",
2032
2098
  component: ImageComp,
2099
+ calculateMetadata: calculateImageMetadata,
2033
2100
  durationInFrames: 1,
2034
- fps: 1,
2101
+ fps: 30,
2035
2102
  width: 1080,
2036
2103
  height: 1920,
2037
2104
  defaultProps: defaultImageProps
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "ugcinc-render",
3
- "version": "1.5.24",
3
+ "version": "1.5.26",
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",