ugcinc-render 1.5.28 → 1.5.30

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 CHANGED
@@ -388,6 +388,51 @@ function hexToRgba(hex, opacity = 100) {
388
388
  return `rgba(${r}, ${g}, ${b}, ${opacity / 100})`;
389
389
  }
390
390
 
391
+ // src/utils/emoji.ts
392
+ var APPLE_EMOJI_CDN_BASE = "https://cdn.jsdelivr.net/npm/emoji-datasource-apple/img/apple/64/";
393
+ function emojiToUnified(emoji) {
394
+ const codePoints = [];
395
+ for (const codePoint of emoji) {
396
+ const hex = codePoint.codePointAt(0)?.toString(16);
397
+ if (hex) {
398
+ codePoints.push(hex);
399
+ }
400
+ }
401
+ return codePoints.join("-");
402
+ }
403
+ function getAppleEmojiUrl(emoji) {
404
+ const unified = emojiToUnified(emoji);
405
+ return `${APPLE_EMOJI_CDN_BASE}${unified}.png`;
406
+ }
407
+ 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;
408
+ function splitTextAndEmojis(text) {
409
+ const segments = [];
410
+ let lastIndex = 0;
411
+ EMOJI_REGEX.lastIndex = 0;
412
+ let match;
413
+ while ((match = EMOJI_REGEX.exec(text)) !== null) {
414
+ if (match.index > lastIndex) {
415
+ segments.push({
416
+ type: "text",
417
+ content: text.slice(lastIndex, match.index)
418
+ });
419
+ }
420
+ segments.push({
421
+ type: "emoji",
422
+ content: match[0],
423
+ imageUrl: getAppleEmojiUrl(match[0])
424
+ });
425
+ lastIndex = match.index + match[0].length;
426
+ }
427
+ if (lastIndex < text.length) {
428
+ segments.push({
429
+ type: "text",
430
+ content: text.slice(lastIndex)
431
+ });
432
+ }
433
+ return segments;
434
+ }
435
+
391
436
  // src/components/TextElement.tsx
392
437
  var import_jsx_runtime = require("react/jsx-runtime");
393
438
  function calculateAutoWidthAndLines({
@@ -686,9 +731,37 @@ function TextElement({ segment, scale = 1 }) {
686
731
  autoWidth,
687
732
  verticalAlign
688
733
  ]);
734
+ const hasStroke = strokeWidth > 0 && strokeColor;
735
+ const renderTextWithEmojis = (text) => {
736
+ if (!hasStroke) {
737
+ return text;
738
+ }
739
+ const segments = splitTextAndEmojis(text);
740
+ if (segments.every((s) => s.type === "text")) {
741
+ return text;
742
+ }
743
+ return segments.map((segment2, i) => {
744
+ if (segment2.type === "text") {
745
+ return /* @__PURE__ */ (0, import_jsx_runtime.jsx)(import_react.default.Fragment, { children: segment2.content }, i);
746
+ }
747
+ return /* @__PURE__ */ (0, import_jsx_runtime.jsx)(
748
+ "span",
749
+ {
750
+ style: {
751
+ textShadow: "none",
752
+ WebkitTextStroke: "initial",
753
+ // Ensure emoji renders properly
754
+ display: "inline"
755
+ },
756
+ children: segment2.content
757
+ },
758
+ i
759
+ );
760
+ });
761
+ };
689
762
  if (autoWidth) {
690
763
  const textContent = calculatedLines.map((line, index) => /* @__PURE__ */ (0, import_jsx_runtime.jsxs)(import_react.default.Fragment, { children: [
691
- line,
764
+ renderTextWithEmojis(line),
692
765
  index < calculatedLines.length - 1 && /* @__PURE__ */ (0, import_jsx_runtime.jsx)("br", {})
693
766
  ] }, index));
694
767
  if (backgroundColor) {
@@ -707,7 +780,7 @@ function TextElement({ segment, scale = 1 }) {
707
780
  }
708
781
  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 }) }) });
709
782
  }
710
- 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 }) }) });
783
+ 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) }) }) });
711
784
  }
712
785
 
713
786
  // src/components/ImageElement.tsx
@@ -1675,7 +1748,7 @@ function VideoElement({
1675
1748
  {
1676
1749
  src,
1677
1750
  style: videoStyle,
1678
- startFrom: startFromFrames,
1751
+ trimBefore: startFromFrames,
1679
1752
  playbackRate: speed,
1680
1753
  volume
1681
1754
  }
package/dist/index.mjs CHANGED
@@ -302,6 +302,51 @@ function hexToRgba(hex, opacity = 100) {
302
302
  return `rgba(${r}, ${g}, ${b}, ${opacity / 100})`;
303
303
  }
304
304
 
305
+ // src/utils/emoji.ts
306
+ var APPLE_EMOJI_CDN_BASE = "https://cdn.jsdelivr.net/npm/emoji-datasource-apple/img/apple/64/";
307
+ function emojiToUnified(emoji) {
308
+ const codePoints = [];
309
+ for (const codePoint of emoji) {
310
+ const hex = codePoint.codePointAt(0)?.toString(16);
311
+ if (hex) {
312
+ codePoints.push(hex);
313
+ }
314
+ }
315
+ return codePoints.join("-");
316
+ }
317
+ function getAppleEmojiUrl(emoji) {
318
+ const unified = emojiToUnified(emoji);
319
+ return `${APPLE_EMOJI_CDN_BASE}${unified}.png`;
320
+ }
321
+ 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;
322
+ function splitTextAndEmojis(text) {
323
+ const segments = [];
324
+ let lastIndex = 0;
325
+ EMOJI_REGEX.lastIndex = 0;
326
+ let match;
327
+ while ((match = EMOJI_REGEX.exec(text)) !== null) {
328
+ if (match.index > lastIndex) {
329
+ segments.push({
330
+ type: "text",
331
+ content: text.slice(lastIndex, match.index)
332
+ });
333
+ }
334
+ segments.push({
335
+ type: "emoji",
336
+ content: match[0],
337
+ imageUrl: getAppleEmojiUrl(match[0])
338
+ });
339
+ lastIndex = match.index + match[0].length;
340
+ }
341
+ if (lastIndex < text.length) {
342
+ segments.push({
343
+ type: "text",
344
+ content: text.slice(lastIndex)
345
+ });
346
+ }
347
+ return segments;
348
+ }
349
+
305
350
  // src/components/TextElement.tsx
306
351
  import { jsx, jsxs } from "react/jsx-runtime";
307
352
  function calculateAutoWidthAndLines({
@@ -600,9 +645,37 @@ function TextElement({ segment, scale = 1 }) {
600
645
  autoWidth,
601
646
  verticalAlign
602
647
  ]);
648
+ const hasStroke = strokeWidth > 0 && strokeColor;
649
+ const renderTextWithEmojis = (text) => {
650
+ if (!hasStroke) {
651
+ return text;
652
+ }
653
+ const segments = splitTextAndEmojis(text);
654
+ if (segments.every((s) => s.type === "text")) {
655
+ return text;
656
+ }
657
+ return segments.map((segment2, i) => {
658
+ if (segment2.type === "text") {
659
+ return /* @__PURE__ */ jsx(React.Fragment, { children: segment2.content }, i);
660
+ }
661
+ return /* @__PURE__ */ jsx(
662
+ "span",
663
+ {
664
+ style: {
665
+ textShadow: "none",
666
+ WebkitTextStroke: "initial",
667
+ // Ensure emoji renders properly
668
+ display: "inline"
669
+ },
670
+ children: segment2.content
671
+ },
672
+ i
673
+ );
674
+ });
675
+ };
603
676
  if (autoWidth) {
604
677
  const textContent = calculatedLines.map((line, index) => /* @__PURE__ */ jsxs(React.Fragment, { children: [
605
- line,
678
+ renderTextWithEmojis(line),
606
679
  index < calculatedLines.length - 1 && /* @__PURE__ */ jsx("br", {})
607
680
  ] }, index));
608
681
  if (backgroundColor) {
@@ -621,7 +694,7 @@ function TextElement({ segment, scale = 1 }) {
621
694
  }
622
695
  return /* @__PURE__ */ jsx("div", { style: positioningContainerStyle, children: /* @__PURE__ */ jsx("div", { style: { width: calculatedWidth, maxWidth: width }, children: /* @__PURE__ */ jsx("div", { style: textStyle, children: textContent }) }) });
623
696
  }
624
- return /* @__PURE__ */ jsx("div", { style: positioningContainerStyle, children: /* @__PURE__ */ jsx("div", { style: backgroundBoxStyle, children: /* @__PURE__ */ jsx("div", { style: textStyle, children: segment.text }) }) });
697
+ return /* @__PURE__ */ jsx("div", { style: positioningContainerStyle, children: /* @__PURE__ */ jsx("div", { style: backgroundBoxStyle, children: /* @__PURE__ */ jsx("div", { style: textStyle, children: renderTextWithEmojis(segment.text) }) }) });
625
698
  }
626
699
 
627
700
  // src/components/ImageElement.tsx
@@ -1589,7 +1662,7 @@ function VideoElement({
1589
1662
  {
1590
1663
  src,
1591
1664
  style: videoStyle,
1592
- startFrom: startFromFrames,
1665
+ trimBefore: startFromFrames,
1593
1666
  playbackRate: speed,
1594
1667
  volume
1595
1668
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "ugcinc-render",
3
- "version": "1.5.28",
3
+ "version": "1.5.30",
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",