You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

functions.ts 2.7KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495
  1. import GraphemeSplitter from 'grapheme-splitter';
  2. import { split } from 'lodash-es';
  3. const AVATAR_COLORS = [
  4. '#6A50D3',
  5. '#FF9B42',
  6. '#DF486F',
  7. '#73348C',
  8. '#B23683',
  9. '#F96E57',
  10. '#4380E2',
  11. '#238561',
  12. '#00A8B3'
  13. ];
  14. const wordSplitRegex = (/\s+|\.+|_+|;+|-+|,+|\|+|\/+|\\+|"+|'+|\(+|\)+|#+|&+/);
  15. const splitter = new GraphemeSplitter();
  16. /**
  17. * Generates the background color of an initials based avatar.
  18. *
  19. * @param {string?} initials - The initials of the avatar.
  20. * @param {Array<string>} customAvatarBackgrounds - Custom avatar background values.
  21. * @returns {string}
  22. */
  23. export function getAvatarColor(initials: string | undefined, customAvatarBackgrounds: Array<string>) {
  24. const hasCustomAvatarBackgronds = customAvatarBackgrounds?.length;
  25. const colorsBase = hasCustomAvatarBackgronds ? customAvatarBackgrounds : AVATAR_COLORS;
  26. let colorIndex = 0;
  27. if (initials) {
  28. let nameHash = 0;
  29. for (const s of initials) {
  30. nameHash += Number(s.codePointAt(0));
  31. }
  32. colorIndex = nameHash % colorsBase.length;
  33. }
  34. return colorsBase[colorIndex];
  35. }
  36. /**
  37. * Returns the first grapheme from a word, uppercased.
  38. *
  39. * @param {string} word - The string to get grapheme from.
  40. * @returns {string}
  41. */
  42. function getFirstGraphemeUpper(word: string) {
  43. if (!word?.length) {
  44. return '';
  45. }
  46. return splitter.splitGraphemes(word)[0].toUpperCase();
  47. }
  48. /**
  49. * Generates initials for a simple string.
  50. *
  51. * @param {string?} s - The string to generate initials for.
  52. * @returns {string?}
  53. */
  54. export function getInitials(s?: string) {
  55. // We don't want to use the domain part of an email address, if it is one
  56. const initialsBasis = split(s, '@')[0];
  57. const [ firstWord, secondWord ] = initialsBasis.split(wordSplitRegex).filter(Boolean);
  58. return getFirstGraphemeUpper(firstWord) + getFirstGraphemeUpper(secondWord);
  59. }
  60. /**
  61. * Checks if the passed URL should be loaded with CORS.
  62. *
  63. * @param {string | Function} url - The URL (on mobile we use a specific Icon component for avatars).
  64. * @param {Array<string>} corsURLs - The URL pattern that matches a URL that needs to be handled with CORS.
  65. * @returns {boolean}
  66. */
  67. export function isCORSAvatarURL(url: string | Function, corsURLs: Array<string> = []): boolean {
  68. if (typeof url === 'function') {
  69. return false;
  70. }
  71. return corsURLs.some(pattern => url.startsWith(pattern));
  72. }
  73. /**
  74. * Checks if the passed prop is a loaded icon or not.
  75. *
  76. * @param {string? | Object?} iconProp - The prop to check.
  77. * @returns {boolean}
  78. */
  79. export function isIcon(iconProp?: string | Function): iconProp is Function {
  80. return Boolean(iconProp) && (typeof iconProp === 'object' || typeof iconProp === 'function');
  81. }