ugcinc 4.5.72 → 4.5.73
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.
|
@@ -162,29 +162,61 @@ function calculateAutoWidthAndLines({ text, maxWidth, paddingLeft, paddingRight,
|
|
|
162
162
|
const calculatedWidth = Math.min(widestLineWidth + paddingLeft + paddingRight, maxWidth);
|
|
163
163
|
return { width: calculatedWidth, lines };
|
|
164
164
|
}
|
|
165
|
-
/**
|
|
166
|
-
const
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
const emojiSpanStrokeStyle = {
|
|
172
|
-
...emojiSpanStyle,
|
|
173
|
-
opacity: 0,
|
|
174
|
-
};
|
|
165
|
+
/** Word Joiner (U+2060) — zero-width character that prevents line breaks */
|
|
166
|
+
const WJ = '\u2060';
|
|
167
|
+
/** Style for emoji spans in the fill layer — no visual change */
|
|
168
|
+
const emojiSpanStyle = { display: 'inline' };
|
|
169
|
+
/** Style for emoji spans in the stroke layer — hidden from SVG filter */
|
|
170
|
+
const emojiSpanStrokeStyle = { display: 'inline', opacity: 0 };
|
|
175
171
|
/**
|
|
176
|
-
*
|
|
172
|
+
* Group consecutive parts from splitTextAndEmojis into merged groups.
|
|
173
|
+
* Consecutive emoji parts are joined into a single group so they share one span,
|
|
174
|
+
* reducing break opportunities.
|
|
175
|
+
*/
|
|
176
|
+
function groupEmojiParts(parts) {
|
|
177
|
+
const groups = [];
|
|
178
|
+
for (const part of parts) {
|
|
179
|
+
const last = groups[groups.length - 1];
|
|
180
|
+
if (last && last.type === part.type) {
|
|
181
|
+
last.content += part.content;
|
|
182
|
+
}
|
|
183
|
+
else {
|
|
184
|
+
groups.push({ type: part.type, content: part.content });
|
|
185
|
+
}
|
|
186
|
+
}
|
|
187
|
+
return groups;
|
|
188
|
+
}
|
|
189
|
+
/**
|
|
190
|
+
* Render text with emojis wrapped in spans + Word Joiners at span boundaries.
|
|
191
|
+
*
|
|
177
192
|
* Both fill and stroke divs use this so they have identical DOM structure
|
|
178
|
-
* (matching vertical metrics). The only difference is the
|
|
193
|
+
* (matching vertical metrics and line breaks). The only difference is the
|
|
194
|
+
* emoji span style: fill spans are visible, stroke spans have opacity: 0.
|
|
195
|
+
*
|
|
196
|
+
* Word Joiners (U+2060) are inserted at boundaries between text nodes and
|
|
197
|
+
* emoji spans to prevent the browser from introducing break opportunities
|
|
198
|
+
* that don't exist in the original plain text.
|
|
179
199
|
*/
|
|
180
200
|
function renderTextWithEmojiSpans(text, forStroke) {
|
|
181
201
|
if (!(0, emoji_1.hasEmoji)(text))
|
|
182
202
|
return text;
|
|
183
203
|
const parts = (0, emoji_1.splitTextAndEmojis)(text);
|
|
204
|
+
const groups = groupEmojiParts(parts);
|
|
184
205
|
const style = forStroke ? emojiSpanStrokeStyle : emojiSpanStyle;
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
206
|
+
const result = [];
|
|
207
|
+
for (let i = 0; i < groups.length; i++) {
|
|
208
|
+
const group = groups[i];
|
|
209
|
+
// Insert Word Joiner between adjacent groups to prevent unwanted line breaks
|
|
210
|
+
if (i > 0)
|
|
211
|
+
result.push(WJ);
|
|
212
|
+
if (group.type === 'emoji') {
|
|
213
|
+
result.push((0, jsx_runtime_1.jsx)("span", { style: style, children: group.content }, i));
|
|
214
|
+
}
|
|
215
|
+
else {
|
|
216
|
+
result.push(group.content);
|
|
217
|
+
}
|
|
218
|
+
}
|
|
219
|
+
return result;
|
|
188
220
|
}
|
|
189
221
|
/**
|
|
190
222
|
* TextElement renders text with full styling support including:
|