ugcinc-render 1.5.11 → 1.5.13

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
@@ -1290,6 +1290,34 @@ declare function generateSegmentId(): string;
1290
1290
  */
1291
1291
  declare function generateOverlayId(): string;
1292
1292
 
1293
+ /**
1294
+ * Emoji utilities for rendering Apple-style emojis consistently
1295
+ * across all platforms using CDN-hosted emoji images.
1296
+ */
1297
+ /**
1298
+ * Convert an emoji character to its unified unicode codepoint format
1299
+ * Example: "😀" -> "1f600", "👨‍👩‍👧" -> "1f468-200d-1f469-200d-1f467"
1300
+ */
1301
+ declare function emojiToUnified(emoji: string): string;
1302
+ /**
1303
+ * Get the Apple emoji CDN URL for a given emoji character
1304
+ */
1305
+ declare function getAppleEmojiUrl(emoji: string): string;
1306
+ /**
1307
+ * Check if a string contains any emoji characters
1308
+ */
1309
+ declare function hasEmoji(text: string): boolean;
1310
+ /**
1311
+ * Split text into segments of text and emojis
1312
+ * Returns an array of segments with type 'text' or 'emoji'
1313
+ */
1314
+ interface TextSegmentPart {
1315
+ type: 'text' | 'emoji';
1316
+ content: string;
1317
+ imageUrl?: string;
1318
+ }
1319
+ declare function splitTextAndEmojis(text: string): TextSegmentPart[];
1320
+
1293
1321
  /**
1294
1322
  * Hook exports for ugcinc-render
1295
1323
  *
@@ -1349,4 +1377,4 @@ declare function useResolvedPositions(elements: ImageEditorElement[], textValues
1349
1377
 
1350
1378
  declare const RenderRoot: React.FC;
1351
1379
 
1352
- export { type AudioSegment, type BaseEditorConfig, type BaseSegment, type BorderRadiusConfig, type Channel, type CropAxisConfig, type CropBoundary, type CropBounds, DIMENSION_PRESETS, type DimensionPreset, type DimensionPresetKey, type DynamicCropConfig, type EditorConfig, type EditorSegment, FONT_FAMILIES, FONT_URLS, type FitDimensions, type FitMode, type FontType, type FontWeight, type HorizontalAnchor, type HorizontalSelfAnchor, type Hyphenation, IMAGE_DEFAULTS, ImageEditorComposition, type ImageEditorCompositionProps, type ImageEditorConfig, type ImageEditorElement, type ImageEditorNodeConfig, ImageElement, type ImageElementProps, type ImageSegment, type PictureSegment, type PositionResolutionError, type PositionResolutionResult, type RelativePositionConfigX, type RelativePositionConfigY, RenderRoot, type Segment, type SegmentTimelinePosition, type SegmentType, type StaticSegment, TEXT_DEFAULTS, type TextAlignment, type TextDirection, TextElement, type TextElementProps, type TextOverflow, type TextSegment, type TextWrap, type TimeMode, type TimeValue, VIDEO_DEFAULTS, VISUAL_DEFAULTS, type VerticalAlignment, type VerticalAnchor, type VerticalSelfAnchor, type VideoEditorAudioSegment, type VideoEditorBaseSegment, type VideoEditorChannel, VideoEditorComposition, type VideoEditorCompositionProps, type VideoEditorConfig, type VideoEditorImageSegment, type VideoEditorNodeConfig, type VideoEditorSegment, type VideoEditorTextSegment, type VideoEditorVideoSegment, type VideoEditorVisualSegment, VideoElement, type VideoElementProps, type VideoSegment, type VisualSegment, type VisualSegmentUnion, type WordBreak, applyImageDefaults, applyTextDefaults, applyVideoDefaults, areFontsLoaded, buildFontString, calculateAutoWidthDimensions, calculateCropBounds, calculateEstimatedDuration, calculateFitDimensions, calculateLineWidth, calculateTimelineContentEnd, canSetAsReference, defaultOffset, formatTime, generateOverlayId, generateSegmentId, getBaseSegments, getBorderRadii, getDependentElements, getFontFamily, getOverlays, getReferenceElementX, getReferenceElementY, getSegmentTimelinePosition, hexToRgba, isDynamicCropEnabled, isSegmentVisibleAtTime, parseHexColor, parseTime, preloadFonts, resolveElementPositions, useFontsLoaded, useImageLoader, useImagePreloader, useResolvedPositions, wrapText };
1380
+ export { type AudioSegment, type BaseEditorConfig, type BaseSegment, type BorderRadiusConfig, type Channel, type CropAxisConfig, type CropBoundary, type CropBounds, DIMENSION_PRESETS, type DimensionPreset, type DimensionPresetKey, type DynamicCropConfig, type EditorConfig, type EditorSegment, FONT_FAMILIES, FONT_URLS, type FitDimensions, type FitMode, type FontType, type FontWeight, type HorizontalAnchor, type HorizontalSelfAnchor, type Hyphenation, IMAGE_DEFAULTS, ImageEditorComposition, type ImageEditorCompositionProps, type ImageEditorConfig, type ImageEditorElement, type ImageEditorNodeConfig, ImageElement, type ImageElementProps, type ImageSegment, type PictureSegment, type PositionResolutionError, type PositionResolutionResult, type RelativePositionConfigX, type RelativePositionConfigY, RenderRoot, type Segment, type SegmentTimelinePosition, type SegmentType, type StaticSegment, TEXT_DEFAULTS, type TextAlignment, type TextDirection, TextElement, type TextElementProps, type TextOverflow, type TextSegment, type TextSegmentPart, type TextWrap, type TimeMode, type TimeValue, VIDEO_DEFAULTS, VISUAL_DEFAULTS, type VerticalAlignment, type VerticalAnchor, type VerticalSelfAnchor, type VideoEditorAudioSegment, type VideoEditorBaseSegment, type VideoEditorChannel, VideoEditorComposition, type VideoEditorCompositionProps, type VideoEditorConfig, type VideoEditorImageSegment, type VideoEditorNodeConfig, type VideoEditorSegment, type VideoEditorTextSegment, type VideoEditorVideoSegment, type VideoEditorVisualSegment, VideoElement, type VideoElementProps, type VideoSegment, type VisualSegment, type VisualSegmentUnion, type WordBreak, applyImageDefaults, applyTextDefaults, applyVideoDefaults, areFontsLoaded, buildFontString, calculateAutoWidthDimensions, calculateCropBounds, calculateEstimatedDuration, calculateFitDimensions, calculateLineWidth, calculateTimelineContentEnd, canSetAsReference, defaultOffset, emojiToUnified, formatTime, generateOverlayId, generateSegmentId, getAppleEmojiUrl, getBaseSegments, getBorderRadii, getDependentElements, getFontFamily, getOverlays, getReferenceElementX, getReferenceElementY, getSegmentTimelinePosition, hasEmoji, hexToRgba, isDynamicCropEnabled, isSegmentVisibleAtTime, parseHexColor, parseTime, preloadFonts, resolveElementPositions, splitTextAndEmojis, useFontsLoaded, useImageLoader, useImagePreloader, useResolvedPositions, wrapText };
package/dist/index.d.ts CHANGED
@@ -1290,6 +1290,34 @@ declare function generateSegmentId(): string;
1290
1290
  */
1291
1291
  declare function generateOverlayId(): string;
1292
1292
 
1293
+ /**
1294
+ * Emoji utilities for rendering Apple-style emojis consistently
1295
+ * across all platforms using CDN-hosted emoji images.
1296
+ */
1297
+ /**
1298
+ * Convert an emoji character to its unified unicode codepoint format
1299
+ * Example: "😀" -> "1f600", "👨‍👩‍👧" -> "1f468-200d-1f469-200d-1f467"
1300
+ */
1301
+ declare function emojiToUnified(emoji: string): string;
1302
+ /**
1303
+ * Get the Apple emoji CDN URL for a given emoji character
1304
+ */
1305
+ declare function getAppleEmojiUrl(emoji: string): string;
1306
+ /**
1307
+ * Check if a string contains any emoji characters
1308
+ */
1309
+ declare function hasEmoji(text: string): boolean;
1310
+ /**
1311
+ * Split text into segments of text and emojis
1312
+ * Returns an array of segments with type 'text' or 'emoji'
1313
+ */
1314
+ interface TextSegmentPart {
1315
+ type: 'text' | 'emoji';
1316
+ content: string;
1317
+ imageUrl?: string;
1318
+ }
1319
+ declare function splitTextAndEmojis(text: string): TextSegmentPart[];
1320
+
1293
1321
  /**
1294
1322
  * Hook exports for ugcinc-render
1295
1323
  *
@@ -1349,4 +1377,4 @@ declare function useResolvedPositions(elements: ImageEditorElement[], textValues
1349
1377
 
1350
1378
  declare const RenderRoot: React.FC;
1351
1379
 
1352
- export { type AudioSegment, type BaseEditorConfig, type BaseSegment, type BorderRadiusConfig, type Channel, type CropAxisConfig, type CropBoundary, type CropBounds, DIMENSION_PRESETS, type DimensionPreset, type DimensionPresetKey, type DynamicCropConfig, type EditorConfig, type EditorSegment, FONT_FAMILIES, FONT_URLS, type FitDimensions, type FitMode, type FontType, type FontWeight, type HorizontalAnchor, type HorizontalSelfAnchor, type Hyphenation, IMAGE_DEFAULTS, ImageEditorComposition, type ImageEditorCompositionProps, type ImageEditorConfig, type ImageEditorElement, type ImageEditorNodeConfig, ImageElement, type ImageElementProps, type ImageSegment, type PictureSegment, type PositionResolutionError, type PositionResolutionResult, type RelativePositionConfigX, type RelativePositionConfigY, RenderRoot, type Segment, type SegmentTimelinePosition, type SegmentType, type StaticSegment, TEXT_DEFAULTS, type TextAlignment, type TextDirection, TextElement, type TextElementProps, type TextOverflow, type TextSegment, type TextWrap, type TimeMode, type TimeValue, VIDEO_DEFAULTS, VISUAL_DEFAULTS, type VerticalAlignment, type VerticalAnchor, type VerticalSelfAnchor, type VideoEditorAudioSegment, type VideoEditorBaseSegment, type VideoEditorChannel, VideoEditorComposition, type VideoEditorCompositionProps, type VideoEditorConfig, type VideoEditorImageSegment, type VideoEditorNodeConfig, type VideoEditorSegment, type VideoEditorTextSegment, type VideoEditorVideoSegment, type VideoEditorVisualSegment, VideoElement, type VideoElementProps, type VideoSegment, type VisualSegment, type VisualSegmentUnion, type WordBreak, applyImageDefaults, applyTextDefaults, applyVideoDefaults, areFontsLoaded, buildFontString, calculateAutoWidthDimensions, calculateCropBounds, calculateEstimatedDuration, calculateFitDimensions, calculateLineWidth, calculateTimelineContentEnd, canSetAsReference, defaultOffset, formatTime, generateOverlayId, generateSegmentId, getBaseSegments, getBorderRadii, getDependentElements, getFontFamily, getOverlays, getReferenceElementX, getReferenceElementY, getSegmentTimelinePosition, hexToRgba, isDynamicCropEnabled, isSegmentVisibleAtTime, parseHexColor, parseTime, preloadFonts, resolveElementPositions, useFontsLoaded, useImageLoader, useImagePreloader, useResolvedPositions, wrapText };
1380
+ export { type AudioSegment, type BaseEditorConfig, type BaseSegment, type BorderRadiusConfig, type Channel, type CropAxisConfig, type CropBoundary, type CropBounds, DIMENSION_PRESETS, type DimensionPreset, type DimensionPresetKey, type DynamicCropConfig, type EditorConfig, type EditorSegment, FONT_FAMILIES, FONT_URLS, type FitDimensions, type FitMode, type FontType, type FontWeight, type HorizontalAnchor, type HorizontalSelfAnchor, type Hyphenation, IMAGE_DEFAULTS, ImageEditorComposition, type ImageEditorCompositionProps, type ImageEditorConfig, type ImageEditorElement, type ImageEditorNodeConfig, ImageElement, type ImageElementProps, type ImageSegment, type PictureSegment, type PositionResolutionError, type PositionResolutionResult, type RelativePositionConfigX, type RelativePositionConfigY, RenderRoot, type Segment, type SegmentTimelinePosition, type SegmentType, type StaticSegment, TEXT_DEFAULTS, type TextAlignment, type TextDirection, TextElement, type TextElementProps, type TextOverflow, type TextSegment, type TextSegmentPart, type TextWrap, type TimeMode, type TimeValue, VIDEO_DEFAULTS, VISUAL_DEFAULTS, type VerticalAlignment, type VerticalAnchor, type VerticalSelfAnchor, type VideoEditorAudioSegment, type VideoEditorBaseSegment, type VideoEditorChannel, VideoEditorComposition, type VideoEditorCompositionProps, type VideoEditorConfig, type VideoEditorImageSegment, type VideoEditorNodeConfig, type VideoEditorSegment, type VideoEditorTextSegment, type VideoEditorVideoSegment, type VideoEditorVisualSegment, VideoElement, type VideoElementProps, type VideoSegment, type VisualSegment, type VisualSegmentUnion, type WordBreak, applyImageDefaults, applyTextDefaults, applyVideoDefaults, areFontsLoaded, buildFontString, calculateAutoWidthDimensions, calculateCropBounds, calculateEstimatedDuration, calculateFitDimensions, calculateLineWidth, calculateTimelineContentEnd, canSetAsReference, defaultOffset, emojiToUnified, formatTime, generateOverlayId, generateSegmentId, getAppleEmojiUrl, getBaseSegments, getBorderRadii, getDependentElements, getFontFamily, getOverlays, getReferenceElementX, getReferenceElementY, getSegmentTimelinePosition, hasEmoji, hexToRgba, isDynamicCropEnabled, isSegmentVisibleAtTime, parseHexColor, parseTime, preloadFonts, resolveElementPositions, splitTextAndEmojis, useFontsLoaded, useImageLoader, useImagePreloader, useResolvedPositions, wrapText };
package/dist/index.js CHANGED
@@ -56,9 +56,11 @@ __export(index_exports, {
56
56
  calculateTimelineContentEnd: () => calculateTimelineContentEnd,
57
57
  canSetAsReference: () => canSetAsReference,
58
58
  defaultOffset: () => defaultOffset,
59
+ emojiToUnified: () => emojiToUnified,
59
60
  formatTime: () => formatTime,
60
61
  generateOverlayId: () => generateOverlayId,
61
62
  generateSegmentId: () => generateSegmentId,
63
+ getAppleEmojiUrl: () => getAppleEmojiUrl,
62
64
  getBaseSegments: () => getBaseSegments,
63
65
  getBorderRadii: () => getBorderRadii,
64
66
  getDependentElements: () => getDependentElements,
@@ -67,6 +69,7 @@ __export(index_exports, {
67
69
  getReferenceElementX: () => getReferenceElementX,
68
70
  getReferenceElementY: () => getReferenceElementY,
69
71
  getSegmentTimelinePosition: () => getSegmentTimelinePosition,
72
+ hasEmoji: () => hasEmoji,
70
73
  hexToRgba: () => hexToRgba,
71
74
  isDynamicCropEnabled: () => isDynamicCropEnabled,
72
75
  isSegmentVisibleAtTime: () => isSegmentVisibleAtTime,
@@ -74,6 +77,7 @@ __export(index_exports, {
74
77
  parseTime: () => parseTime,
75
78
  preloadFonts: () => preloadFonts,
76
79
  resolveElementPositions: () => resolveElementPositions,
80
+ splitTextAndEmojis: () => splitTextAndEmojis,
77
81
  useFontsLoaded: () => useFontsLoaded,
78
82
  useImageLoader: () => useImageLoader,
79
83
  useImagePreloader: () => useImagePreloader,
@@ -302,6 +306,54 @@ function hexToRgba(hex, opacity = 100) {
302
306
  return `rgba(${r}, ${g}, ${b}, ${opacity / 100})`;
303
307
  }
304
308
 
309
+ // src/utils/emoji.ts
310
+ var APPLE_EMOJI_CDN_BASE = "https://cdn.jsdelivr.net/npm/emoji-datasource-apple/img/apple/64/";
311
+ function emojiToUnified(emoji) {
312
+ const codePoints = [];
313
+ for (const codePoint of emoji) {
314
+ const hex = codePoint.codePointAt(0)?.toString(16);
315
+ if (hex) {
316
+ codePoints.push(hex);
317
+ }
318
+ }
319
+ return codePoints.join("-");
320
+ }
321
+ function getAppleEmojiUrl(emoji) {
322
+ const unified = emojiToUnified(emoji);
323
+ return `${APPLE_EMOJI_CDN_BASE}${unified}.png`;
324
+ }
325
+ var EMOJI_REGEX = /(?:\p{Emoji_Presentation}|\p{Emoji}\uFE0F)(?:\p{Emoji_Modifier}|\uFE0F|\u200D(?:\p{Emoji_Presentation}|\p{Emoji}\uFE0F)(?:\p{Emoji_Modifier})?)*|\p{Regional_Indicator}{2}/gu;
326
+ function hasEmoji(text) {
327
+ return EMOJI_REGEX.test(text);
328
+ }
329
+ function splitTextAndEmojis(text) {
330
+ const segments = [];
331
+ let lastIndex = 0;
332
+ EMOJI_REGEX.lastIndex = 0;
333
+ let match;
334
+ while ((match = EMOJI_REGEX.exec(text)) !== null) {
335
+ if (match.index > lastIndex) {
336
+ segments.push({
337
+ type: "text",
338
+ content: text.slice(lastIndex, match.index)
339
+ });
340
+ }
341
+ segments.push({
342
+ type: "emoji",
343
+ content: match[0],
344
+ imageUrl: getAppleEmojiUrl(match[0])
345
+ });
346
+ lastIndex = match.index + match[0].length;
347
+ }
348
+ if (lastIndex < text.length) {
349
+ segments.push({
350
+ type: "text",
351
+ content: text.slice(lastIndex)
352
+ });
353
+ }
354
+ return segments;
355
+ }
356
+
305
357
  // src/components/TextElement.tsx
306
358
  var import_jsx_runtime = require("react/jsx-runtime");
307
359
  function calculateAutoWidthAndLines({
@@ -604,9 +656,36 @@ function TextElement({ segment, scale = 1 }) {
604
656
  autoWidth,
605
657
  verticalAlign
606
658
  ]);
659
+ const renderTextWithEmojis = (text) => {
660
+ if (!hasEmoji(text)) {
661
+ return text;
662
+ }
663
+ const segments = splitTextAndEmojis(text);
664
+ return segments.map((segment2, i) => {
665
+ if (segment2.type === "emoji" && segment2.imageUrl) {
666
+ return /* @__PURE__ */ (0, import_jsx_runtime.jsx)(
667
+ "img",
668
+ {
669
+ src: segment2.imageUrl,
670
+ alt: segment2.content,
671
+ style: {
672
+ height: "1.2em",
673
+ width: "1.2em",
674
+ verticalAlign: "-0.25em",
675
+ display: "inline-block",
676
+ margin: "0 0.05em"
677
+ },
678
+ draggable: false
679
+ },
680
+ i
681
+ );
682
+ }
683
+ return /* @__PURE__ */ (0, import_jsx_runtime.jsx)(import_react.default.Fragment, { children: segment2.content }, i);
684
+ });
685
+ };
607
686
  if (autoWidth) {
608
687
  const textContent = calculatedLines.map((line, index) => /* @__PURE__ */ (0, import_jsx_runtime.jsxs)(import_react.default.Fragment, { children: [
609
- line,
688
+ renderTextWithEmojis(line),
610
689
  index < calculatedLines.length - 1 && /* @__PURE__ */ (0, import_jsx_runtime.jsx)("br", {})
611
690
  ] }, index));
612
691
  if (backgroundColor) {
@@ -625,7 +704,7 @@ function TextElement({ segment, scale = 1 }) {
625
704
  }
626
705
  return /* @__PURE__ */ (0, import_jsx_runtime.jsx)("div", { style: positioningContainerStyle, children: /* @__PURE__ */ (0, import_jsx_runtime.jsx)("div", { style: { width: calculatedWidth, maxWidth: width }, children: /* @__PURE__ */ (0, import_jsx_runtime.jsx)("div", { style: textStyle, children: textContent }) }) });
627
706
  }
628
- return /* @__PURE__ */ (0, import_jsx_runtime.jsx)("div", { style: positioningContainerStyle, children: /* @__PURE__ */ (0, import_jsx_runtime.jsx)("div", { style: backgroundBoxStyle, children: /* @__PURE__ */ (0, import_jsx_runtime.jsx)("div", { style: textStyle, children: segment.text }) }) });
707
+ return /* @__PURE__ */ (0, import_jsx_runtime.jsx)("div", { style: positioningContainerStyle, children: /* @__PURE__ */ (0, import_jsx_runtime.jsx)("div", { style: backgroundBoxStyle, children: /* @__PURE__ */ (0, import_jsx_runtime.jsx)("div", { style: textStyle, children: renderTextWithEmojis(segment.text) }) }) });
629
708
  }
630
709
 
631
710
  // src/components/ImageElement.tsx
@@ -1945,9 +2024,11 @@ var RenderRoot = () => {
1945
2024
  calculateTimelineContentEnd,
1946
2025
  canSetAsReference,
1947
2026
  defaultOffset,
2027
+ emojiToUnified,
1948
2028
  formatTime,
1949
2029
  generateOverlayId,
1950
2030
  generateSegmentId,
2031
+ getAppleEmojiUrl,
1951
2032
  getBaseSegments,
1952
2033
  getBorderRadii,
1953
2034
  getDependentElements,
@@ -1956,6 +2037,7 @@ var RenderRoot = () => {
1956
2037
  getReferenceElementX,
1957
2038
  getReferenceElementY,
1958
2039
  getSegmentTimelinePosition,
2040
+ hasEmoji,
1959
2041
  hexToRgba,
1960
2042
  isDynamicCropEnabled,
1961
2043
  isSegmentVisibleAtTime,
@@ -1963,6 +2045,7 @@ var RenderRoot = () => {
1963
2045
  parseTime,
1964
2046
  preloadFonts,
1965
2047
  resolveElementPositions,
2048
+ splitTextAndEmojis,
1966
2049
  useFontsLoaded,
1967
2050
  useImageLoader,
1968
2051
  useImagePreloader,
package/dist/index.mjs CHANGED
@@ -218,6 +218,54 @@ function hexToRgba(hex, opacity = 100) {
218
218
  return `rgba(${r}, ${g}, ${b}, ${opacity / 100})`;
219
219
  }
220
220
 
221
+ // src/utils/emoji.ts
222
+ var APPLE_EMOJI_CDN_BASE = "https://cdn.jsdelivr.net/npm/emoji-datasource-apple/img/apple/64/";
223
+ function emojiToUnified(emoji) {
224
+ const codePoints = [];
225
+ for (const codePoint of emoji) {
226
+ const hex = codePoint.codePointAt(0)?.toString(16);
227
+ if (hex) {
228
+ codePoints.push(hex);
229
+ }
230
+ }
231
+ return codePoints.join("-");
232
+ }
233
+ function getAppleEmojiUrl(emoji) {
234
+ const unified = emojiToUnified(emoji);
235
+ return `${APPLE_EMOJI_CDN_BASE}${unified}.png`;
236
+ }
237
+ var EMOJI_REGEX = /(?:\p{Emoji_Presentation}|\p{Emoji}\uFE0F)(?:\p{Emoji_Modifier}|\uFE0F|\u200D(?:\p{Emoji_Presentation}|\p{Emoji}\uFE0F)(?:\p{Emoji_Modifier})?)*|\p{Regional_Indicator}{2}/gu;
238
+ function hasEmoji(text) {
239
+ return EMOJI_REGEX.test(text);
240
+ }
241
+ function splitTextAndEmojis(text) {
242
+ const segments = [];
243
+ let lastIndex = 0;
244
+ EMOJI_REGEX.lastIndex = 0;
245
+ let match;
246
+ while ((match = EMOJI_REGEX.exec(text)) !== null) {
247
+ if (match.index > lastIndex) {
248
+ segments.push({
249
+ type: "text",
250
+ content: text.slice(lastIndex, match.index)
251
+ });
252
+ }
253
+ segments.push({
254
+ type: "emoji",
255
+ content: match[0],
256
+ imageUrl: getAppleEmojiUrl(match[0])
257
+ });
258
+ lastIndex = match.index + match[0].length;
259
+ }
260
+ if (lastIndex < text.length) {
261
+ segments.push({
262
+ type: "text",
263
+ content: text.slice(lastIndex)
264
+ });
265
+ }
266
+ return segments;
267
+ }
268
+
221
269
  // src/components/TextElement.tsx
222
270
  import { jsx, jsxs } from "react/jsx-runtime";
223
271
  function calculateAutoWidthAndLines({
@@ -520,9 +568,36 @@ function TextElement({ segment, scale = 1 }) {
520
568
  autoWidth,
521
569
  verticalAlign
522
570
  ]);
571
+ const renderTextWithEmojis = (text) => {
572
+ if (!hasEmoji(text)) {
573
+ return text;
574
+ }
575
+ const segments = splitTextAndEmojis(text);
576
+ return segments.map((segment2, i) => {
577
+ if (segment2.type === "emoji" && segment2.imageUrl) {
578
+ return /* @__PURE__ */ jsx(
579
+ "img",
580
+ {
581
+ src: segment2.imageUrl,
582
+ alt: segment2.content,
583
+ style: {
584
+ height: "1.2em",
585
+ width: "1.2em",
586
+ verticalAlign: "-0.25em",
587
+ display: "inline-block",
588
+ margin: "0 0.05em"
589
+ },
590
+ draggable: false
591
+ },
592
+ i
593
+ );
594
+ }
595
+ return /* @__PURE__ */ jsx(React.Fragment, { children: segment2.content }, i);
596
+ });
597
+ };
523
598
  if (autoWidth) {
524
599
  const textContent = calculatedLines.map((line, index) => /* @__PURE__ */ jsxs(React.Fragment, { children: [
525
- line,
600
+ renderTextWithEmojis(line),
526
601
  index < calculatedLines.length - 1 && /* @__PURE__ */ jsx("br", {})
527
602
  ] }, index));
528
603
  if (backgroundColor) {
@@ -541,7 +616,7 @@ function TextElement({ segment, scale = 1 }) {
541
616
  }
542
617
  return /* @__PURE__ */ jsx("div", { style: positioningContainerStyle, children: /* @__PURE__ */ jsx("div", { style: { width: calculatedWidth, maxWidth: width }, children: /* @__PURE__ */ jsx("div", { style: textStyle, children: textContent }) }) });
543
618
  }
544
- return /* @__PURE__ */ jsx("div", { style: positioningContainerStyle, children: /* @__PURE__ */ jsx("div", { style: backgroundBoxStyle, children: /* @__PURE__ */ jsx("div", { style: textStyle, children: segment.text }) }) });
619
+ return /* @__PURE__ */ jsx("div", { style: positioningContainerStyle, children: /* @__PURE__ */ jsx("div", { style: backgroundBoxStyle, children: /* @__PURE__ */ jsx("div", { style: textStyle, children: renderTextWithEmojis(segment.text) }) }) });
545
620
  }
546
621
 
547
622
  // src/components/ImageElement.tsx
@@ -1860,9 +1935,11 @@ export {
1860
1935
  calculateTimelineContentEnd,
1861
1936
  canSetAsReference,
1862
1937
  defaultOffset,
1938
+ emojiToUnified,
1863
1939
  formatTime,
1864
1940
  generateOverlayId,
1865
1941
  generateSegmentId,
1942
+ getAppleEmojiUrl,
1866
1943
  getBaseSegments,
1867
1944
  getBorderRadii,
1868
1945
  getDependentElements,
@@ -1871,6 +1948,7 @@ export {
1871
1948
  getReferenceElementX,
1872
1949
  getReferenceElementY,
1873
1950
  getSegmentTimelinePosition,
1951
+ hasEmoji,
1874
1952
  hexToRgba,
1875
1953
  isDynamicCropEnabled,
1876
1954
  isSegmentVisibleAtTime,
@@ -1878,6 +1956,7 @@ export {
1878
1956
  parseTime,
1879
1957
  preloadFonts,
1880
1958
  resolveElementPositions,
1959
+ splitTextAndEmojis,
1881
1960
  useFontsLoaded,
1882
1961
  useImageLoader,
1883
1962
  useImagePreloader,
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "ugcinc-render",
3
- "version": "1.5.11",
3
+ "version": "1.5.13",
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",