Skip to content

Commit 0f4a14d

Browse files
committed
✨(frontend) prevent duplicate emoji when used as first character in title
ensures icon and title are visually distinct in sub-document headers Signed-off-by: Cyril <c.gromoff@gmail.com>
1 parent 6314cb3 commit 0f4a14d

File tree

3 files changed

+21
-11
lines changed

3 files changed

+21
-11
lines changed

CHANGELOG.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,7 @@ and this project adheres to
1919
- 🐛(docx) fix image overflow by limiting width to 600px during export #1525
2020
- 🐛(frontend) preserve @ character when esc is pressed after typing it #1512
2121
- 🐛(frontend) fix pdf embed to use full width #1526
22+
- 🐛(frontend) prevent duplicate emoji when used as first character in t… #1595
2223

2324
## [3.9.0] - 2025-11-10
2425

src/frontend/apps/impress/src/features/docs/doc-header/components/DocTitle.tsx

Lines changed: 14 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -122,15 +122,22 @@ const DocTitleInput = ({ doc }: DocTitleProps) => {
122122
if (isTopRoot) {
123123
const sanitizedTitle = updateDocTitle(doc, inputText);
124124
setTitleDisplay(sanitizedTitle);
125+
return sanitizedTitle;
125126
} else {
126-
const sanitizedTitle = updateDocTitle(
127-
doc,
128-
emoji ? `${emoji} ${inputText}` : inputText,
129-
);
127+
const { emoji: pastedEmoji } = getEmojiAndTitle(inputText);
128+
const textPreservingPastedEmoji = pastedEmoji
129+
? `\u200B${inputText}`
130+
: inputText;
131+
const finalTitle = emoji
132+
? `${emoji} ${textPreservingPastedEmoji}`
133+
: textPreservingPastedEmoji;
134+
135+
const sanitizedTitle = updateDocTitle(doc, finalTitle);
130136
const { titleWithoutEmoji: sanitizedTitleWithoutEmoji } =
131137
getEmojiAndTitle(sanitizedTitle);
132138

133139
setTitleDisplay(sanitizedTitleWithoutEmoji);
140+
return sanitizedTitleWithoutEmoji;
134141
}
135142
},
136143
[updateDocTitle, doc, emoji, isTopRoot],
@@ -168,9 +175,9 @@ const DocTitleInput = ({ doc }: DocTitleProps) => {
168175
suppressContentEditableWarning={true}
169176
aria-label={`${t('Document title')}`}
170177
aria-multiline={false}
171-
onBlurCapture={(event) =>
172-
handleTitleSubmit(event.target.textContent || '')
173-
}
178+
onBlurCapture={(event) => {
179+
handleTitleSubmit(event.target.textContent || '');
180+
}}
174181
$color={colorsTokens['greyscale-1000']}
175182
$padding={{ right: 'big' }}
176183
$css={css`

src/frontend/apps/impress/src/features/docs/doc-management/utils.ts

Lines changed: 6 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -26,12 +26,14 @@ export const getEmojiAndTitle = (title: string) => {
2626
// Use emoji-regex library for comprehensive emoji detection compatible with ES5
2727
const regex = emojiRegex();
2828

29-
// Check if the title starts with an emoji
30-
const match = title.match(regex);
29+
// Ignore leading spaces when checking for a leading emoji
30+
const leadingSpacesLength = title.match(/^\s+/)?.[0]?.length ?? 0;
31+
const trimmedStart = title.slice(leadingSpacesLength);
32+
const match = trimmedStart.match(regex);
3133

32-
if (match && title.startsWith(match[0])) {
34+
if (match && trimmedStart.startsWith(match[0])) {
3335
const emoji = match[0];
34-
const titleWithoutEmoji = title.substring(emoji.length).trim();
36+
const titleWithoutEmoji = trimmedStart.substring(emoji.length).trim();
3537
return { emoji, titleWithoutEmoji };
3638
}
3739

0 commit comments

Comments
 (0)