ugcinc-render 1.5.0 → 1.5.2
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 +71 -7
- package/dist/index.mjs +71 -7
- package/package.json +1 -1
package/dist/index.js
CHANGED
|
@@ -294,6 +294,55 @@ function hexToRgba(hex, opacity = 100) {
|
|
|
294
294
|
|
|
295
295
|
// src/components/TextElement.tsx
|
|
296
296
|
var import_jsx_runtime = require("react/jsx-runtime");
|
|
297
|
+
function calculateAutoWidth({
|
|
298
|
+
text,
|
|
299
|
+
maxWidth,
|
|
300
|
+
paddingLeft,
|
|
301
|
+
paddingRight,
|
|
302
|
+
fontSize,
|
|
303
|
+
fontWeight,
|
|
304
|
+
fontFamily,
|
|
305
|
+
letterSpacing
|
|
306
|
+
}) {
|
|
307
|
+
if (typeof document === "undefined") {
|
|
308
|
+
throw new Error("calculateAutoWidth requires a browser environment with document available");
|
|
309
|
+
}
|
|
310
|
+
const canvas = document.createElement("canvas");
|
|
311
|
+
const ctx = canvas.getContext("2d");
|
|
312
|
+
if (!ctx) {
|
|
313
|
+
throw new Error("Failed to get 2D canvas context for text measurement");
|
|
314
|
+
}
|
|
315
|
+
ctx.font = `${fontWeight} ${fontSize}px ${fontFamily}`;
|
|
316
|
+
const availableWidth = maxWidth - paddingLeft - paddingRight;
|
|
317
|
+
const words = text.split(" ");
|
|
318
|
+
const lines = [];
|
|
319
|
+
let currentLine = "";
|
|
320
|
+
for (const word of words) {
|
|
321
|
+
if (!word) continue;
|
|
322
|
+
const testLine = currentLine + (currentLine ? " " : "") + word;
|
|
323
|
+
const charCount = [...testLine].length;
|
|
324
|
+
const extraSpacing = charCount > 1 ? (charCount - 1) * letterSpacing : 0;
|
|
325
|
+
const totalWidth = ctx.measureText(testLine).width + extraSpacing;
|
|
326
|
+
if (totalWidth > availableWidth && currentLine) {
|
|
327
|
+
lines.push(currentLine);
|
|
328
|
+
currentLine = word;
|
|
329
|
+
} else {
|
|
330
|
+
currentLine = testLine;
|
|
331
|
+
}
|
|
332
|
+
}
|
|
333
|
+
if (currentLine) lines.push(currentLine);
|
|
334
|
+
let widestLineWidth = 0;
|
|
335
|
+
for (const line of lines) {
|
|
336
|
+
const chars = [...line];
|
|
337
|
+
let lineWidth = 0;
|
|
338
|
+
for (const char of chars) {
|
|
339
|
+
lineWidth += ctx.measureText(char).width + letterSpacing;
|
|
340
|
+
}
|
|
341
|
+
if (chars.length > 0) lineWidth -= letterSpacing;
|
|
342
|
+
widestLineWidth = Math.max(widestLineWidth, lineWidth);
|
|
343
|
+
}
|
|
344
|
+
return Math.min(widestLineWidth + paddingLeft + paddingRight, maxWidth);
|
|
345
|
+
}
|
|
297
346
|
function TextElement({ segment, scale = 1 }) {
|
|
298
347
|
const fontType = segment.fontType ?? TEXT_DEFAULTS.fontType;
|
|
299
348
|
const fontSize = (segment.fontSize ?? TEXT_DEFAULTS.fontSize) * scale;
|
|
@@ -306,10 +355,10 @@ function TextElement({ segment, scale = 1 }) {
|
|
|
306
355
|
const strokeColor = segment.strokeColor;
|
|
307
356
|
const strokeWidth = (segment.strokeWidth ?? TEXT_DEFAULTS.strokeWidth) * scale;
|
|
308
357
|
const uniformPadding = (segment.padding ?? TEXT_DEFAULTS.padding) * scale;
|
|
309
|
-
const paddingTop = segment.paddingTop
|
|
310
|
-
const paddingRight = segment.paddingRight
|
|
311
|
-
const paddingBottom = segment.paddingBottom
|
|
312
|
-
const paddingLeft = segment.paddingLeft
|
|
358
|
+
const paddingTop = segment.paddingTop !== void 0 ? segment.paddingTop * scale : uniformPadding;
|
|
359
|
+
const paddingRight = segment.paddingRight !== void 0 ? segment.paddingRight * scale : uniformPadding;
|
|
360
|
+
const paddingBottom = segment.paddingBottom !== void 0 ? segment.paddingBottom * scale : uniformPadding;
|
|
361
|
+
const paddingLeft = segment.paddingLeft !== void 0 ? segment.paddingLeft * scale : uniformPadding;
|
|
313
362
|
const x = segment.xOffset * scale;
|
|
314
363
|
const y = segment.yOffset * scale;
|
|
315
364
|
const width = segment.width * scale;
|
|
@@ -321,6 +370,19 @@ function TextElement({ segment, scale = 1 }) {
|
|
|
321
370
|
const backgroundOpacity = segment.backgroundOpacity ?? TEXT_DEFAULTS.backgroundOpacity;
|
|
322
371
|
const backgroundBorderRadius = segment.backgroundBorderRadius;
|
|
323
372
|
const fontFamily = getFontFamily(fontType);
|
|
373
|
+
const calculatedWidth = (0, import_react.useMemo)(() => {
|
|
374
|
+
if (!autoWidth) return width;
|
|
375
|
+
return calculateAutoWidth({
|
|
376
|
+
text: segment.text,
|
|
377
|
+
maxWidth: width,
|
|
378
|
+
paddingLeft,
|
|
379
|
+
paddingRight,
|
|
380
|
+
fontSize,
|
|
381
|
+
fontWeight,
|
|
382
|
+
fontFamily,
|
|
383
|
+
letterSpacing
|
|
384
|
+
});
|
|
385
|
+
}, [autoWidth, segment.text, width, paddingLeft, paddingRight, fontSize, fontWeight, fontFamily, letterSpacing]);
|
|
324
386
|
const borderRadiusStyle = (0, import_react.useMemo)(() => {
|
|
325
387
|
if (!backgroundBorderRadius) return void 0;
|
|
326
388
|
const radii = getBorderRadii(backgroundBorderRadius);
|
|
@@ -344,8 +406,10 @@ function TextElement({ segment, scale = 1 }) {
|
|
|
344
406
|
}), [x, y, width, height, rotation, verticalAlign, autoWidth, boxAlign]);
|
|
345
407
|
const backgroundBoxStyle = (0, import_react.useMemo)(() => {
|
|
346
408
|
const baseStyle = autoWidth ? {
|
|
347
|
-
width
|
|
348
|
-
|
|
409
|
+
// Use explicit calculated width instead of fit-content
|
|
410
|
+
// This fixes the issue where multi-line text doesn't shrink to widest line
|
|
411
|
+
width: calculatedWidth,
|
|
412
|
+
maxWidth: width
|
|
349
413
|
} : {
|
|
350
414
|
// When not autoWidth, let the text div handle everything
|
|
351
415
|
display: "flex",
|
|
@@ -359,7 +423,7 @@ function TextElement({ segment, scale = 1 }) {
|
|
|
359
423
|
backgroundColor: hexToRgba(backgroundColor, backgroundOpacity),
|
|
360
424
|
borderRadius: borderRadiusStyle
|
|
361
425
|
};
|
|
362
|
-
}, [autoWidth, backgroundColor, backgroundOpacity, borderRadiusStyle]);
|
|
426
|
+
}, [autoWidth, calculatedWidth, width, backgroundColor, backgroundOpacity, borderRadiusStyle]);
|
|
363
427
|
const textStyle = (0, import_react.useMemo)(() => ({
|
|
364
428
|
fontFamily,
|
|
365
429
|
fontSize,
|
package/dist/index.mjs
CHANGED
|
@@ -220,6 +220,55 @@ function hexToRgba(hex, opacity = 100) {
|
|
|
220
220
|
|
|
221
221
|
// src/components/TextElement.tsx
|
|
222
222
|
import { jsx } from "react/jsx-runtime";
|
|
223
|
+
function calculateAutoWidth({
|
|
224
|
+
text,
|
|
225
|
+
maxWidth,
|
|
226
|
+
paddingLeft,
|
|
227
|
+
paddingRight,
|
|
228
|
+
fontSize,
|
|
229
|
+
fontWeight,
|
|
230
|
+
fontFamily,
|
|
231
|
+
letterSpacing
|
|
232
|
+
}) {
|
|
233
|
+
if (typeof document === "undefined") {
|
|
234
|
+
throw new Error("calculateAutoWidth requires a browser environment with document available");
|
|
235
|
+
}
|
|
236
|
+
const canvas = document.createElement("canvas");
|
|
237
|
+
const ctx = canvas.getContext("2d");
|
|
238
|
+
if (!ctx) {
|
|
239
|
+
throw new Error("Failed to get 2D canvas context for text measurement");
|
|
240
|
+
}
|
|
241
|
+
ctx.font = `${fontWeight} ${fontSize}px ${fontFamily}`;
|
|
242
|
+
const availableWidth = maxWidth - paddingLeft - paddingRight;
|
|
243
|
+
const words = text.split(" ");
|
|
244
|
+
const lines = [];
|
|
245
|
+
let currentLine = "";
|
|
246
|
+
for (const word of words) {
|
|
247
|
+
if (!word) continue;
|
|
248
|
+
const testLine = currentLine + (currentLine ? " " : "") + word;
|
|
249
|
+
const charCount = [...testLine].length;
|
|
250
|
+
const extraSpacing = charCount > 1 ? (charCount - 1) * letterSpacing : 0;
|
|
251
|
+
const totalWidth = ctx.measureText(testLine).width + extraSpacing;
|
|
252
|
+
if (totalWidth > availableWidth && currentLine) {
|
|
253
|
+
lines.push(currentLine);
|
|
254
|
+
currentLine = word;
|
|
255
|
+
} else {
|
|
256
|
+
currentLine = testLine;
|
|
257
|
+
}
|
|
258
|
+
}
|
|
259
|
+
if (currentLine) lines.push(currentLine);
|
|
260
|
+
let widestLineWidth = 0;
|
|
261
|
+
for (const line of lines) {
|
|
262
|
+
const chars = [...line];
|
|
263
|
+
let lineWidth = 0;
|
|
264
|
+
for (const char of chars) {
|
|
265
|
+
lineWidth += ctx.measureText(char).width + letterSpacing;
|
|
266
|
+
}
|
|
267
|
+
if (chars.length > 0) lineWidth -= letterSpacing;
|
|
268
|
+
widestLineWidth = Math.max(widestLineWidth, lineWidth);
|
|
269
|
+
}
|
|
270
|
+
return Math.min(widestLineWidth + paddingLeft + paddingRight, maxWidth);
|
|
271
|
+
}
|
|
223
272
|
function TextElement({ segment, scale = 1 }) {
|
|
224
273
|
const fontType = segment.fontType ?? TEXT_DEFAULTS.fontType;
|
|
225
274
|
const fontSize = (segment.fontSize ?? TEXT_DEFAULTS.fontSize) * scale;
|
|
@@ -232,10 +281,10 @@ function TextElement({ segment, scale = 1 }) {
|
|
|
232
281
|
const strokeColor = segment.strokeColor;
|
|
233
282
|
const strokeWidth = (segment.strokeWidth ?? TEXT_DEFAULTS.strokeWidth) * scale;
|
|
234
283
|
const uniformPadding = (segment.padding ?? TEXT_DEFAULTS.padding) * scale;
|
|
235
|
-
const paddingTop = segment.paddingTop
|
|
236
|
-
const paddingRight = segment.paddingRight
|
|
237
|
-
const paddingBottom = segment.paddingBottom
|
|
238
|
-
const paddingLeft = segment.paddingLeft
|
|
284
|
+
const paddingTop = segment.paddingTop !== void 0 ? segment.paddingTop * scale : uniformPadding;
|
|
285
|
+
const paddingRight = segment.paddingRight !== void 0 ? segment.paddingRight * scale : uniformPadding;
|
|
286
|
+
const paddingBottom = segment.paddingBottom !== void 0 ? segment.paddingBottom * scale : uniformPadding;
|
|
287
|
+
const paddingLeft = segment.paddingLeft !== void 0 ? segment.paddingLeft * scale : uniformPadding;
|
|
239
288
|
const x = segment.xOffset * scale;
|
|
240
289
|
const y = segment.yOffset * scale;
|
|
241
290
|
const width = segment.width * scale;
|
|
@@ -247,6 +296,19 @@ function TextElement({ segment, scale = 1 }) {
|
|
|
247
296
|
const backgroundOpacity = segment.backgroundOpacity ?? TEXT_DEFAULTS.backgroundOpacity;
|
|
248
297
|
const backgroundBorderRadius = segment.backgroundBorderRadius;
|
|
249
298
|
const fontFamily = getFontFamily(fontType);
|
|
299
|
+
const calculatedWidth = useMemo(() => {
|
|
300
|
+
if (!autoWidth) return width;
|
|
301
|
+
return calculateAutoWidth({
|
|
302
|
+
text: segment.text,
|
|
303
|
+
maxWidth: width,
|
|
304
|
+
paddingLeft,
|
|
305
|
+
paddingRight,
|
|
306
|
+
fontSize,
|
|
307
|
+
fontWeight,
|
|
308
|
+
fontFamily,
|
|
309
|
+
letterSpacing
|
|
310
|
+
});
|
|
311
|
+
}, [autoWidth, segment.text, width, paddingLeft, paddingRight, fontSize, fontWeight, fontFamily, letterSpacing]);
|
|
250
312
|
const borderRadiusStyle = useMemo(() => {
|
|
251
313
|
if (!backgroundBorderRadius) return void 0;
|
|
252
314
|
const radii = getBorderRadii(backgroundBorderRadius);
|
|
@@ -270,8 +332,10 @@ function TextElement({ segment, scale = 1 }) {
|
|
|
270
332
|
}), [x, y, width, height, rotation, verticalAlign, autoWidth, boxAlign]);
|
|
271
333
|
const backgroundBoxStyle = useMemo(() => {
|
|
272
334
|
const baseStyle = autoWidth ? {
|
|
273
|
-
width
|
|
274
|
-
|
|
335
|
+
// Use explicit calculated width instead of fit-content
|
|
336
|
+
// This fixes the issue where multi-line text doesn't shrink to widest line
|
|
337
|
+
width: calculatedWidth,
|
|
338
|
+
maxWidth: width
|
|
275
339
|
} : {
|
|
276
340
|
// When not autoWidth, let the text div handle everything
|
|
277
341
|
display: "flex",
|
|
@@ -285,7 +349,7 @@ function TextElement({ segment, scale = 1 }) {
|
|
|
285
349
|
backgroundColor: hexToRgba(backgroundColor, backgroundOpacity),
|
|
286
350
|
borderRadius: borderRadiusStyle
|
|
287
351
|
};
|
|
288
|
-
}, [autoWidth, backgroundColor, backgroundOpacity, borderRadiusStyle]);
|
|
352
|
+
}, [autoWidth, calculatedWidth, width, backgroundColor, backgroundOpacity, borderRadiusStyle]);
|
|
289
353
|
const textStyle = useMemo(() => ({
|
|
290
354
|
fontFamily,
|
|
291
355
|
fontSize,
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "ugcinc-render",
|
|
3
|
-
"version": "1.5.
|
|
3
|
+
"version": "1.5.2",
|
|
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",
|