ugcinc-render 1.5.9 → 1.5.10

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
@@ -290,10 +290,10 @@ interface ImageEditorElement {
290
290
  paddingRight?: number;
291
291
  paddingBottom?: number;
292
292
  paddingLeft?: number;
293
- multiLinePaddingTop?: number;
294
- multiLinePaddingRight?: number;
295
- multiLinePaddingBottom?: number;
296
- multiLinePaddingLeft?: number;
293
+ multiLineExtraPaddingTop?: number;
294
+ multiLineExtraPaddingRight?: number;
295
+ multiLineExtraPaddingBottom?: number;
296
+ multiLineExtraPaddingLeft?: number;
297
297
  /** When true, box shrinks to fit content (width becomes max width) */
298
298
  autoWidth?: boolean;
299
299
  /** Which side the box anchors to when autoWidth is true */
@@ -622,14 +622,14 @@ interface TextSegment extends VisualSegment {
622
622
  paddingBottom?: number;
623
623
  /** Left padding in pixels (overrides uniform padding) */
624
624
  paddingLeft?: number;
625
- /** Top padding for multi-line text (2+ lines) */
626
- multiLinePaddingTop?: number;
627
- /** Right padding for multi-line text (2+ lines) */
628
- multiLinePaddingRight?: number;
629
- /** Bottom padding for multi-line text (2+ lines) */
630
- multiLinePaddingBottom?: number;
631
- /** Left padding for multi-line text (2+ lines) */
632
- multiLinePaddingLeft?: number;
625
+ /** Extra top padding added when text has 2+ lines */
626
+ multiLineExtraPaddingTop?: number;
627
+ /** Extra right padding added when text has 2+ lines */
628
+ multiLineExtraPaddingRight?: number;
629
+ /** Extra bottom padding added when text has 2+ lines */
630
+ multiLineExtraPaddingBottom?: number;
631
+ /** Extra left padding added when text has 2+ lines */
632
+ multiLineExtraPaddingLeft?: number;
633
633
  /** Font family (default: 'arial') */
634
634
  fontType?: FontType;
635
635
  /** Font size in pixels (default: 40) */
package/dist/index.d.ts CHANGED
@@ -290,10 +290,10 @@ interface ImageEditorElement {
290
290
  paddingRight?: number;
291
291
  paddingBottom?: number;
292
292
  paddingLeft?: number;
293
- multiLinePaddingTop?: number;
294
- multiLinePaddingRight?: number;
295
- multiLinePaddingBottom?: number;
296
- multiLinePaddingLeft?: number;
293
+ multiLineExtraPaddingTop?: number;
294
+ multiLineExtraPaddingRight?: number;
295
+ multiLineExtraPaddingBottom?: number;
296
+ multiLineExtraPaddingLeft?: number;
297
297
  /** When true, box shrinks to fit content (width becomes max width) */
298
298
  autoWidth?: boolean;
299
299
  /** Which side the box anchors to when autoWidth is true */
@@ -622,14 +622,14 @@ interface TextSegment extends VisualSegment {
622
622
  paddingBottom?: number;
623
623
  /** Left padding in pixels (overrides uniform padding) */
624
624
  paddingLeft?: number;
625
- /** Top padding for multi-line text (2+ lines) */
626
- multiLinePaddingTop?: number;
627
- /** Right padding for multi-line text (2+ lines) */
628
- multiLinePaddingRight?: number;
629
- /** Bottom padding for multi-line text (2+ lines) */
630
- multiLinePaddingBottom?: number;
631
- /** Left padding for multi-line text (2+ lines) */
632
- multiLinePaddingLeft?: number;
625
+ /** Extra top padding added when text has 2+ lines */
626
+ multiLineExtraPaddingTop?: number;
627
+ /** Extra right padding added when text has 2+ lines */
628
+ multiLineExtraPaddingRight?: number;
629
+ /** Extra bottom padding added when text has 2+ lines */
630
+ multiLineExtraPaddingBottom?: number;
631
+ /** Extra left padding added when text has 2+ lines */
632
+ multiLineExtraPaddingLeft?: number;
633
633
  /** Font family (default: 'arial') */
634
634
  fontType?: FontType;
635
635
  /** Font size in pixels (default: 40) */
package/dist/index.js CHANGED
@@ -420,11 +420,11 @@ function TextElement({ segment, scale = 1 }) {
420
420
  const basePaddingRight = segment.paddingRight !== void 0 ? segment.paddingRight * scale : uniformPadding;
421
421
  const basePaddingBottom = segment.paddingBottom !== void 0 ? segment.paddingBottom * scale : uniformPadding;
422
422
  const basePaddingLeft = segment.paddingLeft !== void 0 ? segment.paddingLeft * scale : uniformPadding;
423
- const multiLinePaddingTop = segment.multiLinePaddingTop !== void 0 ? segment.multiLinePaddingTop * scale : void 0;
424
- const multiLinePaddingRight = segment.multiLinePaddingRight !== void 0 ? segment.multiLinePaddingRight * scale : void 0;
425
- const multiLinePaddingBottom = segment.multiLinePaddingBottom !== void 0 ? segment.multiLinePaddingBottom * scale : void 0;
426
- const multiLinePaddingLeft = segment.multiLinePaddingLeft !== void 0 ? segment.multiLinePaddingLeft * scale : void 0;
427
- const hasMultiLinePadding = multiLinePaddingTop !== void 0 || multiLinePaddingRight !== void 0 || multiLinePaddingBottom !== void 0 || multiLinePaddingLeft !== void 0;
423
+ const extraPaddingTop = (segment.multiLineExtraPaddingTop ?? 0) * scale;
424
+ const extraPaddingRight = (segment.multiLineExtraPaddingRight ?? 0) * scale;
425
+ const extraPaddingBottom = (segment.multiLineExtraPaddingBottom ?? 0) * scale;
426
+ const extraPaddingLeft = (segment.multiLineExtraPaddingLeft ?? 0) * scale;
427
+ const hasExtraPadding = extraPaddingTop > 0 || extraPaddingRight > 0 || extraPaddingBottom > 0 || extraPaddingLeft > 0;
428
428
  const x = segment.xOffset * scale;
429
429
  const y = segment.yOffset * scale;
430
430
  const width = segment.width * scale;
@@ -436,22 +436,14 @@ function TextElement({ segment, scale = 1 }) {
436
436
  const backgroundOpacity = segment.backgroundOpacity ?? TEXT_DEFAULTS.backgroundOpacity;
437
437
  const backgroundBorderRadius = segment.backgroundBorderRadius;
438
438
  const fontFamily = getFontFamily(fontType);
439
- const { autoWidthResult, finalPaddingTop, finalPaddingRight, finalPaddingBottom, finalPaddingLeft, isMultiLine } = (0, import_react.useMemo)(() => {
440
- let effectivePaddingTop = basePaddingTop;
441
- let effectivePaddingRight = basePaddingRight;
442
- let effectivePaddingBottom = basePaddingBottom;
443
- let effectivePaddingLeft = basePaddingLeft;
444
- if (!autoWidth && !hasMultiLinePadding) {
439
+ const { autoWidthResult, isMultiLine } = (0, import_react.useMemo)(() => {
440
+ if (!autoWidth && !hasExtraPadding) {
445
441
  return {
446
442
  autoWidthResult: null,
447
- finalPaddingTop: effectivePaddingTop,
448
- finalPaddingRight: effectivePaddingRight,
449
- finalPaddingBottom: effectivePaddingBottom,
450
- finalPaddingLeft: effectivePaddingLeft,
451
443
  isMultiLine: false
452
444
  };
453
445
  }
454
- const firstPassResult = calculateAutoWidthAndLines({
446
+ const result = calculateAutoWidthAndLines({
455
447
  text: segment.text,
456
448
  maxWidth: width,
457
449
  paddingLeft: basePaddingLeft,
@@ -462,67 +454,68 @@ function TextElement({ segment, scale = 1 }) {
462
454
  letterSpacing,
463
455
  lineHeight
464
456
  });
465
- const multiLine = firstPassResult.lines.length >= 2;
466
- if (multiLine && hasMultiLinePadding) {
467
- effectivePaddingTop = multiLinePaddingTop ?? basePaddingTop;
468
- effectivePaddingRight = multiLinePaddingRight ?? basePaddingRight;
469
- effectivePaddingBottom = multiLinePaddingBottom ?? basePaddingBottom;
470
- effectivePaddingLeft = multiLinePaddingLeft ?? basePaddingLeft;
471
- if (effectivePaddingLeft !== basePaddingLeft || effectivePaddingRight !== basePaddingRight) {
472
- const secondPassResult = calculateAutoWidthAndLines({
473
- text: segment.text,
474
- maxWidth: width,
475
- paddingLeft: effectivePaddingLeft,
476
- paddingRight: effectivePaddingRight,
477
- fontSize,
478
- fontWeight,
479
- fontFamily,
480
- letterSpacing,
481
- lineHeight
482
- });
483
- return {
484
- autoWidthResult: autoWidth ? secondPassResult : null,
485
- finalPaddingTop: effectivePaddingTop,
486
- finalPaddingRight: effectivePaddingRight,
487
- finalPaddingBottom: effectivePaddingBottom,
488
- finalPaddingLeft: effectivePaddingLeft,
489
- isMultiLine: secondPassResult.lines.length >= 2
490
- };
491
- }
492
- }
493
457
  return {
494
- autoWidthResult: autoWidth ? firstPassResult : null,
495
- finalPaddingTop: effectivePaddingTop,
496
- finalPaddingRight: effectivePaddingRight,
497
- finalPaddingBottom: effectivePaddingBottom,
498
- finalPaddingLeft: effectivePaddingLeft,
499
- isMultiLine: multiLine
458
+ autoWidthResult: autoWidth ? result : null,
459
+ isMultiLine: result.lines.length >= 2
500
460
  };
501
461
  }, [
502
462
  autoWidth,
503
463
  segment.text,
504
464
  width,
505
- basePaddingTop,
506
- basePaddingRight,
507
- basePaddingBottom,
508
465
  basePaddingLeft,
509
- multiLinePaddingTop,
510
- multiLinePaddingRight,
511
- multiLinePaddingBottom,
512
- multiLinePaddingLeft,
513
- hasMultiLinePadding,
466
+ basePaddingRight,
467
+ hasExtraPadding,
514
468
  fontSize,
515
469
  fontWeight,
516
470
  fontFamily,
517
471
  letterSpacing,
518
472
  lineHeight
519
473
  ]);
520
- const calculatedWidth = autoWidthResult?.width ?? width;
521
474
  const calculatedLines = autoWidthResult?.lines ?? [segment.text];
522
- const paddingTop = finalPaddingTop;
523
- const paddingRight = finalPaddingRight;
524
- const paddingBottom = finalPaddingBottom;
525
- const paddingLeft = finalPaddingLeft;
475
+ const paddingTop = basePaddingTop + (isMultiLine ? extraPaddingTop : 0);
476
+ const paddingRight = basePaddingRight + (isMultiLine ? extraPaddingRight : 0);
477
+ const paddingBottom = basePaddingBottom + (isMultiLine ? extraPaddingBottom : 0);
478
+ const paddingLeft = basePaddingLeft + (isMultiLine ? extraPaddingLeft : 0);
479
+ const calculatedWidth = (0, import_react.useMemo)(() => {
480
+ if (!autoWidth) return width;
481
+ if (!isMultiLine || extraPaddingLeft === 0 && extraPaddingRight === 0) {
482
+ return autoWidthResult?.width ?? width;
483
+ }
484
+ if (typeof document === "undefined") return width;
485
+ const measureSpan = document.createElement("span");
486
+ measureSpan.style.cssText = `
487
+ position: absolute;
488
+ visibility: hidden;
489
+ pointer-events: none;
490
+ font-family: ${fontFamily};
491
+ font-size: ${fontSize}px;
492
+ font-weight: ${fontWeight};
493
+ letter-spacing: ${letterSpacing}px;
494
+ white-space: nowrap;
495
+ `;
496
+ document.body.appendChild(measureSpan);
497
+ let widestLineWidth = 0;
498
+ for (const line of calculatedLines) {
499
+ measureSpan.textContent = line;
500
+ widestLineWidth = Math.max(widestLineWidth, measureSpan.getBoundingClientRect().width);
501
+ }
502
+ document.body.removeChild(measureSpan);
503
+ return Math.min(widestLineWidth + paddingLeft + paddingRight, width);
504
+ }, [
505
+ autoWidth,
506
+ autoWidthResult,
507
+ width,
508
+ isMultiLine,
509
+ extraPaddingLeft,
510
+ extraPaddingRight,
511
+ paddingLeft,
512
+ paddingRight,
513
+ calculatedLines,
514
+ fontFamily,
515
+ fontSize,
516
+ fontWeight,
517
+ letterSpacing
518
+ ]);
526
519
  const borderRadiusStyle = (0, import_react.useMemo)(() => {
527
520
  if (!backgroundBorderRadius) return void 0;
528
521
  const radii = getBorderRadii(backgroundBorderRadius);
@@ -1189,10 +1182,10 @@ function elementToTextSegment(elem) {
1189
1182
  paddingRight: elem.paddingRight,
1190
1183
  paddingBottom: elem.paddingBottom,
1191
1184
  paddingLeft: elem.paddingLeft,
1192
- multiLinePaddingTop: elem.multiLinePaddingTop,
1193
- multiLinePaddingRight: elem.multiLinePaddingRight,
1194
- multiLinePaddingBottom: elem.multiLinePaddingBottom,
1195
- multiLinePaddingLeft: elem.multiLinePaddingLeft,
1185
+ multiLineExtraPaddingTop: elem.multiLineExtraPaddingTop,
1186
+ multiLineExtraPaddingRight: elem.multiLineExtraPaddingRight,
1187
+ multiLineExtraPaddingBottom: elem.multiLineExtraPaddingBottom,
1188
+ multiLineExtraPaddingLeft: elem.multiLineExtraPaddingLeft,
1196
1189
  autoWidth: elem.autoWidth,
1197
1190
  boxAlign: elem.boxAlign
1198
1191
  };
package/dist/index.mjs CHANGED
@@ -336,11 +336,11 @@ function TextElement({ segment, scale = 1 }) {
336
336
  const basePaddingRight = segment.paddingRight !== void 0 ? segment.paddingRight * scale : uniformPadding;
337
337
  const basePaddingBottom = segment.paddingBottom !== void 0 ? segment.paddingBottom * scale : uniformPadding;
338
338
  const basePaddingLeft = segment.paddingLeft !== void 0 ? segment.paddingLeft * scale : uniformPadding;
339
- const multiLinePaddingTop = segment.multiLinePaddingTop !== void 0 ? segment.multiLinePaddingTop * scale : void 0;
340
- const multiLinePaddingRight = segment.multiLinePaddingRight !== void 0 ? segment.multiLinePaddingRight * scale : void 0;
341
- const multiLinePaddingBottom = segment.multiLinePaddingBottom !== void 0 ? segment.multiLinePaddingBottom * scale : void 0;
342
- const multiLinePaddingLeft = segment.multiLinePaddingLeft !== void 0 ? segment.multiLinePaddingLeft * scale : void 0;
343
- const hasMultiLinePadding = multiLinePaddingTop !== void 0 || multiLinePaddingRight !== void 0 || multiLinePaddingBottom !== void 0 || multiLinePaddingLeft !== void 0;
339
+ const extraPaddingTop = (segment.multiLineExtraPaddingTop ?? 0) * scale;
340
+ const extraPaddingRight = (segment.multiLineExtraPaddingRight ?? 0) * scale;
341
+ const extraPaddingBottom = (segment.multiLineExtraPaddingBottom ?? 0) * scale;
342
+ const extraPaddingLeft = (segment.multiLineExtraPaddingLeft ?? 0) * scale;
343
+ const hasExtraPadding = extraPaddingTop > 0 || extraPaddingRight > 0 || extraPaddingBottom > 0 || extraPaddingLeft > 0;
344
344
  const x = segment.xOffset * scale;
345
345
  const y = segment.yOffset * scale;
346
346
  const width = segment.width * scale;
@@ -352,22 +352,14 @@ function TextElement({ segment, scale = 1 }) {
352
352
  const backgroundOpacity = segment.backgroundOpacity ?? TEXT_DEFAULTS.backgroundOpacity;
353
353
  const backgroundBorderRadius = segment.backgroundBorderRadius;
354
354
  const fontFamily = getFontFamily(fontType);
355
- const { autoWidthResult, finalPaddingTop, finalPaddingRight, finalPaddingBottom, finalPaddingLeft, isMultiLine } = useMemo(() => {
356
- let effectivePaddingTop = basePaddingTop;
357
- let effectivePaddingRight = basePaddingRight;
358
- let effectivePaddingBottom = basePaddingBottom;
359
- let effectivePaddingLeft = basePaddingLeft;
360
- if (!autoWidth && !hasMultiLinePadding) {
355
+ const { autoWidthResult, isMultiLine } = useMemo(() => {
356
+ if (!autoWidth && !hasExtraPadding) {
361
357
  return {
362
358
  autoWidthResult: null,
363
- finalPaddingTop: effectivePaddingTop,
364
- finalPaddingRight: effectivePaddingRight,
365
- finalPaddingBottom: effectivePaddingBottom,
366
- finalPaddingLeft: effectivePaddingLeft,
367
359
  isMultiLine: false
368
360
  };
369
361
  }
370
- const firstPassResult = calculateAutoWidthAndLines({
362
+ const result = calculateAutoWidthAndLines({
371
363
  text: segment.text,
372
364
  maxWidth: width,
373
365
  paddingLeft: basePaddingLeft,
@@ -378,67 +370,68 @@ function TextElement({ segment, scale = 1 }) {
378
370
  letterSpacing,
379
371
  lineHeight
380
372
  });
381
- const multiLine = firstPassResult.lines.length >= 2;
382
- if (multiLine && hasMultiLinePadding) {
383
- effectivePaddingTop = multiLinePaddingTop ?? basePaddingTop;
384
- effectivePaddingRight = multiLinePaddingRight ?? basePaddingRight;
385
- effectivePaddingBottom = multiLinePaddingBottom ?? basePaddingBottom;
386
- effectivePaddingLeft = multiLinePaddingLeft ?? basePaddingLeft;
387
- if (effectivePaddingLeft !== basePaddingLeft || effectivePaddingRight !== basePaddingRight) {
388
- const secondPassResult = calculateAutoWidthAndLines({
389
- text: segment.text,
390
- maxWidth: width,
391
- paddingLeft: effectivePaddingLeft,
392
- paddingRight: effectivePaddingRight,
393
- fontSize,
394
- fontWeight,
395
- fontFamily,
396
- letterSpacing,
397
- lineHeight
398
- });
399
- return {
400
- autoWidthResult: autoWidth ? secondPassResult : null,
401
- finalPaddingTop: effectivePaddingTop,
402
- finalPaddingRight: effectivePaddingRight,
403
- finalPaddingBottom: effectivePaddingBottom,
404
- finalPaddingLeft: effectivePaddingLeft,
405
- isMultiLine: secondPassResult.lines.length >= 2
406
- };
407
- }
408
- }
409
373
  return {
410
- autoWidthResult: autoWidth ? firstPassResult : null,
411
- finalPaddingTop: effectivePaddingTop,
412
- finalPaddingRight: effectivePaddingRight,
413
- finalPaddingBottom: effectivePaddingBottom,
414
- finalPaddingLeft: effectivePaddingLeft,
415
- isMultiLine: multiLine
374
+ autoWidthResult: autoWidth ? result : null,
375
+ isMultiLine: result.lines.length >= 2
416
376
  };
417
377
  }, [
418
378
  autoWidth,
419
379
  segment.text,
420
380
  width,
421
- basePaddingTop,
422
- basePaddingRight,
423
- basePaddingBottom,
424
381
  basePaddingLeft,
425
- multiLinePaddingTop,
426
- multiLinePaddingRight,
427
- multiLinePaddingBottom,
428
- multiLinePaddingLeft,
429
- hasMultiLinePadding,
382
+ basePaddingRight,
383
+ hasExtraPadding,
430
384
  fontSize,
431
385
  fontWeight,
432
386
  fontFamily,
433
387
  letterSpacing,
434
388
  lineHeight
435
389
  ]);
436
- const calculatedWidth = autoWidthResult?.width ?? width;
437
390
  const calculatedLines = autoWidthResult?.lines ?? [segment.text];
438
- const paddingTop = finalPaddingTop;
439
- const paddingRight = finalPaddingRight;
440
- const paddingBottom = finalPaddingBottom;
441
- const paddingLeft = finalPaddingLeft;
391
+ const paddingTop = basePaddingTop + (isMultiLine ? extraPaddingTop : 0);
392
+ const paddingRight = basePaddingRight + (isMultiLine ? extraPaddingRight : 0);
393
+ const paddingBottom = basePaddingBottom + (isMultiLine ? extraPaddingBottom : 0);
394
+ const paddingLeft = basePaddingLeft + (isMultiLine ? extraPaddingLeft : 0);
395
+ const calculatedWidth = useMemo(() => {
396
+ if (!autoWidth) return width;
397
+ if (!isMultiLine || extraPaddingLeft === 0 && extraPaddingRight === 0) {
398
+ return autoWidthResult?.width ?? width;
399
+ }
400
+ if (typeof document === "undefined") return width;
401
+ const measureSpan = document.createElement("span");
402
+ measureSpan.style.cssText = `
403
+ position: absolute;
404
+ visibility: hidden;
405
+ pointer-events: none;
406
+ font-family: ${fontFamily};
407
+ font-size: ${fontSize}px;
408
+ font-weight: ${fontWeight};
409
+ letter-spacing: ${letterSpacing}px;
410
+ white-space: nowrap;
411
+ `;
412
+ document.body.appendChild(measureSpan);
413
+ let widestLineWidth = 0;
414
+ for (const line of calculatedLines) {
415
+ measureSpan.textContent = line;
416
+ widestLineWidth = Math.max(widestLineWidth, measureSpan.getBoundingClientRect().width);
417
+ }
418
+ document.body.removeChild(measureSpan);
419
+ return Math.min(widestLineWidth + paddingLeft + paddingRight, width);
420
+ }, [
421
+ autoWidth,
422
+ autoWidthResult,
423
+ width,
424
+ isMultiLine,
425
+ extraPaddingLeft,
426
+ extraPaddingRight,
427
+ paddingLeft,
428
+ paddingRight,
429
+ calculatedLines,
430
+ fontFamily,
431
+ fontSize,
432
+ fontWeight,
433
+ letterSpacing
434
+ ]);
442
435
  const borderRadiusStyle = useMemo(() => {
443
436
  if (!backgroundBorderRadius) return void 0;
444
437
  const radii = getBorderRadii(backgroundBorderRadius);
@@ -1105,10 +1098,10 @@ function elementToTextSegment(elem) {
1105
1098
  paddingRight: elem.paddingRight,
1106
1099
  paddingBottom: elem.paddingBottom,
1107
1100
  paddingLeft: elem.paddingLeft,
1108
- multiLinePaddingTop: elem.multiLinePaddingTop,
1109
- multiLinePaddingRight: elem.multiLinePaddingRight,
1110
- multiLinePaddingBottom: elem.multiLinePaddingBottom,
1111
- multiLinePaddingLeft: elem.multiLinePaddingLeft,
1101
+ multiLineExtraPaddingTop: elem.multiLineExtraPaddingTop,
1102
+ multiLineExtraPaddingRight: elem.multiLineExtraPaddingRight,
1103
+ multiLineExtraPaddingBottom: elem.multiLineExtraPaddingBottom,
1104
+ multiLineExtraPaddingLeft: elem.multiLineExtraPaddingLeft,
1112
1105
  autoWidth: elem.autoWidth,
1113
1106
  boxAlign: elem.boxAlign
1114
1107
  };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "ugcinc-render",
3
- "version": "1.5.9",
3
+ "version": "1.5.10",
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",