ugcinc-render 1.5.17 → 1.5.19
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 +38 -41
- package/dist/index.mjs +38 -41
- package/package.json +1 -1
package/dist/index.js
CHANGED
|
@@ -420,29 +420,28 @@ function calculateAutoWidthAndLines({
|
|
|
420
420
|
white-space: nowrap;
|
|
421
421
|
`;
|
|
422
422
|
document.body.appendChild(measureSpan);
|
|
423
|
+
const computedStyle = window.getComputedStyle(measureSpan);
|
|
424
|
+
const computedFontFamily = computedStyle.fontFamily;
|
|
425
|
+
const requestedFontLoaded = typeof document.fonts !== "undefined" ? document.fonts.check(`${fontWeight} ${fontSize}px ${fontFamily.split(",")[0]}`) : "unknown";
|
|
423
426
|
const measureText = (textToMeasure) => {
|
|
424
427
|
measureSpan.textContent = textToMeasure;
|
|
425
428
|
return measureSpan.getBoundingClientRect().width;
|
|
426
429
|
};
|
|
427
430
|
measureSpan.textContent = "M";
|
|
428
|
-
const
|
|
431
|
+
const mWidth = measureSpan.getBoundingClientRect().width;
|
|
429
432
|
const words = text.split(/(\s+)/);
|
|
430
433
|
const lines = [];
|
|
431
434
|
let currentLine = "";
|
|
432
435
|
for (let i = 0; i < words.length; i++) {
|
|
433
436
|
const word = words[i];
|
|
434
437
|
if (word === "\n" || word === "\r\n") {
|
|
435
|
-
if (currentLine)
|
|
436
|
-
lines.push(currentLine);
|
|
437
|
-
}
|
|
438
|
+
if (currentLine) lines.push(currentLine);
|
|
438
439
|
currentLine = "";
|
|
439
440
|
continue;
|
|
440
441
|
}
|
|
441
442
|
if (!word) continue;
|
|
442
443
|
if (/^\s+$/.test(word)) {
|
|
443
|
-
if (currentLine)
|
|
444
|
-
currentLine += word;
|
|
445
|
-
}
|
|
444
|
+
if (currentLine) currentLine += word;
|
|
446
445
|
continue;
|
|
447
446
|
}
|
|
448
447
|
const testLine = currentLine + word;
|
|
@@ -477,12 +476,8 @@ function calculateAutoWidthAndLines({
|
|
|
477
476
|
currentLine = testLine;
|
|
478
477
|
}
|
|
479
478
|
}
|
|
480
|
-
if (currentLine.trim())
|
|
481
|
-
|
|
482
|
-
}
|
|
483
|
-
if (lines.length === 0) {
|
|
484
|
-
lines.push("");
|
|
485
|
-
}
|
|
479
|
+
if (currentLine.trim()) lines.push(currentLine.trimEnd());
|
|
480
|
+
if (lines.length === 0) lines.push("");
|
|
486
481
|
let widestLineWidth = 0;
|
|
487
482
|
for (const line of lines) {
|
|
488
483
|
const lineWidth = measureText(line);
|
|
@@ -490,18 +485,25 @@ function calculateAutoWidthAndLines({
|
|
|
490
485
|
}
|
|
491
486
|
document.body.removeChild(measureSpan);
|
|
492
487
|
const calculatedWidth = Math.min(widestLineWidth + paddingLeft + paddingRight, maxWidth);
|
|
488
|
+
console.log("[TextElement] WIDTH_CALC:", JSON.stringify({
|
|
489
|
+
text: text.substring(0, 30),
|
|
490
|
+
fontFamily: fontFamily.split(",")[0],
|
|
491
|
+
computedFont: computedFontFamily.split(",")[0],
|
|
492
|
+
fontLoaded: requestedFontLoaded,
|
|
493
|
+
fontSize,
|
|
494
|
+
fontWeight,
|
|
495
|
+
letterSpacing,
|
|
496
|
+
mWidth: Math.round(mWidth * 100) / 100,
|
|
497
|
+
widestLine: Math.round(widestLineWidth * 100) / 100,
|
|
498
|
+
paddingL: paddingLeft,
|
|
499
|
+
paddingR: paddingRight,
|
|
500
|
+
calcWidth: Math.round(calculatedWidth * 100) / 100,
|
|
501
|
+
maxWidth,
|
|
502
|
+
lines: lines.length
|
|
503
|
+
}));
|
|
493
504
|
return { width: calculatedWidth, lines };
|
|
494
505
|
}
|
|
495
506
|
function TextElement({ segment, scale = 1 }) {
|
|
496
|
-
import_react.default.useEffect(() => {
|
|
497
|
-
const fontFamily2 = getFontFamily(segment.fontType ?? TEXT_DEFAULTS.fontType);
|
|
498
|
-
console.log("[ugcinc-render/TextElement] Rendering with:", {
|
|
499
|
-
text: segment.text?.substring(0, 50) + (segment.text?.length > 50 ? "..." : ""),
|
|
500
|
-
fontType: segment.fontType ?? TEXT_DEFAULTS.fontType,
|
|
501
|
-
fontFamily: fontFamily2,
|
|
502
|
-
hasEmojis: /[\u{1F300}-\u{1F9FF}]/u.test(segment.text || "")
|
|
503
|
-
});
|
|
504
|
-
}, [segment.text, segment.fontType]);
|
|
505
507
|
const fontType = segment.fontType ?? TEXT_DEFAULTS.fontType;
|
|
506
508
|
const fontSize = (segment.fontSize ?? TEXT_DEFAULTS.fontSize) * scale;
|
|
507
509
|
const fontWeight = segment.fontWeight ?? TEXT_DEFAULTS.fontWeight;
|
|
@@ -623,24 +625,11 @@ function TextElement({ segment, scale = 1 }) {
|
|
|
623
625
|
transformOrigin: "center center",
|
|
624
626
|
display: "flex",
|
|
625
627
|
flexDirection: "column",
|
|
626
|
-
// Vertical alignment within the container
|
|
627
628
|
justifyContent: verticalAlign === "top" ? "flex-start" : verticalAlign === "bottom" ? "flex-end" : "center",
|
|
628
|
-
// Horizontal alignment (boxAlign) - only applies when autoWidth is enabled
|
|
629
629
|
alignItems: autoWidth ? boxAlign === "center" ? "center" : boxAlign === "right" ? "flex-end" : "flex-start" : "stretch"
|
|
630
630
|
}), [x, y, width, height, rotation, verticalAlign, autoWidth, boxAlign]);
|
|
631
631
|
const backgroundBoxStyle = (0, import_react.useMemo)(() => {
|
|
632
|
-
const baseStyle = autoWidth ? {
|
|
633
|
-
// Use explicit calculated width instead of fit-content
|
|
634
|
-
// This fixes the issue where multi-line text doesn't shrink to widest line
|
|
635
|
-
width: calculatedWidth,
|
|
636
|
-
maxWidth: width
|
|
637
|
-
} : {
|
|
638
|
-
// When not autoWidth, let the text div handle everything
|
|
639
|
-
display: "flex",
|
|
640
|
-
flexDirection: "column",
|
|
641
|
-
flex: 1,
|
|
642
|
-
minHeight: 0
|
|
643
|
-
};
|
|
632
|
+
const baseStyle = autoWidth ? { width: calculatedWidth, maxWidth: width } : { display: "flex", flexDirection: "column", flex: 1, minHeight: 0 };
|
|
644
633
|
if (!backgroundColor) return baseStyle;
|
|
645
634
|
return {
|
|
646
635
|
...baseStyle,
|
|
@@ -655,12 +644,10 @@ function TextElement({ segment, scale = 1 }) {
|
|
|
655
644
|
color,
|
|
656
645
|
lineHeight,
|
|
657
646
|
letterSpacing,
|
|
658
|
-
// textAlign works for multi-line text within the (possibly auto-width) box
|
|
659
647
|
textAlign: alignment === "justify" ? "justify" : alignment,
|
|
660
648
|
padding: `${paddingTop}px ${paddingRight}px ${paddingBottom}px ${paddingLeft}px`,
|
|
661
649
|
whiteSpace: "pre-wrap",
|
|
662
650
|
wordBreak: "break-word",
|
|
663
|
-
// When not autoWidth, handle vertical alignment via flex
|
|
664
651
|
...!autoWidth && {
|
|
665
652
|
display: "flex",
|
|
666
653
|
flexDirection: "column",
|
|
@@ -668,7 +655,6 @@ function TextElement({ segment, scale = 1 }) {
|
|
|
668
655
|
flex: 1,
|
|
669
656
|
minHeight: 0
|
|
670
657
|
},
|
|
671
|
-
// Text stroke using text-shadow for cross-browser support
|
|
672
658
|
...strokeWidth > 0 && strokeColor && {
|
|
673
659
|
textShadow: `
|
|
674
660
|
-${strokeWidth}px -${strokeWidth}px 0 ${strokeColor},
|
|
@@ -680,7 +666,6 @@ function TextElement({ segment, scale = 1 }) {
|
|
|
680
666
|
-${strokeWidth}px 0 0 ${strokeColor},
|
|
681
667
|
${strokeWidth}px 0 0 ${strokeColor}
|
|
682
668
|
`,
|
|
683
|
-
// Also use WebKit text stroke for better quality where supported
|
|
684
669
|
WebkitTextStroke: `${strokeWidth}px ${strokeColor}`,
|
|
685
670
|
paintOrder: "stroke fill"
|
|
686
671
|
}
|
|
@@ -1242,7 +1227,7 @@ function getSortedSegments(config) {
|
|
|
1242
1227
|
});
|
|
1243
1228
|
}
|
|
1244
1229
|
function elementToTextSegment(elem) {
|
|
1245
|
-
|
|
1230
|
+
const segment = {
|
|
1246
1231
|
id: elem.id,
|
|
1247
1232
|
type: "text",
|
|
1248
1233
|
source: "",
|
|
@@ -1280,6 +1265,18 @@ function elementToTextSegment(elem) {
|
|
|
1280
1265
|
autoWidth: elem.autoWidth,
|
|
1281
1266
|
boxAlign: elem.boxAlign
|
|
1282
1267
|
};
|
|
1268
|
+
console.log("[Composition] ELEMENT:", JSON.stringify({
|
|
1269
|
+
id: elem.id,
|
|
1270
|
+
text: (elem.text ?? "").substring(0, 20),
|
|
1271
|
+
w: elem.width,
|
|
1272
|
+
h: elem.height,
|
|
1273
|
+
font: elem.font,
|
|
1274
|
+
fontSize: elem.fontSize,
|
|
1275
|
+
autoWidth: elem.autoWidth,
|
|
1276
|
+
pL: elem.paddingLeft,
|
|
1277
|
+
pR: elem.paddingRight
|
|
1278
|
+
}));
|
|
1279
|
+
return segment;
|
|
1283
1280
|
}
|
|
1284
1281
|
function elementToImageSegment(elem, source) {
|
|
1285
1282
|
return {
|
package/dist/index.mjs
CHANGED
|
@@ -334,29 +334,28 @@ function calculateAutoWidthAndLines({
|
|
|
334
334
|
white-space: nowrap;
|
|
335
335
|
`;
|
|
336
336
|
document.body.appendChild(measureSpan);
|
|
337
|
+
const computedStyle = window.getComputedStyle(measureSpan);
|
|
338
|
+
const computedFontFamily = computedStyle.fontFamily;
|
|
339
|
+
const requestedFontLoaded = typeof document.fonts !== "undefined" ? document.fonts.check(`${fontWeight} ${fontSize}px ${fontFamily.split(",")[0]}`) : "unknown";
|
|
337
340
|
const measureText = (textToMeasure) => {
|
|
338
341
|
measureSpan.textContent = textToMeasure;
|
|
339
342
|
return measureSpan.getBoundingClientRect().width;
|
|
340
343
|
};
|
|
341
344
|
measureSpan.textContent = "M";
|
|
342
|
-
const
|
|
345
|
+
const mWidth = measureSpan.getBoundingClientRect().width;
|
|
343
346
|
const words = text.split(/(\s+)/);
|
|
344
347
|
const lines = [];
|
|
345
348
|
let currentLine = "";
|
|
346
349
|
for (let i = 0; i < words.length; i++) {
|
|
347
350
|
const word = words[i];
|
|
348
351
|
if (word === "\n" || word === "\r\n") {
|
|
349
|
-
if (currentLine)
|
|
350
|
-
lines.push(currentLine);
|
|
351
|
-
}
|
|
352
|
+
if (currentLine) lines.push(currentLine);
|
|
352
353
|
currentLine = "";
|
|
353
354
|
continue;
|
|
354
355
|
}
|
|
355
356
|
if (!word) continue;
|
|
356
357
|
if (/^\s+$/.test(word)) {
|
|
357
|
-
if (currentLine)
|
|
358
|
-
currentLine += word;
|
|
359
|
-
}
|
|
358
|
+
if (currentLine) currentLine += word;
|
|
360
359
|
continue;
|
|
361
360
|
}
|
|
362
361
|
const testLine = currentLine + word;
|
|
@@ -391,12 +390,8 @@ function calculateAutoWidthAndLines({
|
|
|
391
390
|
currentLine = testLine;
|
|
392
391
|
}
|
|
393
392
|
}
|
|
394
|
-
if (currentLine.trim())
|
|
395
|
-
|
|
396
|
-
}
|
|
397
|
-
if (lines.length === 0) {
|
|
398
|
-
lines.push("");
|
|
399
|
-
}
|
|
393
|
+
if (currentLine.trim()) lines.push(currentLine.trimEnd());
|
|
394
|
+
if (lines.length === 0) lines.push("");
|
|
400
395
|
let widestLineWidth = 0;
|
|
401
396
|
for (const line of lines) {
|
|
402
397
|
const lineWidth = measureText(line);
|
|
@@ -404,18 +399,25 @@ function calculateAutoWidthAndLines({
|
|
|
404
399
|
}
|
|
405
400
|
document.body.removeChild(measureSpan);
|
|
406
401
|
const calculatedWidth = Math.min(widestLineWidth + paddingLeft + paddingRight, maxWidth);
|
|
402
|
+
console.log("[TextElement] WIDTH_CALC:", JSON.stringify({
|
|
403
|
+
text: text.substring(0, 30),
|
|
404
|
+
fontFamily: fontFamily.split(",")[0],
|
|
405
|
+
computedFont: computedFontFamily.split(",")[0],
|
|
406
|
+
fontLoaded: requestedFontLoaded,
|
|
407
|
+
fontSize,
|
|
408
|
+
fontWeight,
|
|
409
|
+
letterSpacing,
|
|
410
|
+
mWidth: Math.round(mWidth * 100) / 100,
|
|
411
|
+
widestLine: Math.round(widestLineWidth * 100) / 100,
|
|
412
|
+
paddingL: paddingLeft,
|
|
413
|
+
paddingR: paddingRight,
|
|
414
|
+
calcWidth: Math.round(calculatedWidth * 100) / 100,
|
|
415
|
+
maxWidth,
|
|
416
|
+
lines: lines.length
|
|
417
|
+
}));
|
|
407
418
|
return { width: calculatedWidth, lines };
|
|
408
419
|
}
|
|
409
420
|
function TextElement({ segment, scale = 1 }) {
|
|
410
|
-
React.useEffect(() => {
|
|
411
|
-
const fontFamily2 = getFontFamily(segment.fontType ?? TEXT_DEFAULTS.fontType);
|
|
412
|
-
console.log("[ugcinc-render/TextElement] Rendering with:", {
|
|
413
|
-
text: segment.text?.substring(0, 50) + (segment.text?.length > 50 ? "..." : ""),
|
|
414
|
-
fontType: segment.fontType ?? TEXT_DEFAULTS.fontType,
|
|
415
|
-
fontFamily: fontFamily2,
|
|
416
|
-
hasEmojis: /[\u{1F300}-\u{1F9FF}]/u.test(segment.text || "")
|
|
417
|
-
});
|
|
418
|
-
}, [segment.text, segment.fontType]);
|
|
419
421
|
const fontType = segment.fontType ?? TEXT_DEFAULTS.fontType;
|
|
420
422
|
const fontSize = (segment.fontSize ?? TEXT_DEFAULTS.fontSize) * scale;
|
|
421
423
|
const fontWeight = segment.fontWeight ?? TEXT_DEFAULTS.fontWeight;
|
|
@@ -537,24 +539,11 @@ function TextElement({ segment, scale = 1 }) {
|
|
|
537
539
|
transformOrigin: "center center",
|
|
538
540
|
display: "flex",
|
|
539
541
|
flexDirection: "column",
|
|
540
|
-
// Vertical alignment within the container
|
|
541
542
|
justifyContent: verticalAlign === "top" ? "flex-start" : verticalAlign === "bottom" ? "flex-end" : "center",
|
|
542
|
-
// Horizontal alignment (boxAlign) - only applies when autoWidth is enabled
|
|
543
543
|
alignItems: autoWidth ? boxAlign === "center" ? "center" : boxAlign === "right" ? "flex-end" : "flex-start" : "stretch"
|
|
544
544
|
}), [x, y, width, height, rotation, verticalAlign, autoWidth, boxAlign]);
|
|
545
545
|
const backgroundBoxStyle = useMemo(() => {
|
|
546
|
-
const baseStyle = autoWidth ? {
|
|
547
|
-
// Use explicit calculated width instead of fit-content
|
|
548
|
-
// This fixes the issue where multi-line text doesn't shrink to widest line
|
|
549
|
-
width: calculatedWidth,
|
|
550
|
-
maxWidth: width
|
|
551
|
-
} : {
|
|
552
|
-
// When not autoWidth, let the text div handle everything
|
|
553
|
-
display: "flex",
|
|
554
|
-
flexDirection: "column",
|
|
555
|
-
flex: 1,
|
|
556
|
-
minHeight: 0
|
|
557
|
-
};
|
|
546
|
+
const baseStyle = autoWidth ? { width: calculatedWidth, maxWidth: width } : { display: "flex", flexDirection: "column", flex: 1, minHeight: 0 };
|
|
558
547
|
if (!backgroundColor) return baseStyle;
|
|
559
548
|
return {
|
|
560
549
|
...baseStyle,
|
|
@@ -569,12 +558,10 @@ function TextElement({ segment, scale = 1 }) {
|
|
|
569
558
|
color,
|
|
570
559
|
lineHeight,
|
|
571
560
|
letterSpacing,
|
|
572
|
-
// textAlign works for multi-line text within the (possibly auto-width) box
|
|
573
561
|
textAlign: alignment === "justify" ? "justify" : alignment,
|
|
574
562
|
padding: `${paddingTop}px ${paddingRight}px ${paddingBottom}px ${paddingLeft}px`,
|
|
575
563
|
whiteSpace: "pre-wrap",
|
|
576
564
|
wordBreak: "break-word",
|
|
577
|
-
// When not autoWidth, handle vertical alignment via flex
|
|
578
565
|
...!autoWidth && {
|
|
579
566
|
display: "flex",
|
|
580
567
|
flexDirection: "column",
|
|
@@ -582,7 +569,6 @@ function TextElement({ segment, scale = 1 }) {
|
|
|
582
569
|
flex: 1,
|
|
583
570
|
minHeight: 0
|
|
584
571
|
},
|
|
585
|
-
// Text stroke using text-shadow for cross-browser support
|
|
586
572
|
...strokeWidth > 0 && strokeColor && {
|
|
587
573
|
textShadow: `
|
|
588
574
|
-${strokeWidth}px -${strokeWidth}px 0 ${strokeColor},
|
|
@@ -594,7 +580,6 @@ function TextElement({ segment, scale = 1 }) {
|
|
|
594
580
|
-${strokeWidth}px 0 0 ${strokeColor},
|
|
595
581
|
${strokeWidth}px 0 0 ${strokeColor}
|
|
596
582
|
`,
|
|
597
|
-
// Also use WebKit text stroke for better quality where supported
|
|
598
583
|
WebkitTextStroke: `${strokeWidth}px ${strokeColor}`,
|
|
599
584
|
paintOrder: "stroke fill"
|
|
600
585
|
}
|
|
@@ -1156,7 +1141,7 @@ function getSortedSegments(config) {
|
|
|
1156
1141
|
});
|
|
1157
1142
|
}
|
|
1158
1143
|
function elementToTextSegment(elem) {
|
|
1159
|
-
|
|
1144
|
+
const segment = {
|
|
1160
1145
|
id: elem.id,
|
|
1161
1146
|
type: "text",
|
|
1162
1147
|
source: "",
|
|
@@ -1194,6 +1179,18 @@ function elementToTextSegment(elem) {
|
|
|
1194
1179
|
autoWidth: elem.autoWidth,
|
|
1195
1180
|
boxAlign: elem.boxAlign
|
|
1196
1181
|
};
|
|
1182
|
+
console.log("[Composition] ELEMENT:", JSON.stringify({
|
|
1183
|
+
id: elem.id,
|
|
1184
|
+
text: (elem.text ?? "").substring(0, 20),
|
|
1185
|
+
w: elem.width,
|
|
1186
|
+
h: elem.height,
|
|
1187
|
+
font: elem.font,
|
|
1188
|
+
fontSize: elem.fontSize,
|
|
1189
|
+
autoWidth: elem.autoWidth,
|
|
1190
|
+
pL: elem.paddingLeft,
|
|
1191
|
+
pR: elem.paddingRight
|
|
1192
|
+
}));
|
|
1193
|
+
return segment;
|
|
1197
1194
|
}
|
|
1198
1195
|
function elementToImageSegment(elem, source) {
|
|
1199
1196
|
return {
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "ugcinc-render",
|
|
3
|
-
"version": "1.5.
|
|
3
|
+
"version": "1.5.19",
|
|
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",
|