ugcinc 4.5.65 → 4.5.67
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.
|
@@ -46,6 +46,20 @@ const defaults_1 = require("../utils/defaults");
|
|
|
46
46
|
const fonts_1 = require("../utils/fonts");
|
|
47
47
|
const text_1 = require("../utils/text");
|
|
48
48
|
const emoji_1 = require("../utils/emoji");
|
|
49
|
+
/**
|
|
50
|
+
* Render text with emojis wrapped in spans — used by BOTH fill and stroke
|
|
51
|
+
* divs so they share identical DOM structure and vertical metrics.
|
|
52
|
+
* In the stroke layer, emoji spans get visibility:hidden so the SVG filter
|
|
53
|
+
* doesn't dilate them.
|
|
54
|
+
*/
|
|
55
|
+
function renderTextWithEmojiSpans(text, hideEmojis) {
|
|
56
|
+
const parts = (0, emoji_1.splitTextAndEmojis)(text);
|
|
57
|
+
if (parts.every(p => p.type === 'text'))
|
|
58
|
+
return text;
|
|
59
|
+
return parts.map((part, i) => part.type === 'emoji'
|
|
60
|
+
? (0, jsx_runtime_1.jsx)("span", { style: hideEmojis ? { visibility: 'hidden' } : undefined, children: part.content }, i)
|
|
61
|
+
: (0, jsx_runtime_1.jsx)(react_1.default.Fragment, { children: part.content }, i));
|
|
62
|
+
}
|
|
49
63
|
/**
|
|
50
64
|
* Calculate the actual width for auto-width text AND the line breaks.
|
|
51
65
|
* Uses DOM-based measurement to ensure the same fonts are used as CSS rendering.
|
|
@@ -350,49 +364,24 @@ function TextElement({ segment, scale = 1 }) {
|
|
|
350
364
|
const strokeTextStyle = (0, react_1.useMemo)(() => {
|
|
351
365
|
if (!hasStroke)
|
|
352
366
|
return undefined;
|
|
353
|
-
|
|
367
|
+
return {
|
|
354
368
|
...textStyle,
|
|
355
369
|
color: strokeColor,
|
|
356
370
|
filter: `url(#${filterId})`,
|
|
357
371
|
position: 'absolute',
|
|
372
|
+
zIndex: 0,
|
|
358
373
|
top: 0,
|
|
359
374
|
left: 0,
|
|
360
375
|
right: 0,
|
|
361
376
|
bottom: 0,
|
|
362
377
|
};
|
|
363
|
-
|
|
364
|
-
}, [hasStroke, textStyle, strokeColor, filterId, strokeWidth, paddingTop, paddingRight, paddingBottom, paddingLeft]);
|
|
365
|
-
if (hasStroke) {
|
|
366
|
-
console.log('[TextElement] STROKE_DIAG:', JSON.stringify({
|
|
367
|
-
text: segment.text.substring(0, 30),
|
|
368
|
-
strokeWidth,
|
|
369
|
-
fontSize,
|
|
370
|
-
fillZ: textStyle.zIndex,
|
|
371
|
-
fillPos: textStyle.position,
|
|
372
|
-
strokeZ: strokeTextStyle?.zIndex,
|
|
373
|
-
strokePos: strokeTextStyle?.position,
|
|
374
|
-
strokeFilter: strokeTextStyle?.filter,
|
|
375
|
-
autoWidth,
|
|
376
|
-
hasBg: !!backgroundColor,
|
|
377
|
-
}));
|
|
378
|
-
}
|
|
378
|
+
}, [hasStroke, textStyle, strokeColor, filterId]);
|
|
379
379
|
// SVG filter for smooth text outline (avoids miter spikes from -webkit-text-stroke)
|
|
380
380
|
const strokePadPct = Math.max(50, Math.ceil((strokeWidth / fontSize) * 200));
|
|
381
381
|
const strokeFilterSvg = hasStroke ? ((0, jsx_runtime_1.jsx)("svg", { style: { position: 'absolute', width: 0, height: 0, overflow: 'hidden' }, "aria-hidden": "true", children: (0, jsx_runtime_1.jsx)("defs", { children: (0, jsx_runtime_1.jsxs)("filter", { id: filterId, x: `-${strokePadPct}%`, y: `-${strokePadPct}%`, width: `${100 + 2 * strokePadPct}%`, height: `${100 + 2 * strokePadPct}%`, children: [(0, jsx_runtime_1.jsx)("feMorphology", { in: "SourceAlpha", operator: "dilate", radius: strokeWidth, result: "dilated" }), (0, jsx_runtime_1.jsx)("feFlood", { floodColor: strokeColor, result: "color" }), (0, jsx_runtime_1.jsx)("feComposite", { in: "color", in2: "dilated", operator: "in" })] }) }) })) : null;
|
|
382
|
-
// Render text with emojis made invisible (opacity 0) so the stroke
|
|
383
|
-
// filter doesn't dilate around them. Emojis still occupy space to
|
|
384
|
-
// keep layout identical to the fill layer.
|
|
385
|
-
const renderStrokeText = (text) => {
|
|
386
|
-
const parts = (0, emoji_1.splitTextAndEmojis)(text);
|
|
387
|
-
if (parts.every(p => p.type === 'text'))
|
|
388
|
-
return text;
|
|
389
|
-
return parts.map((part, i) => part.type === 'emoji'
|
|
390
|
-
? (0, jsx_runtime_1.jsx)("span", { style: { visibility: 'hidden' }, children: part.content }, i)
|
|
391
|
-
: (0, jsx_runtime_1.jsx)(react_1.default.Fragment, { children: part.content }, i));
|
|
392
|
-
};
|
|
393
382
|
if (autoWidth) {
|
|
394
|
-
const
|
|
395
|
-
const strokeContent = calculatedLines.map((line, index) => ((0, jsx_runtime_1.jsxs)(react_1.default.Fragment, { children: [
|
|
383
|
+
const fillContent = calculatedLines.map((line, index) => ((0, jsx_runtime_1.jsxs)(react_1.default.Fragment, { children: [hasStroke ? renderTextWithEmojiSpans(line, false) : line, index < calculatedLines.length - 1 && (0, jsx_runtime_1.jsx)("br", {})] }, index)));
|
|
384
|
+
const strokeContent = hasStroke ? calculatedLines.map((line, index) => ((0, jsx_runtime_1.jsxs)(react_1.default.Fragment, { children: [renderTextWithEmojiSpans(line, true), index < calculatedLines.length - 1 && (0, jsx_runtime_1.jsx)("br", {})] }, index))) : null;
|
|
396
385
|
if (backgroundColor) {
|
|
397
386
|
return ((0, jsx_runtime_1.jsx)("div", { style: positioningContainerStyle, children: (0, jsx_runtime_1.jsxs)("div", { style: {
|
|
398
387
|
width: calculatedWidth,
|
|
@@ -400,10 +389,10 @@ function TextElement({ segment, scale = 1 }) {
|
|
|
400
389
|
backgroundColor: (0, text_1.hexToRgba)(backgroundColor, backgroundOpacity),
|
|
401
390
|
borderRadius: borderRadiusStyle,
|
|
402
391
|
...(hasStroke && { position: 'relative' }),
|
|
403
|
-
}, children: [strokeFilterSvg, strokeTextStyle && (0, jsx_runtime_1.jsx)("div", { style: strokeTextStyle, "aria-hidden": "true", children: strokeContent }), (0, jsx_runtime_1.jsx)("div", { style: textStyle, children:
|
|
392
|
+
}, children: [strokeFilterSvg, strokeTextStyle && (0, jsx_runtime_1.jsx)("div", { style: strokeTextStyle, "aria-hidden": "true", children: strokeContent }), (0, jsx_runtime_1.jsx)("div", { style: textStyle, children: fillContent })] }) }));
|
|
404
393
|
}
|
|
405
|
-
return ((0, jsx_runtime_1.jsx)("div", { style: positioningContainerStyle, children: (0, jsx_runtime_1.jsxs)("div", { style: { width: calculatedWidth, maxWidth: width, ...(hasStroke && { position: 'relative' }) }, children: [strokeFilterSvg, strokeTextStyle && (0, jsx_runtime_1.jsx)("div", { style: strokeTextStyle, "aria-hidden": "true", children: strokeContent }), (0, jsx_runtime_1.jsx)("div", { style: textStyle, children:
|
|
394
|
+
return ((0, jsx_runtime_1.jsx)("div", { style: positioningContainerStyle, children: (0, jsx_runtime_1.jsxs)("div", { style: { width: calculatedWidth, maxWidth: width, ...(hasStroke && { position: 'relative' }) }, children: [strokeFilterSvg, strokeTextStyle && (0, jsx_runtime_1.jsx)("div", { style: strokeTextStyle, "aria-hidden": "true", children: strokeContent }), (0, jsx_runtime_1.jsx)("div", { style: textStyle, children: fillContent })] }) }));
|
|
406
395
|
}
|
|
407
|
-
return ((0, jsx_runtime_1.jsx)("div", { style: positioningContainerStyle, children: (0, jsx_runtime_1.jsxs)("div", { style: { ...backgroundBoxStyle, ...(hasStroke && { position: 'relative' }) }, children: [strokeFilterSvg, strokeTextStyle && (0, jsx_runtime_1.jsx)("div", { style: strokeTextStyle, "aria-hidden": "true", children:
|
|
396
|
+
return ((0, jsx_runtime_1.jsx)("div", { style: positioningContainerStyle, children: (0, jsx_runtime_1.jsxs)("div", { style: { ...backgroundBoxStyle, ...(hasStroke && { position: 'relative' }) }, children: [strokeFilterSvg, strokeTextStyle && (0, jsx_runtime_1.jsx)("div", { style: strokeTextStyle, "aria-hidden": "true", children: hasStroke ? renderTextWithEmojiSpans(segment.text, true) : segment.text }), (0, jsx_runtime_1.jsx)("div", { style: textStyle, children: hasStroke ? renderTextWithEmojiSpans(segment.text, false) : segment.text })] }) }));
|
|
408
397
|
}
|
|
409
398
|
exports.default = TextElement;
|