ugcinc-render 1.5.8 → 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,6 +290,10 @@ interface ImageEditorElement {
290
290
  paddingRight?: number;
291
291
  paddingBottom?: number;
292
292
  paddingLeft?: number;
293
+ multiLineExtraPaddingTop?: number;
294
+ multiLineExtraPaddingRight?: number;
295
+ multiLineExtraPaddingBottom?: number;
296
+ multiLineExtraPaddingLeft?: number;
293
297
  /** When true, box shrinks to fit content (width becomes max width) */
294
298
  autoWidth?: boolean;
295
299
  /** Which side the box anchors to when autoWidth is true */
@@ -618,6 +622,14 @@ interface TextSegment extends VisualSegment {
618
622
  paddingBottom?: number;
619
623
  /** Left padding in pixels (overrides uniform padding) */
620
624
  paddingLeft?: 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;
621
633
  /** Font family (default: 'arial') */
622
634
  fontType?: FontType;
623
635
  /** Font size in pixels (default: 40) */
package/dist/index.d.ts CHANGED
@@ -290,6 +290,10 @@ interface ImageEditorElement {
290
290
  paddingRight?: number;
291
291
  paddingBottom?: number;
292
292
  paddingLeft?: number;
293
+ multiLineExtraPaddingTop?: number;
294
+ multiLineExtraPaddingRight?: number;
295
+ multiLineExtraPaddingBottom?: number;
296
+ multiLineExtraPaddingLeft?: number;
293
297
  /** When true, box shrinks to fit content (width becomes max width) */
294
298
  autoWidth?: boolean;
295
299
  /** Which side the box anchors to when autoWidth is true */
@@ -618,6 +622,14 @@ interface TextSegment extends VisualSegment {
618
622
  paddingBottom?: number;
619
623
  /** Left padding in pixels (overrides uniform padding) */
620
624
  paddingLeft?: 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;
621
633
  /** Font family (default: 'arial') */
622
634
  fontType?: FontType;
623
635
  /** Font size in pixels (default: 40) */
package/dist/index.js CHANGED
@@ -416,10 +416,15 @@ function TextElement({ segment, scale = 1 }) {
416
416
  const strokeColor = segment.strokeColor;
417
417
  const strokeWidth = (segment.strokeWidth ?? TEXT_DEFAULTS.strokeWidth) * scale;
418
418
  const uniformPadding = (segment.padding ?? TEXT_DEFAULTS.padding) * scale;
419
- const paddingTop = segment.paddingTop !== void 0 ? segment.paddingTop * scale : uniformPadding;
420
- const paddingRight = segment.paddingRight !== void 0 ? segment.paddingRight * scale : uniformPadding;
421
- const paddingBottom = segment.paddingBottom !== void 0 ? segment.paddingBottom * scale : uniformPadding;
422
- const paddingLeft = segment.paddingLeft !== void 0 ? segment.paddingLeft * scale : uniformPadding;
419
+ const basePaddingTop = segment.paddingTop !== void 0 ? segment.paddingTop * scale : uniformPadding;
420
+ const basePaddingRight = segment.paddingRight !== void 0 ? segment.paddingRight * scale : uniformPadding;
421
+ const basePaddingBottom = segment.paddingBottom !== void 0 ? segment.paddingBottom * scale : uniformPadding;
422
+ const basePaddingLeft = segment.paddingLeft !== void 0 ? segment.paddingLeft * scale : uniformPadding;
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;
423
428
  const x = segment.xOffset * scale;
424
429
  const y = segment.yOffset * scale;
425
430
  const width = segment.width * scale;
@@ -431,22 +436,86 @@ function TextElement({ segment, scale = 1 }) {
431
436
  const backgroundOpacity = segment.backgroundOpacity ?? TEXT_DEFAULTS.backgroundOpacity;
432
437
  const backgroundBorderRadius = segment.backgroundBorderRadius;
433
438
  const fontFamily = getFontFamily(fontType);
434
- const autoWidthResult = (0, import_react.useMemo)(() => {
435
- if (!autoWidth) return null;
436
- return calculateAutoWidthAndLines({
439
+ const { autoWidthResult, isMultiLine } = (0, import_react.useMemo)(() => {
440
+ if (!autoWidth && !hasExtraPadding) {
441
+ return {
442
+ autoWidthResult: null,
443
+ isMultiLine: false
444
+ };
445
+ }
446
+ const result = calculateAutoWidthAndLines({
437
447
  text: segment.text,
438
448
  maxWidth: width,
439
- paddingLeft,
440
- paddingRight,
449
+ paddingLeft: basePaddingLeft,
450
+ paddingRight: basePaddingRight,
441
451
  fontSize,
442
452
  fontWeight,
443
453
  fontFamily,
444
454
  letterSpacing,
445
455
  lineHeight
446
456
  });
447
- }, [autoWidth, segment.text, width, paddingLeft, paddingRight, fontSize, fontWeight, fontFamily, letterSpacing, lineHeight]);
448
- const calculatedWidth = autoWidthResult?.width ?? width;
457
+ return {
458
+ autoWidthResult: autoWidth ? result : null,
459
+ isMultiLine: result.lines.length >= 2
460
+ };
461
+ }, [
462
+ autoWidth,
463
+ segment.text,
464
+ width,
465
+ basePaddingLeft,
466
+ basePaddingRight,
467
+ hasExtraPadding,
468
+ fontSize,
469
+ fontWeight,
470
+ fontFamily,
471
+ letterSpacing,
472
+ lineHeight
473
+ ]);
449
474
  const calculatedLines = autoWidthResult?.lines ?? [segment.text];
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
+ ]);
450
519
  const borderRadiusStyle = (0, import_react.useMemo)(() => {
451
520
  if (!backgroundBorderRadius) return void 0;
452
521
  const radii = getBorderRadii(backgroundBorderRadius);
@@ -1113,6 +1182,10 @@ function elementToTextSegment(elem) {
1113
1182
  paddingRight: elem.paddingRight,
1114
1183
  paddingBottom: elem.paddingBottom,
1115
1184
  paddingLeft: elem.paddingLeft,
1185
+ multiLineExtraPaddingTop: elem.multiLineExtraPaddingTop,
1186
+ multiLineExtraPaddingRight: elem.multiLineExtraPaddingRight,
1187
+ multiLineExtraPaddingBottom: elem.multiLineExtraPaddingBottom,
1188
+ multiLineExtraPaddingLeft: elem.multiLineExtraPaddingLeft,
1116
1189
  autoWidth: elem.autoWidth,
1117
1190
  boxAlign: elem.boxAlign
1118
1191
  };
package/dist/index.mjs CHANGED
@@ -332,10 +332,15 @@ function TextElement({ segment, scale = 1 }) {
332
332
  const strokeColor = segment.strokeColor;
333
333
  const strokeWidth = (segment.strokeWidth ?? TEXT_DEFAULTS.strokeWidth) * scale;
334
334
  const uniformPadding = (segment.padding ?? TEXT_DEFAULTS.padding) * scale;
335
- const paddingTop = segment.paddingTop !== void 0 ? segment.paddingTop * scale : uniformPadding;
336
- const paddingRight = segment.paddingRight !== void 0 ? segment.paddingRight * scale : uniformPadding;
337
- const paddingBottom = segment.paddingBottom !== void 0 ? segment.paddingBottom * scale : uniformPadding;
338
- const paddingLeft = segment.paddingLeft !== void 0 ? segment.paddingLeft * scale : uniformPadding;
335
+ const basePaddingTop = segment.paddingTop !== void 0 ? segment.paddingTop * scale : uniformPadding;
336
+ const basePaddingRight = segment.paddingRight !== void 0 ? segment.paddingRight * scale : uniformPadding;
337
+ const basePaddingBottom = segment.paddingBottom !== void 0 ? segment.paddingBottom * scale : uniformPadding;
338
+ const basePaddingLeft = segment.paddingLeft !== void 0 ? segment.paddingLeft * scale : uniformPadding;
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;
339
344
  const x = segment.xOffset * scale;
340
345
  const y = segment.yOffset * scale;
341
346
  const width = segment.width * scale;
@@ -347,22 +352,86 @@ function TextElement({ segment, scale = 1 }) {
347
352
  const backgroundOpacity = segment.backgroundOpacity ?? TEXT_DEFAULTS.backgroundOpacity;
348
353
  const backgroundBorderRadius = segment.backgroundBorderRadius;
349
354
  const fontFamily = getFontFamily(fontType);
350
- const autoWidthResult = useMemo(() => {
351
- if (!autoWidth) return null;
352
- return calculateAutoWidthAndLines({
355
+ const { autoWidthResult, isMultiLine } = useMemo(() => {
356
+ if (!autoWidth && !hasExtraPadding) {
357
+ return {
358
+ autoWidthResult: null,
359
+ isMultiLine: false
360
+ };
361
+ }
362
+ const result = calculateAutoWidthAndLines({
353
363
  text: segment.text,
354
364
  maxWidth: width,
355
- paddingLeft,
356
- paddingRight,
365
+ paddingLeft: basePaddingLeft,
366
+ paddingRight: basePaddingRight,
357
367
  fontSize,
358
368
  fontWeight,
359
369
  fontFamily,
360
370
  letterSpacing,
361
371
  lineHeight
362
372
  });
363
- }, [autoWidth, segment.text, width, paddingLeft, paddingRight, fontSize, fontWeight, fontFamily, letterSpacing, lineHeight]);
364
- const calculatedWidth = autoWidthResult?.width ?? width;
373
+ return {
374
+ autoWidthResult: autoWidth ? result : null,
375
+ isMultiLine: result.lines.length >= 2
376
+ };
377
+ }, [
378
+ autoWidth,
379
+ segment.text,
380
+ width,
381
+ basePaddingLeft,
382
+ basePaddingRight,
383
+ hasExtraPadding,
384
+ fontSize,
385
+ fontWeight,
386
+ fontFamily,
387
+ letterSpacing,
388
+ lineHeight
389
+ ]);
365
390
  const calculatedLines = autoWidthResult?.lines ?? [segment.text];
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
+ ]);
366
435
  const borderRadiusStyle = useMemo(() => {
367
436
  if (!backgroundBorderRadius) return void 0;
368
437
  const radii = getBorderRadii(backgroundBorderRadius);
@@ -1029,6 +1098,10 @@ function elementToTextSegment(elem) {
1029
1098
  paddingRight: elem.paddingRight,
1030
1099
  paddingBottom: elem.paddingBottom,
1031
1100
  paddingLeft: elem.paddingLeft,
1101
+ multiLineExtraPaddingTop: elem.multiLineExtraPaddingTop,
1102
+ multiLineExtraPaddingRight: elem.multiLineExtraPaddingRight,
1103
+ multiLineExtraPaddingBottom: elem.multiLineExtraPaddingBottom,
1104
+ multiLineExtraPaddingLeft: elem.multiLineExtraPaddingLeft,
1032
1105
  autoWidth: elem.autoWidth,
1033
1106
  boxAlign: elem.boxAlign
1034
1107
  };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "ugcinc-render",
3
- "version": "1.5.8",
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",