ugcinc-render 1.5.15 → 1.5.17
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 +13 -29
- package/dist/index.d.ts +13 -29
- package/dist/index.js +131 -136
- package/dist/index.mjs +129 -132
- package/package.json +1 -1
package/dist/index.d.mts
CHANGED
|
@@ -955,9 +955,14 @@ declare function VideoElement({ segment, src, startFrame, durationInFrames, scal
|
|
|
955
955
|
* Font utilities for the rendering system
|
|
956
956
|
*/
|
|
957
957
|
|
|
958
|
+
/**
|
|
959
|
+
* Apple Color Emoji font name - used as fallback for emoji characters
|
|
960
|
+
*/
|
|
961
|
+
declare const APPLE_EMOJI_FONT = "\"Apple Color Emoji\"";
|
|
958
962
|
/**
|
|
959
963
|
* Font family CSS strings for each font type
|
|
960
964
|
* These match the fonts registered in the rendering system
|
|
965
|
+
* Apple Color Emoji is added as a fallback for consistent emoji rendering
|
|
961
966
|
*/
|
|
962
967
|
declare const FONT_FAMILIES: Record<FontType, string>;
|
|
963
968
|
/**
|
|
@@ -984,6 +989,9 @@ declare const FONT_URLS: {
|
|
|
984
989
|
apple: {
|
|
985
990
|
regular: string;
|
|
986
991
|
};
|
|
992
|
+
emoji: {
|
|
993
|
+
apple: string;
|
|
994
|
+
};
|
|
987
995
|
};
|
|
988
996
|
/**
|
|
989
997
|
* Preload fonts for rendering
|
|
@@ -994,6 +1002,10 @@ declare function preloadFonts(): Promise<void>;
|
|
|
994
1002
|
* Check if fonts are loaded
|
|
995
1003
|
*/
|
|
996
1004
|
declare function areFontsLoaded(): boolean;
|
|
1005
|
+
/**
|
|
1006
|
+
* Debug utility to log current font status
|
|
1007
|
+
*/
|
|
1008
|
+
declare function debugFontStatus(): void;
|
|
997
1009
|
|
|
998
1010
|
/**
|
|
999
1011
|
* Fit calculation utilities for media positioning
|
|
@@ -1290,34 +1302,6 @@ declare function generateSegmentId(): string;
|
|
|
1290
1302
|
*/
|
|
1291
1303
|
declare function generateOverlayId(): string;
|
|
1292
1304
|
|
|
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
|
-
|
|
1321
1305
|
/**
|
|
1322
1306
|
* Hook exports for ugcinc-render
|
|
1323
1307
|
*
|
|
@@ -1377,4 +1361,4 @@ declare function useResolvedPositions(elements: ImageEditorElement[], textValues
|
|
|
1377
1361
|
|
|
1378
1362
|
declare const RenderRoot: React.FC;
|
|
1379
1363
|
|
|
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
|
|
1364
|
+
export { APPLE_EMOJI_FONT, 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, debugFontStatus, defaultOffset, formatTime, generateOverlayId, generateSegmentId, getBaseSegments, getBorderRadii, getDependentElements, getFontFamily, getOverlays, getReferenceElementX, getReferenceElementY, getSegmentTimelinePosition, hexToRgba, isDynamicCropEnabled, isSegmentVisibleAtTime, parseHexColor, parseTime, preloadFonts, resolveElementPositions, useFontsLoaded, useImageLoader, useImagePreloader, useResolvedPositions, wrapText };
|
package/dist/index.d.ts
CHANGED
|
@@ -955,9 +955,14 @@ declare function VideoElement({ segment, src, startFrame, durationInFrames, scal
|
|
|
955
955
|
* Font utilities for the rendering system
|
|
956
956
|
*/
|
|
957
957
|
|
|
958
|
+
/**
|
|
959
|
+
* Apple Color Emoji font name - used as fallback for emoji characters
|
|
960
|
+
*/
|
|
961
|
+
declare const APPLE_EMOJI_FONT = "\"Apple Color Emoji\"";
|
|
958
962
|
/**
|
|
959
963
|
* Font family CSS strings for each font type
|
|
960
964
|
* These match the fonts registered in the rendering system
|
|
965
|
+
* Apple Color Emoji is added as a fallback for consistent emoji rendering
|
|
961
966
|
*/
|
|
962
967
|
declare const FONT_FAMILIES: Record<FontType, string>;
|
|
963
968
|
/**
|
|
@@ -984,6 +989,9 @@ declare const FONT_URLS: {
|
|
|
984
989
|
apple: {
|
|
985
990
|
regular: string;
|
|
986
991
|
};
|
|
992
|
+
emoji: {
|
|
993
|
+
apple: string;
|
|
994
|
+
};
|
|
987
995
|
};
|
|
988
996
|
/**
|
|
989
997
|
* Preload fonts for rendering
|
|
@@ -994,6 +1002,10 @@ declare function preloadFonts(): Promise<void>;
|
|
|
994
1002
|
* Check if fonts are loaded
|
|
995
1003
|
*/
|
|
996
1004
|
declare function areFontsLoaded(): boolean;
|
|
1005
|
+
/**
|
|
1006
|
+
* Debug utility to log current font status
|
|
1007
|
+
*/
|
|
1008
|
+
declare function debugFontStatus(): void;
|
|
997
1009
|
|
|
998
1010
|
/**
|
|
999
1011
|
* Fit calculation utilities for media positioning
|
|
@@ -1290,34 +1302,6 @@ declare function generateSegmentId(): string;
|
|
|
1290
1302
|
*/
|
|
1291
1303
|
declare function generateOverlayId(): string;
|
|
1292
1304
|
|
|
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
|
-
|
|
1321
1305
|
/**
|
|
1322
1306
|
* Hook exports for ugcinc-render
|
|
1323
1307
|
*
|
|
@@ -1377,4 +1361,4 @@ declare function useResolvedPositions(elements: ImageEditorElement[], textValues
|
|
|
1377
1361
|
|
|
1378
1362
|
declare const RenderRoot: React.FC;
|
|
1379
1363
|
|
|
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
|
|
1364
|
+
export { APPLE_EMOJI_FONT, 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, debugFontStatus, defaultOffset, formatTime, generateOverlayId, generateSegmentId, getBaseSegments, getBorderRadii, getDependentElements, getFontFamily, getOverlays, getReferenceElementX, getReferenceElementY, getSegmentTimelinePosition, hexToRgba, isDynamicCropEnabled, isSegmentVisibleAtTime, parseHexColor, parseTime, preloadFonts, resolveElementPositions, useFontsLoaded, useImageLoader, useImagePreloader, useResolvedPositions, wrapText };
|
package/dist/index.js
CHANGED
|
@@ -30,6 +30,7 @@ var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: tru
|
|
|
30
30
|
// src/index.ts
|
|
31
31
|
var index_exports = {};
|
|
32
32
|
__export(index_exports, {
|
|
33
|
+
APPLE_EMOJI_FONT: () => APPLE_EMOJI_FONT,
|
|
33
34
|
DIMENSION_PRESETS: () => DIMENSION_PRESETS,
|
|
34
35
|
FONT_FAMILIES: () => FONT_FAMILIES,
|
|
35
36
|
FONT_URLS: () => FONT_URLS,
|
|
@@ -55,12 +56,11 @@ __export(index_exports, {
|
|
|
55
56
|
calculateLineWidth: () => calculateLineWidth,
|
|
56
57
|
calculateTimelineContentEnd: () => calculateTimelineContentEnd,
|
|
57
58
|
canSetAsReference: () => canSetAsReference,
|
|
59
|
+
debugFontStatus: () => debugFontStatus,
|
|
58
60
|
defaultOffset: () => defaultOffset,
|
|
59
|
-
emojiToUnified: () => emojiToUnified,
|
|
60
61
|
formatTime: () => formatTime,
|
|
61
62
|
generateOverlayId: () => generateOverlayId,
|
|
62
63
|
generateSegmentId: () => generateSegmentId,
|
|
63
|
-
getAppleEmojiUrl: () => getAppleEmojiUrl,
|
|
64
64
|
getBaseSegments: () => getBaseSegments,
|
|
65
65
|
getBorderRadii: () => getBorderRadii,
|
|
66
66
|
getDependentElements: () => getDependentElements,
|
|
@@ -69,7 +69,6 @@ __export(index_exports, {
|
|
|
69
69
|
getReferenceElementX: () => getReferenceElementX,
|
|
70
70
|
getReferenceElementY: () => getReferenceElementY,
|
|
71
71
|
getSegmentTimelinePosition: () => getSegmentTimelinePosition,
|
|
72
|
-
hasEmoji: () => hasEmoji,
|
|
73
72
|
hexToRgba: () => hexToRgba,
|
|
74
73
|
isDynamicCropEnabled: () => isDynamicCropEnabled,
|
|
75
74
|
isSegmentVisibleAtTime: () => isSegmentVisibleAtTime,
|
|
@@ -77,7 +76,6 @@ __export(index_exports, {
|
|
|
77
76
|
parseTime: () => parseTime,
|
|
78
77
|
preloadFonts: () => preloadFonts,
|
|
79
78
|
resolveElementPositions: () => resolveElementPositions,
|
|
80
|
-
splitTextAndEmojis: () => splitTextAndEmojis,
|
|
81
79
|
useFontsLoaded: () => useFontsLoaded,
|
|
82
80
|
useImageLoader: () => useImageLoader,
|
|
83
81
|
useImagePreloader: () => useImagePreloader,
|
|
@@ -163,10 +161,11 @@ function applyVideoDefaults(segment) {
|
|
|
163
161
|
}
|
|
164
162
|
|
|
165
163
|
// src/utils/fonts.ts
|
|
164
|
+
var APPLE_EMOJI_FONT = '"Apple Color Emoji"';
|
|
166
165
|
var FONT_FAMILIES = {
|
|
167
|
-
tiktok:
|
|
168
|
-
apple:
|
|
169
|
-
arial:
|
|
166
|
+
tiktok: `"TikTok Sans", ${APPLE_EMOJI_FONT}, sans-serif`,
|
|
167
|
+
apple: `"SF Pro", "SF Pro Display", -apple-system, BlinkMacSystemFont, ${APPLE_EMOJI_FONT}, sans-serif`,
|
|
168
|
+
arial: `Arial, ${APPLE_EMOJI_FONT}, sans-serif`
|
|
170
169
|
};
|
|
171
170
|
function getFontFamily(fontType) {
|
|
172
171
|
return FONT_FAMILIES[fontType] ?? FONT_FAMILIES.arial;
|
|
@@ -186,40 +185,123 @@ var FONT_URLS = {
|
|
|
186
185
|
},
|
|
187
186
|
apple: {
|
|
188
187
|
regular: "/SF-Pro.ttf"
|
|
188
|
+
},
|
|
189
|
+
emoji: {
|
|
190
|
+
apple: "/AppleColorEmoji.ttf"
|
|
189
191
|
}
|
|
190
192
|
};
|
|
191
193
|
async function preloadFonts() {
|
|
194
|
+
console.log("[ugcinc-render/fonts] preloadFonts() called");
|
|
192
195
|
if (typeof document !== "undefined") {
|
|
193
|
-
|
|
194
|
-
const
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
|
|
196
|
+
console.log("[ugcinc-render/fonts] Browser environment detected, loading fonts...");
|
|
197
|
+
const fontResults = [];
|
|
198
|
+
try {
|
|
199
|
+
const tiktokRegular = new FontFace(
|
|
200
|
+
"TikTok Sans",
|
|
201
|
+
`url(${FONT_URLS.tiktok.regular})`,
|
|
202
|
+
{ weight: "normal" }
|
|
203
|
+
);
|
|
204
|
+
console.log(`[ugcinc-render/fonts] Loading TikTok Sans Regular from: ${FONT_URLS.tiktok.regular}`);
|
|
205
|
+
await tiktokRegular.load();
|
|
206
|
+
document.fonts.add(tiktokRegular);
|
|
207
|
+
fontResults.push({ name: "TikTok Sans Regular", status: "success" });
|
|
208
|
+
} catch (err) {
|
|
209
|
+
const errorMsg = err instanceof Error ? err.message : String(err);
|
|
210
|
+
console.error(`[ugcinc-render/fonts] Failed to load TikTok Sans Regular:`, errorMsg);
|
|
211
|
+
fontResults.push({ name: "TikTok Sans Regular", status: "error", error: errorMsg });
|
|
212
|
+
}
|
|
213
|
+
try {
|
|
214
|
+
const tiktokBold = new FontFace(
|
|
215
|
+
"TikTok Sans",
|
|
216
|
+
`url(${FONT_URLS.tiktok.bold})`,
|
|
217
|
+
{ weight: "bold" }
|
|
218
|
+
);
|
|
219
|
+
console.log(`[ugcinc-render/fonts] Loading TikTok Sans Bold from: ${FONT_URLS.tiktok.bold}`);
|
|
220
|
+
await tiktokBold.load();
|
|
221
|
+
document.fonts.add(tiktokBold);
|
|
222
|
+
fontResults.push({ name: "TikTok Sans Bold", status: "success" });
|
|
223
|
+
} catch (err) {
|
|
224
|
+
const errorMsg = err instanceof Error ? err.message : String(err);
|
|
225
|
+
console.error(`[ugcinc-render/fonts] Failed to load TikTok Sans Bold:`, errorMsg);
|
|
226
|
+
fontResults.push({ name: "TikTok Sans Bold", status: "error", error: errorMsg });
|
|
227
|
+
}
|
|
228
|
+
try {
|
|
229
|
+
const sfPro = new FontFace(
|
|
230
|
+
"SF Pro",
|
|
231
|
+
`url(${FONT_URLS.apple.regular})`,
|
|
232
|
+
{ weight: "normal" }
|
|
233
|
+
);
|
|
234
|
+
console.log(`[ugcinc-render/fonts] Loading SF Pro from: ${FONT_URLS.apple.regular}`);
|
|
235
|
+
await sfPro.load();
|
|
236
|
+
document.fonts.add(sfPro);
|
|
237
|
+
fontResults.push({ name: "SF Pro", status: "success" });
|
|
238
|
+
} catch (err) {
|
|
239
|
+
const errorMsg = err instanceof Error ? err.message : String(err);
|
|
240
|
+
console.error(`[ugcinc-render/fonts] Failed to load SF Pro:`, errorMsg);
|
|
241
|
+
fontResults.push({ name: "SF Pro", status: "error", error: errorMsg });
|
|
242
|
+
}
|
|
243
|
+
try {
|
|
244
|
+
const appleEmoji = new FontFace(
|
|
245
|
+
"Apple Color Emoji",
|
|
246
|
+
`url(${FONT_URLS.emoji.apple})`,
|
|
247
|
+
{ weight: "normal" }
|
|
248
|
+
);
|
|
249
|
+
console.log(`[ugcinc-render/fonts] Loading Apple Color Emoji from: ${FONT_URLS.emoji.apple}`);
|
|
250
|
+
await appleEmoji.load();
|
|
251
|
+
document.fonts.add(appleEmoji);
|
|
252
|
+
fontResults.push({ name: "Apple Color Emoji", status: "success" });
|
|
253
|
+
} catch (err) {
|
|
254
|
+
const errorMsg = err instanceof Error ? err.message : String(err);
|
|
255
|
+
console.error(`[ugcinc-render/fonts] Failed to load Apple Color Emoji:`, errorMsg);
|
|
256
|
+
fontResults.push({ name: "Apple Color Emoji", status: "error", error: errorMsg });
|
|
257
|
+
}
|
|
258
|
+
console.log("[ugcinc-render/fonts] Font loading complete. Results:", fontResults);
|
|
259
|
+
const availableFonts = [];
|
|
260
|
+
document.fonts.forEach((font) => {
|
|
261
|
+
availableFonts.push(`${font.family} (${font.weight}, ${font.status})`);
|
|
215
262
|
});
|
|
263
|
+
console.log("[ugcinc-render/fonts] Available fonts in document:", availableFonts);
|
|
264
|
+
} else {
|
|
265
|
+
console.log("[ugcinc-render/fonts] Not in browser environment, skipping font loading");
|
|
216
266
|
}
|
|
217
267
|
}
|
|
218
268
|
function areFontsLoaded() {
|
|
219
269
|
if (typeof document === "undefined") {
|
|
270
|
+
console.log("[ugcinc-render/fonts] areFontsLoaded: Not in browser environment");
|
|
220
271
|
return false;
|
|
221
272
|
}
|
|
222
|
-
|
|
273
|
+
const tiktokRegular = document.fonts.check('normal 16px "TikTok Sans"');
|
|
274
|
+
const tiktokBold = document.fonts.check('bold 16px "TikTok Sans"');
|
|
275
|
+
const sfPro = document.fonts.check('normal 16px "SF Pro"');
|
|
276
|
+
const appleEmoji = document.fonts.check('normal 16px "Apple Color Emoji"');
|
|
277
|
+
console.log("[ugcinc-render/fonts] areFontsLoaded check:", {
|
|
278
|
+
tiktokRegular,
|
|
279
|
+
tiktokBold,
|
|
280
|
+
sfPro,
|
|
281
|
+
appleEmoji
|
|
282
|
+
});
|
|
283
|
+
return tiktokRegular && tiktokBold && sfPro && appleEmoji;
|
|
284
|
+
}
|
|
285
|
+
function debugFontStatus() {
|
|
286
|
+
console.log("[ugcinc-render/fonts] === FONT DEBUG STATUS ===");
|
|
287
|
+
if (typeof document === "undefined") {
|
|
288
|
+
console.log("[ugcinc-render/fonts] Not in browser environment");
|
|
289
|
+
return;
|
|
290
|
+
}
|
|
291
|
+
console.log("[ugcinc-render/fonts] Font checks:");
|
|
292
|
+
console.log(" - TikTok Sans (normal):", document.fonts.check('normal 16px "TikTok Sans"'));
|
|
293
|
+
console.log(" - TikTok Sans (bold):", document.fonts.check('bold 16px "TikTok Sans"'));
|
|
294
|
+
console.log(" - SF Pro:", document.fonts.check('normal 16px "SF Pro"'));
|
|
295
|
+
console.log(" - Apple Color Emoji:", document.fonts.check('normal 16px "Apple Color Emoji"'));
|
|
296
|
+
console.log("[ugcinc-render/fonts] All fonts in document.fonts:");
|
|
297
|
+
document.fonts.forEach((font) => {
|
|
298
|
+
console.log(` - ${font.family}: weight=${font.weight}, style=${font.style}, status=${font.status}`);
|
|
299
|
+
});
|
|
300
|
+
console.log("[ugcinc-render/fonts] Font family stacks:");
|
|
301
|
+
console.log(" - tiktok:", FONT_FAMILIES.tiktok);
|
|
302
|
+
console.log(" - apple:", FONT_FAMILIES.apple);
|
|
303
|
+
console.log(" - arial:", FONT_FAMILIES.arial);
|
|
304
|
+
console.log("[ugcinc-render/fonts] === END FONT DEBUG ===");
|
|
223
305
|
}
|
|
224
306
|
|
|
225
307
|
// src/utils/text.ts
|
|
@@ -306,66 +388,6 @@ function hexToRgba(hex, opacity = 100) {
|
|
|
306
388
|
return `rgba(${r}, ${g}, ${b}, ${opacity / 100})`;
|
|
307
389
|
}
|
|
308
390
|
|
|
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
|
-
function countEmojis(text) {
|
|
357
|
-
EMOJI_REGEX.lastIndex = 0;
|
|
358
|
-
const matches = text.match(EMOJI_REGEX);
|
|
359
|
-
return matches ? matches.length : 0;
|
|
360
|
-
}
|
|
361
|
-
function getEmojiWidth(fontSize) {
|
|
362
|
-
return fontSize * 1.2;
|
|
363
|
-
}
|
|
364
|
-
function stripEmojis(text) {
|
|
365
|
-
EMOJI_REGEX.lastIndex = 0;
|
|
366
|
-
return text.replace(EMOJI_REGEX, "");
|
|
367
|
-
}
|
|
368
|
-
|
|
369
391
|
// src/components/TextElement.tsx
|
|
370
392
|
var import_jsx_runtime = require("react/jsx-runtime");
|
|
371
393
|
function calculateAutoWidthAndLines({
|
|
@@ -398,17 +420,9 @@ function calculateAutoWidthAndLines({
|
|
|
398
420
|
white-space: nowrap;
|
|
399
421
|
`;
|
|
400
422
|
document.body.appendChild(measureSpan);
|
|
401
|
-
const
|
|
402
|
-
|
|
403
|
-
|
|
404
|
-
if (emojiCount === 0) {
|
|
405
|
-
measureSpan.textContent = textToMeasure;
|
|
406
|
-
return measureSpan.getBoundingClientRect().width;
|
|
407
|
-
}
|
|
408
|
-
const textWithoutEmojis = stripEmojis(textToMeasure);
|
|
409
|
-
measureSpan.textContent = textWithoutEmojis;
|
|
410
|
-
const textWidth = measureSpan.getBoundingClientRect().width;
|
|
411
|
-
return textWidth + emojiCount * emojiWidth;
|
|
423
|
+
const measureText = (textToMeasure) => {
|
|
424
|
+
measureSpan.textContent = textToMeasure;
|
|
425
|
+
return measureSpan.getBoundingClientRect().width;
|
|
412
426
|
};
|
|
413
427
|
measureSpan.textContent = "M";
|
|
414
428
|
const charWidth = measureSpan.getBoundingClientRect().width;
|
|
@@ -432,12 +446,12 @@ function calculateAutoWidthAndLines({
|
|
|
432
446
|
continue;
|
|
433
447
|
}
|
|
434
448
|
const testLine = currentLine + word;
|
|
435
|
-
const testWidth =
|
|
449
|
+
const testWidth = measureText(testLine);
|
|
436
450
|
const WRAP_TOLERANCE = 0.5;
|
|
437
451
|
if (testWidth > availableWidth + WRAP_TOLERANCE && currentLine.trim()) {
|
|
438
452
|
lines.push(currentLine.trimEnd());
|
|
439
453
|
currentLine = word;
|
|
440
|
-
const wordWidth =
|
|
454
|
+
const wordWidth = measureText(word);
|
|
441
455
|
if (wordWidth > availableWidth) {
|
|
442
456
|
let remainingWord = word;
|
|
443
457
|
while (remainingWord) {
|
|
@@ -471,7 +485,7 @@ function calculateAutoWidthAndLines({
|
|
|
471
485
|
}
|
|
472
486
|
let widestLineWidth = 0;
|
|
473
487
|
for (const line of lines) {
|
|
474
|
-
const lineWidth =
|
|
488
|
+
const lineWidth = measureText(line);
|
|
475
489
|
widestLineWidth = Math.max(widestLineWidth, lineWidth);
|
|
476
490
|
}
|
|
477
491
|
document.body.removeChild(measureSpan);
|
|
@@ -479,6 +493,15 @@ function calculateAutoWidthAndLines({
|
|
|
479
493
|
return { width: calculatedWidth, lines };
|
|
480
494
|
}
|
|
481
495
|
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]);
|
|
482
505
|
const fontType = segment.fontType ?? TEXT_DEFAULTS.fontType;
|
|
483
506
|
const fontSize = (segment.fontSize ?? TEXT_DEFAULTS.fontSize) * scale;
|
|
484
507
|
const fontWeight = segment.fontWeight ?? TEXT_DEFAULTS.fontWeight;
|
|
@@ -678,35 +701,9 @@ function TextElement({ segment, scale = 1 }) {
|
|
|
678
701
|
autoWidth,
|
|
679
702
|
verticalAlign
|
|
680
703
|
]);
|
|
681
|
-
const renderTextWithEmojis = (text) => {
|
|
682
|
-
if (!hasEmoji(text)) {
|
|
683
|
-
return text;
|
|
684
|
-
}
|
|
685
|
-
const segments = splitTextAndEmojis(text);
|
|
686
|
-
return segments.map((segment2, i) => {
|
|
687
|
-
if (segment2.type === "emoji" && segment2.imageUrl) {
|
|
688
|
-
return /* @__PURE__ */ (0, import_jsx_runtime.jsx)(
|
|
689
|
-
"img",
|
|
690
|
-
{
|
|
691
|
-
src: segment2.imageUrl,
|
|
692
|
-
alt: segment2.content,
|
|
693
|
-
style: {
|
|
694
|
-
height: "1.2em",
|
|
695
|
-
width: "1.2em",
|
|
696
|
-
verticalAlign: "-0.25em",
|
|
697
|
-
display: "inline"
|
|
698
|
-
},
|
|
699
|
-
draggable: false
|
|
700
|
-
},
|
|
701
|
-
i
|
|
702
|
-
);
|
|
703
|
-
}
|
|
704
|
-
return /* @__PURE__ */ (0, import_jsx_runtime.jsx)(import_react.default.Fragment, { children: segment2.content }, i);
|
|
705
|
-
});
|
|
706
|
-
};
|
|
707
704
|
if (autoWidth) {
|
|
708
705
|
const textContent = calculatedLines.map((line, index) => /* @__PURE__ */ (0, import_jsx_runtime.jsxs)(import_react.default.Fragment, { children: [
|
|
709
|
-
|
|
706
|
+
line,
|
|
710
707
|
index < calculatedLines.length - 1 && /* @__PURE__ */ (0, import_jsx_runtime.jsx)("br", {})
|
|
711
708
|
] }, index));
|
|
712
709
|
if (backgroundColor) {
|
|
@@ -725,7 +722,7 @@ function TextElement({ segment, scale = 1 }) {
|
|
|
725
722
|
}
|
|
726
723
|
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 }) }) });
|
|
727
724
|
}
|
|
728
|
-
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:
|
|
725
|
+
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 }) }) });
|
|
729
726
|
}
|
|
730
727
|
|
|
731
728
|
// src/components/ImageElement.tsx
|
|
@@ -2019,6 +2016,7 @@ var RenderRoot = () => {
|
|
|
2019
2016
|
};
|
|
2020
2017
|
// Annotate the CommonJS export names for ESM import in node:
|
|
2021
2018
|
0 && (module.exports = {
|
|
2019
|
+
APPLE_EMOJI_FONT,
|
|
2022
2020
|
DIMENSION_PRESETS,
|
|
2023
2021
|
FONT_FAMILIES,
|
|
2024
2022
|
FONT_URLS,
|
|
@@ -2044,12 +2042,11 @@ var RenderRoot = () => {
|
|
|
2044
2042
|
calculateLineWidth,
|
|
2045
2043
|
calculateTimelineContentEnd,
|
|
2046
2044
|
canSetAsReference,
|
|
2045
|
+
debugFontStatus,
|
|
2047
2046
|
defaultOffset,
|
|
2048
|
-
emojiToUnified,
|
|
2049
2047
|
formatTime,
|
|
2050
2048
|
generateOverlayId,
|
|
2051
2049
|
generateSegmentId,
|
|
2052
|
-
getAppleEmojiUrl,
|
|
2053
2050
|
getBaseSegments,
|
|
2054
2051
|
getBorderRadii,
|
|
2055
2052
|
getDependentElements,
|
|
@@ -2058,7 +2055,6 @@ var RenderRoot = () => {
|
|
|
2058
2055
|
getReferenceElementX,
|
|
2059
2056
|
getReferenceElementY,
|
|
2060
2057
|
getSegmentTimelinePosition,
|
|
2061
|
-
hasEmoji,
|
|
2062
2058
|
hexToRgba,
|
|
2063
2059
|
isDynamicCropEnabled,
|
|
2064
2060
|
isSegmentVisibleAtTime,
|
|
@@ -2066,7 +2062,6 @@ var RenderRoot = () => {
|
|
|
2066
2062
|
parseTime,
|
|
2067
2063
|
preloadFonts,
|
|
2068
2064
|
resolveElementPositions,
|
|
2069
|
-
splitTextAndEmojis,
|
|
2070
2065
|
useFontsLoaded,
|
|
2071
2066
|
useImageLoader,
|
|
2072
2067
|
useImagePreloader,
|
package/dist/index.mjs
CHANGED
|
@@ -75,10 +75,11 @@ function applyVideoDefaults(segment) {
|
|
|
75
75
|
}
|
|
76
76
|
|
|
77
77
|
// src/utils/fonts.ts
|
|
78
|
+
var APPLE_EMOJI_FONT = '"Apple Color Emoji"';
|
|
78
79
|
var FONT_FAMILIES = {
|
|
79
|
-
tiktok:
|
|
80
|
-
apple:
|
|
81
|
-
arial:
|
|
80
|
+
tiktok: `"TikTok Sans", ${APPLE_EMOJI_FONT}, sans-serif`,
|
|
81
|
+
apple: `"SF Pro", "SF Pro Display", -apple-system, BlinkMacSystemFont, ${APPLE_EMOJI_FONT}, sans-serif`,
|
|
82
|
+
arial: `Arial, ${APPLE_EMOJI_FONT}, sans-serif`
|
|
82
83
|
};
|
|
83
84
|
function getFontFamily(fontType) {
|
|
84
85
|
return FONT_FAMILIES[fontType] ?? FONT_FAMILIES.arial;
|
|
@@ -98,40 +99,123 @@ var FONT_URLS = {
|
|
|
98
99
|
},
|
|
99
100
|
apple: {
|
|
100
101
|
regular: "/SF-Pro.ttf"
|
|
102
|
+
},
|
|
103
|
+
emoji: {
|
|
104
|
+
apple: "/AppleColorEmoji.ttf"
|
|
101
105
|
}
|
|
102
106
|
};
|
|
103
107
|
async function preloadFonts() {
|
|
108
|
+
console.log("[ugcinc-render/fonts] preloadFonts() called");
|
|
104
109
|
if (typeof document !== "undefined") {
|
|
105
|
-
|
|
106
|
-
const
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
110
|
+
console.log("[ugcinc-render/fonts] Browser environment detected, loading fonts...");
|
|
111
|
+
const fontResults = [];
|
|
112
|
+
try {
|
|
113
|
+
const tiktokRegular = new FontFace(
|
|
114
|
+
"TikTok Sans",
|
|
115
|
+
`url(${FONT_URLS.tiktok.regular})`,
|
|
116
|
+
{ weight: "normal" }
|
|
117
|
+
);
|
|
118
|
+
console.log(`[ugcinc-render/fonts] Loading TikTok Sans Regular from: ${FONT_URLS.tiktok.regular}`);
|
|
119
|
+
await tiktokRegular.load();
|
|
120
|
+
document.fonts.add(tiktokRegular);
|
|
121
|
+
fontResults.push({ name: "TikTok Sans Regular", status: "success" });
|
|
122
|
+
} catch (err) {
|
|
123
|
+
const errorMsg = err instanceof Error ? err.message : String(err);
|
|
124
|
+
console.error(`[ugcinc-render/fonts] Failed to load TikTok Sans Regular:`, errorMsg);
|
|
125
|
+
fontResults.push({ name: "TikTok Sans Regular", status: "error", error: errorMsg });
|
|
126
|
+
}
|
|
127
|
+
try {
|
|
128
|
+
const tiktokBold = new FontFace(
|
|
129
|
+
"TikTok Sans",
|
|
130
|
+
`url(${FONT_URLS.tiktok.bold})`,
|
|
131
|
+
{ weight: "bold" }
|
|
132
|
+
);
|
|
133
|
+
console.log(`[ugcinc-render/fonts] Loading TikTok Sans Bold from: ${FONT_URLS.tiktok.bold}`);
|
|
134
|
+
await tiktokBold.load();
|
|
135
|
+
document.fonts.add(tiktokBold);
|
|
136
|
+
fontResults.push({ name: "TikTok Sans Bold", status: "success" });
|
|
137
|
+
} catch (err) {
|
|
138
|
+
const errorMsg = err instanceof Error ? err.message : String(err);
|
|
139
|
+
console.error(`[ugcinc-render/fonts] Failed to load TikTok Sans Bold:`, errorMsg);
|
|
140
|
+
fontResults.push({ name: "TikTok Sans Bold", status: "error", error: errorMsg });
|
|
141
|
+
}
|
|
142
|
+
try {
|
|
143
|
+
const sfPro = new FontFace(
|
|
144
|
+
"SF Pro",
|
|
145
|
+
`url(${FONT_URLS.apple.regular})`,
|
|
146
|
+
{ weight: "normal" }
|
|
147
|
+
);
|
|
148
|
+
console.log(`[ugcinc-render/fonts] Loading SF Pro from: ${FONT_URLS.apple.regular}`);
|
|
149
|
+
await sfPro.load();
|
|
150
|
+
document.fonts.add(sfPro);
|
|
151
|
+
fontResults.push({ name: "SF Pro", status: "success" });
|
|
152
|
+
} catch (err) {
|
|
153
|
+
const errorMsg = err instanceof Error ? err.message : String(err);
|
|
154
|
+
console.error(`[ugcinc-render/fonts] Failed to load SF Pro:`, errorMsg);
|
|
155
|
+
fontResults.push({ name: "SF Pro", status: "error", error: errorMsg });
|
|
156
|
+
}
|
|
157
|
+
try {
|
|
158
|
+
const appleEmoji = new FontFace(
|
|
159
|
+
"Apple Color Emoji",
|
|
160
|
+
`url(${FONT_URLS.emoji.apple})`,
|
|
161
|
+
{ weight: "normal" }
|
|
162
|
+
);
|
|
163
|
+
console.log(`[ugcinc-render/fonts] Loading Apple Color Emoji from: ${FONT_URLS.emoji.apple}`);
|
|
164
|
+
await appleEmoji.load();
|
|
165
|
+
document.fonts.add(appleEmoji);
|
|
166
|
+
fontResults.push({ name: "Apple Color Emoji", status: "success" });
|
|
167
|
+
} catch (err) {
|
|
168
|
+
const errorMsg = err instanceof Error ? err.message : String(err);
|
|
169
|
+
console.error(`[ugcinc-render/fonts] Failed to load Apple Color Emoji:`, errorMsg);
|
|
170
|
+
fontResults.push({ name: "Apple Color Emoji", status: "error", error: errorMsg });
|
|
171
|
+
}
|
|
172
|
+
console.log("[ugcinc-render/fonts] Font loading complete. Results:", fontResults);
|
|
173
|
+
const availableFonts = [];
|
|
174
|
+
document.fonts.forEach((font) => {
|
|
175
|
+
availableFonts.push(`${font.family} (${font.weight}, ${font.status})`);
|
|
127
176
|
});
|
|
177
|
+
console.log("[ugcinc-render/fonts] Available fonts in document:", availableFonts);
|
|
178
|
+
} else {
|
|
179
|
+
console.log("[ugcinc-render/fonts] Not in browser environment, skipping font loading");
|
|
128
180
|
}
|
|
129
181
|
}
|
|
130
182
|
function areFontsLoaded() {
|
|
131
183
|
if (typeof document === "undefined") {
|
|
184
|
+
console.log("[ugcinc-render/fonts] areFontsLoaded: Not in browser environment");
|
|
132
185
|
return false;
|
|
133
186
|
}
|
|
134
|
-
|
|
187
|
+
const tiktokRegular = document.fonts.check('normal 16px "TikTok Sans"');
|
|
188
|
+
const tiktokBold = document.fonts.check('bold 16px "TikTok Sans"');
|
|
189
|
+
const sfPro = document.fonts.check('normal 16px "SF Pro"');
|
|
190
|
+
const appleEmoji = document.fonts.check('normal 16px "Apple Color Emoji"');
|
|
191
|
+
console.log("[ugcinc-render/fonts] areFontsLoaded check:", {
|
|
192
|
+
tiktokRegular,
|
|
193
|
+
tiktokBold,
|
|
194
|
+
sfPro,
|
|
195
|
+
appleEmoji
|
|
196
|
+
});
|
|
197
|
+
return tiktokRegular && tiktokBold && sfPro && appleEmoji;
|
|
198
|
+
}
|
|
199
|
+
function debugFontStatus() {
|
|
200
|
+
console.log("[ugcinc-render/fonts] === FONT DEBUG STATUS ===");
|
|
201
|
+
if (typeof document === "undefined") {
|
|
202
|
+
console.log("[ugcinc-render/fonts] Not in browser environment");
|
|
203
|
+
return;
|
|
204
|
+
}
|
|
205
|
+
console.log("[ugcinc-render/fonts] Font checks:");
|
|
206
|
+
console.log(" - TikTok Sans (normal):", document.fonts.check('normal 16px "TikTok Sans"'));
|
|
207
|
+
console.log(" - TikTok Sans (bold):", document.fonts.check('bold 16px "TikTok Sans"'));
|
|
208
|
+
console.log(" - SF Pro:", document.fonts.check('normal 16px "SF Pro"'));
|
|
209
|
+
console.log(" - Apple Color Emoji:", document.fonts.check('normal 16px "Apple Color Emoji"'));
|
|
210
|
+
console.log("[ugcinc-render/fonts] All fonts in document.fonts:");
|
|
211
|
+
document.fonts.forEach((font) => {
|
|
212
|
+
console.log(` - ${font.family}: weight=${font.weight}, style=${font.style}, status=${font.status}`);
|
|
213
|
+
});
|
|
214
|
+
console.log("[ugcinc-render/fonts] Font family stacks:");
|
|
215
|
+
console.log(" - tiktok:", FONT_FAMILIES.tiktok);
|
|
216
|
+
console.log(" - apple:", FONT_FAMILIES.apple);
|
|
217
|
+
console.log(" - arial:", FONT_FAMILIES.arial);
|
|
218
|
+
console.log("[ugcinc-render/fonts] === END FONT DEBUG ===");
|
|
135
219
|
}
|
|
136
220
|
|
|
137
221
|
// src/utils/text.ts
|
|
@@ -218,66 +302,6 @@ function hexToRgba(hex, opacity = 100) {
|
|
|
218
302
|
return `rgba(${r}, ${g}, ${b}, ${opacity / 100})`;
|
|
219
303
|
}
|
|
220
304
|
|
|
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
|
-
function countEmojis(text) {
|
|
269
|
-
EMOJI_REGEX.lastIndex = 0;
|
|
270
|
-
const matches = text.match(EMOJI_REGEX);
|
|
271
|
-
return matches ? matches.length : 0;
|
|
272
|
-
}
|
|
273
|
-
function getEmojiWidth(fontSize) {
|
|
274
|
-
return fontSize * 1.2;
|
|
275
|
-
}
|
|
276
|
-
function stripEmojis(text) {
|
|
277
|
-
EMOJI_REGEX.lastIndex = 0;
|
|
278
|
-
return text.replace(EMOJI_REGEX, "");
|
|
279
|
-
}
|
|
280
|
-
|
|
281
305
|
// src/components/TextElement.tsx
|
|
282
306
|
import { jsx, jsxs } from "react/jsx-runtime";
|
|
283
307
|
function calculateAutoWidthAndLines({
|
|
@@ -310,17 +334,9 @@ function calculateAutoWidthAndLines({
|
|
|
310
334
|
white-space: nowrap;
|
|
311
335
|
`;
|
|
312
336
|
document.body.appendChild(measureSpan);
|
|
313
|
-
const
|
|
314
|
-
|
|
315
|
-
|
|
316
|
-
if (emojiCount === 0) {
|
|
317
|
-
measureSpan.textContent = textToMeasure;
|
|
318
|
-
return measureSpan.getBoundingClientRect().width;
|
|
319
|
-
}
|
|
320
|
-
const textWithoutEmojis = stripEmojis(textToMeasure);
|
|
321
|
-
measureSpan.textContent = textWithoutEmojis;
|
|
322
|
-
const textWidth = measureSpan.getBoundingClientRect().width;
|
|
323
|
-
return textWidth + emojiCount * emojiWidth;
|
|
337
|
+
const measureText = (textToMeasure) => {
|
|
338
|
+
measureSpan.textContent = textToMeasure;
|
|
339
|
+
return measureSpan.getBoundingClientRect().width;
|
|
324
340
|
};
|
|
325
341
|
measureSpan.textContent = "M";
|
|
326
342
|
const charWidth = measureSpan.getBoundingClientRect().width;
|
|
@@ -344,12 +360,12 @@ function calculateAutoWidthAndLines({
|
|
|
344
360
|
continue;
|
|
345
361
|
}
|
|
346
362
|
const testLine = currentLine + word;
|
|
347
|
-
const testWidth =
|
|
363
|
+
const testWidth = measureText(testLine);
|
|
348
364
|
const WRAP_TOLERANCE = 0.5;
|
|
349
365
|
if (testWidth > availableWidth + WRAP_TOLERANCE && currentLine.trim()) {
|
|
350
366
|
lines.push(currentLine.trimEnd());
|
|
351
367
|
currentLine = word;
|
|
352
|
-
const wordWidth =
|
|
368
|
+
const wordWidth = measureText(word);
|
|
353
369
|
if (wordWidth > availableWidth) {
|
|
354
370
|
let remainingWord = word;
|
|
355
371
|
while (remainingWord) {
|
|
@@ -383,7 +399,7 @@ function calculateAutoWidthAndLines({
|
|
|
383
399
|
}
|
|
384
400
|
let widestLineWidth = 0;
|
|
385
401
|
for (const line of lines) {
|
|
386
|
-
const lineWidth =
|
|
402
|
+
const lineWidth = measureText(line);
|
|
387
403
|
widestLineWidth = Math.max(widestLineWidth, lineWidth);
|
|
388
404
|
}
|
|
389
405
|
document.body.removeChild(measureSpan);
|
|
@@ -391,6 +407,15 @@ function calculateAutoWidthAndLines({
|
|
|
391
407
|
return { width: calculatedWidth, lines };
|
|
392
408
|
}
|
|
393
409
|
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]);
|
|
394
419
|
const fontType = segment.fontType ?? TEXT_DEFAULTS.fontType;
|
|
395
420
|
const fontSize = (segment.fontSize ?? TEXT_DEFAULTS.fontSize) * scale;
|
|
396
421
|
const fontWeight = segment.fontWeight ?? TEXT_DEFAULTS.fontWeight;
|
|
@@ -590,35 +615,9 @@ function TextElement({ segment, scale = 1 }) {
|
|
|
590
615
|
autoWidth,
|
|
591
616
|
verticalAlign
|
|
592
617
|
]);
|
|
593
|
-
const renderTextWithEmojis = (text) => {
|
|
594
|
-
if (!hasEmoji(text)) {
|
|
595
|
-
return text;
|
|
596
|
-
}
|
|
597
|
-
const segments = splitTextAndEmojis(text);
|
|
598
|
-
return segments.map((segment2, i) => {
|
|
599
|
-
if (segment2.type === "emoji" && segment2.imageUrl) {
|
|
600
|
-
return /* @__PURE__ */ jsx(
|
|
601
|
-
"img",
|
|
602
|
-
{
|
|
603
|
-
src: segment2.imageUrl,
|
|
604
|
-
alt: segment2.content,
|
|
605
|
-
style: {
|
|
606
|
-
height: "1.2em",
|
|
607
|
-
width: "1.2em",
|
|
608
|
-
verticalAlign: "-0.25em",
|
|
609
|
-
display: "inline"
|
|
610
|
-
},
|
|
611
|
-
draggable: false
|
|
612
|
-
},
|
|
613
|
-
i
|
|
614
|
-
);
|
|
615
|
-
}
|
|
616
|
-
return /* @__PURE__ */ jsx(React.Fragment, { children: segment2.content }, i);
|
|
617
|
-
});
|
|
618
|
-
};
|
|
619
618
|
if (autoWidth) {
|
|
620
619
|
const textContent = calculatedLines.map((line, index) => /* @__PURE__ */ jsxs(React.Fragment, { children: [
|
|
621
|
-
|
|
620
|
+
line,
|
|
622
621
|
index < calculatedLines.length - 1 && /* @__PURE__ */ jsx("br", {})
|
|
623
622
|
] }, index));
|
|
624
623
|
if (backgroundColor) {
|
|
@@ -637,7 +636,7 @@ function TextElement({ segment, scale = 1 }) {
|
|
|
637
636
|
}
|
|
638
637
|
return /* @__PURE__ */ jsx("div", { style: positioningContainerStyle, children: /* @__PURE__ */ jsx("div", { style: { width: calculatedWidth, maxWidth: width }, children: /* @__PURE__ */ jsx("div", { style: textStyle, children: textContent }) }) });
|
|
639
638
|
}
|
|
640
|
-
return /* @__PURE__ */ jsx("div", { style: positioningContainerStyle, children: /* @__PURE__ */ jsx("div", { style: backgroundBoxStyle, children: /* @__PURE__ */ jsx("div", { style: textStyle, children:
|
|
639
|
+
return /* @__PURE__ */ jsx("div", { style: positioningContainerStyle, children: /* @__PURE__ */ jsx("div", { style: backgroundBoxStyle, children: /* @__PURE__ */ jsx("div", { style: textStyle, children: segment.text }) }) });
|
|
641
640
|
}
|
|
642
641
|
|
|
643
642
|
// src/components/ImageElement.tsx
|
|
@@ -1930,6 +1929,7 @@ var RenderRoot = () => {
|
|
|
1930
1929
|
] });
|
|
1931
1930
|
};
|
|
1932
1931
|
export {
|
|
1932
|
+
APPLE_EMOJI_FONT,
|
|
1933
1933
|
DIMENSION_PRESETS,
|
|
1934
1934
|
FONT_FAMILIES,
|
|
1935
1935
|
FONT_URLS,
|
|
@@ -1955,12 +1955,11 @@ export {
|
|
|
1955
1955
|
calculateLineWidth,
|
|
1956
1956
|
calculateTimelineContentEnd,
|
|
1957
1957
|
canSetAsReference,
|
|
1958
|
+
debugFontStatus,
|
|
1958
1959
|
defaultOffset,
|
|
1959
|
-
emojiToUnified,
|
|
1960
1960
|
formatTime,
|
|
1961
1961
|
generateOverlayId,
|
|
1962
1962
|
generateSegmentId,
|
|
1963
|
-
getAppleEmojiUrl,
|
|
1964
1963
|
getBaseSegments,
|
|
1965
1964
|
getBorderRadii,
|
|
1966
1965
|
getDependentElements,
|
|
@@ -1969,7 +1968,6 @@ export {
|
|
|
1969
1968
|
getReferenceElementX,
|
|
1970
1969
|
getReferenceElementY,
|
|
1971
1970
|
getSegmentTimelinePosition,
|
|
1972
|
-
hasEmoji,
|
|
1973
1971
|
hexToRgba,
|
|
1974
1972
|
isDynamicCropEnabled,
|
|
1975
1973
|
isSegmentVisibleAtTime,
|
|
@@ -1977,7 +1975,6 @@ export {
|
|
|
1977
1975
|
parseTime,
|
|
1978
1976
|
preloadFonts,
|
|
1979
1977
|
resolveElementPositions,
|
|
1980
|
-
splitTextAndEmojis,
|
|
1981
1978
|
useFontsLoaded,
|
|
1982
1979
|
useImageLoader,
|
|
1983
1980
|
useImagePreloader,
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "ugcinc-render",
|
|
3
|
-
"version": "1.5.
|
|
3
|
+
"version": "1.5.17",
|
|
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",
|