Skip to content

Commit

Permalink
IMP-208: Add isEmojiSupported util fn (#295)
Browse files Browse the repository at this point in the history
  • Loading branch information
KeinAsylum authored Apr 11, 2024
1 parent 39d97e6 commit d281114
Show file tree
Hide file tree
Showing 4 changed files with 104 additions and 8 deletions.
1 change: 1 addition & 0 deletions src/common/utils/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,7 @@ export { detectLocale } from './detectLocale';
export { createRegExpForMetaPattern } from './createRegExpForMetaPattern';
export { formatCard } from './formatCard';
export { truncate } from './truncate';
export { isEmojiSupported } from './isEmojiSupported';

export type { URLParams } from './getUrlParams';
export type { CountrySubdivision, Country } from './countries';
51 changes: 51 additions & 0 deletions src/common/utils/isEmojiSupported.test.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,51 @@
import { isEmojiSupported } from './isEmojiSupported';

describe('isEmojiSupported', () => {
let ctx;

beforeEach(() => {
// Mock the canvas context
ctx = {
fillStyle: '',
fillRect: jest.fn(),
textBaseline: '',
font: '',
fillText: jest.fn(),
getImageData: jest.fn(),
};
// Setup to return a fake image data array
ctx.getImageData.mockReturnValue({
data: new Uint8ClampedArray(32 * 32 * 4).fill(0), // All pixels transparent
});
// Mock canvas creation
document.createElement = jest.fn().mockReturnValue({
getContext: () => ctx,
width: 32,
height: 32,
});
});

test('should detect supported emoji by checking non-transparent pixels', () => {
// Mocking the context to simulate an emoji being supported (non-transparent pixels)
ctx.getImageData.mockReturnValue({
data: new Uint8ClampedArray(32 * 32 * 4).fill(255), // All pixels non-transparent
});

expect(isEmojiSupported('😊')).toBe(true);
});

test('should detect unsupported emoji by checking all transparent pixels', () => {
// Using the initial all-transparent setup by default

expect(isEmojiSupported('😊')).toBe(false);
});

test('should handle null canvas context gracefully', () => {
// Simulate canvas context not being available
(document.createElement as any).mockReturnValue({
getContext: () => null,
});

expect(isEmojiSupported('😊')).toBe(false);
});
});
37 changes: 37 additions & 0 deletions src/common/utils/isEmojiSupported.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
import { isNil } from './isNil';

// Tests flag emoji
export function isEmojiSupported(emoji: string): boolean {
if (isNil(emoji)) {
return false;
}
const canvas = document.createElement('canvas');
canvas.width = canvas.height = 32; // The size should be large enough to hold the emoji
const ctx = canvas.getContext('2d');
if (!ctx) {
return false; // In case the browser doesn't support canvas
}

ctx.fillStyle = 'white'; // Background color
ctx.fillRect(0, 0, 32, 32); // Fill the background
ctx.textBaseline = 'top';
ctx.font = '32px Arial'; // A common font that may not support the emoji

ctx.fillText(emoji, 0, 0); // Draw the emoji on the canvas

const imageData = ctx.getImageData(0, 0, canvas.width, canvas.height).data;

let isSupported = false;

// Loop through pixel data; every four items in the array represent the RGBA values of a pixel
for (let i = 0; i < imageData.length; i += 4) {
const alpha = imageData[i + 3]; // Get the alpha value of the pixel
if (alpha > 0) {
// Check if the pixel is not completely transparent
isSupported = true;
break;
}
}

return isSupported;
}
23 changes: 15 additions & 8 deletions src/components/ViewContainer/LocaleSelector.tsx
Original file line number Diff line number Diff line change
@@ -1,8 +1,9 @@
import { ChevronDownIcon } from '@chakra-ui/icons';
import { Flex, Menu, MenuButton, MenuItem, MenuList, Text } from '@chakra-ui/react';
import { useContext, useEffect, useState } from 'react';
import { useContext, useEffect, useMemo, useState } from 'react';

import { CustomizationContext, Locale } from 'checkout/contexts';
import { isEmojiSupported } from 'checkout/utils';

import { useLocale } from './useLocale';

Expand Down Expand Up @@ -68,13 +69,17 @@ export function LocaleSelector({ onLocaleChange }: LocaleSelectorProps) {
}
}, [localeState, activeLocaleCode]);

const isEmojiAvailable = useMemo(() => isEmojiSupported('🏳️'), []);

return (
<Menu isLazy>
<Menu>
<MenuButton color="white">
<Flex alignItems="center" gap="1">
<Text as="span" fontSize="md">
{localeInfo[activeLocaleCode]?.flag || '🏳️'}
</Text>
{isEmojiAvailable && (
<Text as="span" fontSize="md">
{localeInfo[activeLocaleCode]?.flag}
</Text>
)}
<Text color="white" fontSize="md" fontWeight="bold">
{localeInfo[activeLocaleCode]?.short || activeLocaleCode}
</Text>
Expand All @@ -91,9 +96,11 @@ export function LocaleSelector({ onLocaleChange }: LocaleSelectorProps) {
}}
>
<Flex alignItems="center" gap="3">
<Text as="span" fontSize="xl">
{flag}
</Text>
{isEmojiAvailable && (
<Text as="span" fontSize="xl">
{flag}
</Text>
)}
<Text fontSize="md">{long}</Text>
</Flex>
</MenuItem>
Expand Down

0 comments on commit d281114

Please sign in to comment.