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
- /** Shared inline style for emoji spans prevents line breaks */
166
- const emojiSpanStyle = {
167
- display: 'inline',
168
- whiteSpace: 'pre-wrap',
169
- };
170
- /** Stroke layer emoji span same structure as fill but invisible to the SVG filter */
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
- * Render text with emojis wrapped in spans.
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 emoji span style.
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
- return parts.map((part, i) => part.type === 'emoji'
186
- ? (0, jsx_runtime_1.jsx)("span", { style: style, children: part.content }, i)
187
- : part.content);
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:
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "ugcinc",
3
- "version": "4.5.72",
3
+ "version": "4.5.73",
4
4
  "description": "TypeScript/JavaScript client for the UGC Inc API",
5
5
  "main": "dist/index.js",
6
6
  "types": "dist/index.d.ts",