diff --git a/package-lock.json b/package-lock.json index e4146478c..87ac5c65f 100644 --- a/package-lock.json +++ b/package-lock.json @@ -55,6 +55,7 @@ "dropbox": "10.7.0", "face-api.js": "0.22.2", "focus-visible": "5.1.0", + "grapheme-splitter": "1.0.4", "i18n-iso-countries": "6.8.0", "i18next": "17.0.6", "i18next-browser-languagedetector": "3.0.1", @@ -10820,6 +10821,11 @@ "node": ">=0.4.0" } }, + "node_modules/grapheme-splitter": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/grapheme-splitter/-/grapheme-splitter-1.0.4.tgz", + "integrity": "sha512-bzh50DW9kTPM00T8y4o8vQg89Di9oLJVLW/KaOGIXJWP/iqCN6WKYkbNOF04vFLJhwcpYUh9ydh/+5vpOqV4YQ==" + }, "node_modules/growly": { "version": "1.3.0", "resolved": "https://registry.npmjs.org/growly/-/growly-1.3.0.tgz", @@ -28639,6 +28645,11 @@ "resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.1.11.tgz", "integrity": "sha1-Dovf5NHduIVNZOBOp8AOKgJuVlg=" }, + "grapheme-splitter": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/grapheme-splitter/-/grapheme-splitter-1.0.4.tgz", + "integrity": "sha512-bzh50DW9kTPM00T8y4o8vQg89Di9oLJVLW/KaOGIXJWP/iqCN6WKYkbNOF04vFLJhwcpYUh9ydh/+5vpOqV4YQ==" + }, "growly": { "version": "1.3.0", "resolved": "https://registry.npmjs.org/growly/-/growly-1.3.0.tgz", diff --git a/package.json b/package.json index f21e61950..e6d5fb942 100644 --- a/package.json +++ b/package.json @@ -60,6 +60,7 @@ "dropbox": "10.7.0", "face-api.js": "0.22.2", "focus-visible": "5.1.0", + "grapheme-splitter": "1.0.4", "i18n-iso-countries": "6.8.0", "i18next": "17.0.6", "i18next-browser-languagedetector": "3.0.1", diff --git a/react/features/base/avatar/functions.js b/react/features/base/avatar/functions.js index 9e87c6ade..4aac4db0f 100644 --- a/react/features/base/avatar/functions.js +++ b/react/features/base/avatar/functions.js @@ -1,5 +1,6 @@ // @flow +import GraphemeSplitter from 'grapheme-splitter'; import _ from 'lodash'; const AVATAR_COLORS = [ @@ -13,6 +14,8 @@ const AVATAR_COLORS = [ '#2AA076', '#00A8B3' ]; +const wordSplitRegex = (/\s+|\.+|_+|;+|-+|,+|\|+|\/+|\\+/); +const splitter = new GraphemeSplitter(); /** * Generates the background color of an initials based avatar. @@ -40,6 +43,20 @@ export function getAvatarColor(initials: ?string, customAvatarBackgrounds: Array return colorsBase[colorIndex]; } +/** + * Returns the first grapheme from a word, uppercased. + * + * @param {string} word - The string to get grapheme from. + * @returns {string} + */ +function getFirstGraphemeUpper(word) { + if (!word?.length) { + return ''; + } + + return splitter.splitGraphemes(word)[0].toUpperCase(); +} + /** * Generates initials for a simple string. * @@ -49,12 +66,7 @@ export function getAvatarColor(initials: ?string, customAvatarBackgrounds: Array export function getInitials(s: ?string) { // We don't want to use the domain part of an email address, if it is one const initialsBasis = _.split(s, '@')[0]; - const words = _.words(initialsBasis); - let initials = ''; + const [ firstWord, secondWord ] = initialsBasis.split(wordSplitRegex); - for (const w of words) { - (initials.length < 2) && (initials += String.fromCodePoint(w.codePointAt(0)).toUpperCase()); - } - - return initials; + return getFirstGraphemeUpper(firstWord) + getFirstGraphemeUpper(secondWord); }