Skip to content

Commit

Permalink
feat: emojis in the input value will be converted to images
Browse files Browse the repository at this point in the history
  • Loading branch information
cesarwbr committed Apr 3, 2024
1 parent 303018b commit be7e4cc
Show file tree
Hide file tree
Showing 6 changed files with 61 additions and 9 deletions.
1 change: 1 addition & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -80,6 +80,7 @@ export default function Example() {
| `onResize` | function | - | A callback function that is invoked when the width or height of the input element changes. It receives the current size value as its argument. |
| `placeholder` | string | "Type a message" | Specifies the placeholder text to be displayed when the input is empty. |
| `placeholderColor` | string | "#C4C4C4" | Specifies the color of the placeholder text. Accepts any valid CSS color value. |
| `shouldConvertEmojiToImage` | boolean | false | When set to true, emojis in the input value will be converted to images. |
| `shouldReturn` | boolean | - | When set to true, allows the user to create a new line using the `Shift + Enter` or `Ctrl + Enter` keyboard shortcuts. |
| `theme` | string | - | Specifies the theme for the emoji picker popup. Available values: "light", "dark", "auto". |
| `value` | string | "" | The current value of the input element. |
Expand Down
8 changes: 8 additions & 0 deletions example/src/App.js
Original file line number Diff line number Diff line change
Expand Up @@ -327,6 +327,14 @@ export default function App() {
Allows the user to use the <Code inline>Shift + Enter</Code> or <Code inline>Ctrl + Enter</Code> keyboard shortcut to create a new line.
</TableTd>
</TableTr>
<TableTr>
<TableTd>
<Code>shouldConvertEmojiToImage</Code>
</TableTd>
<TableTd>
Defaults to false. If set to true, emojis will be converted to images in the result.
</TableTd>
</TableTr>
<TableTr>
<TableTd>
<Code>value</Code>
Expand Down
3 changes: 2 additions & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -78,6 +78,7 @@
"dependencies": {
"@emoji-mart/data": "1.1.2",
"@emoji-mart/react": "1.1.1",
"emoji-mart": "5.5.2"
"emoji-mart": "5.5.2",
"react-easy-emoji": "^1.8.1"
}
}
5 changes: 3 additions & 2 deletions src/hooks/use-expose.js
Original file line number Diff line number Diff line change
Expand Up @@ -9,14 +9,15 @@ import { useSanitize } from "./use-sanitize";
* @property {React.MutableRefObject<import('../text-input').Ref | null>} textInputRef
* @property {(value: string) => void} setValue
* @property {() => void} emitChange
* @property {boolean=} shouldConvertEmojiToImage
*/

/**
*
* @param {Props} props
*/
export function useExpose({ ref, textInputRef, setValue, emitChange }) {
const { sanitize, sanitizedTextRef } = useSanitize(false);
export function useExpose({ ref, textInputRef, setValue, emitChange, shouldConvertEmojiToImage }) {
const { sanitize, sanitizedTextRef } = useSanitize(false, shouldConvertEmojiToImage);

useImperativeHandle(ref, () => ({
get value() {
Expand Down
41 changes: 39 additions & 2 deletions src/hooks/use-sanitize.js
Original file line number Diff line number Diff line change
@@ -1,17 +1,24 @@
// @ts-check

import { useCallback, useRef } from "react";
import { renderToString } from 'react-dom/server'
import emoji from 'react-easy-emoji'
import { removeHtmlExceptBr } from "../utils/input-event-utils";

const EMOJI_REGEX = new RegExp(
/(?:[\u2700-\u27bf]|(?:\ud83c[\udde6-\uddff]){2}|[\ud800-\udbff][\udc00-\udfff])[\ufe0e\ufe0f]?(?:[\u0300-\u036f\ufe20-\ufe23\u20d0-\u20f0]|\ud83c[\udffb-\udfff])?(?:\u200d(?:[^\ud800-\udfff]|(?:\ud83c[\udde6-\uddff]){2}|[\ud800-\udbff][\udc00-\udfff])[\ufe0e\ufe0f]?(?:[\u0300-\u036f\ufe20-\ufe23\u20d0-\u20f0]|\ud83c[\udffb-\udfff])?)*/g
)

/**
* @typedef {import('../types/types').SanitizeFn} SanitizeFn
*/

// eslint-disable-next-line valid-jsdoc
/**
* @param {boolean} shouldReturn
* @param {boolean} shouldConvertEmojiToImage
*/
export function useSanitize(shouldReturn) {
export function useSanitize(shouldReturn, shouldConvertEmojiToImage) {
/** @type {React.MutableRefObject<SanitizeFn[]>} */
const sanitizeFnsRef = useRef([]);

Expand All @@ -30,10 +37,14 @@ export function useSanitize(shouldReturn) {

result = replaceAllHtmlToString(result, shouldReturn);

if (shouldConvertEmojiToImage) {
result = convertEmojiToImage(result);
}

sanitizedTextRef.current = result;

return result;
}, []);
}, [shouldReturn, shouldConvertEmojiToImage]);

return { addSanitizeFn, sanitize, sanitizedTextRef };
}
Expand All @@ -59,3 +70,29 @@ export function replaceAllHtmlToString(html, shouldReturn) {

return text;
}

/**
*
* @param {string} text
* @return {string}
*/
function convertEmojiToImage(text) {
text = handleEmoji(text)
text = renderToString(emoji(text))
text = text.replace(
new RegExp('&lt;span class=&quot;message-emoji&quot;&gt;', 'g'),
'<span class="message-emoji">'
)
text = text.replace(new RegExp('&lt;/span&gt;', 'g'), '</span>')

return text
}

/**
*
* @param {string} text
* @return {string}
*/
function handleEmoji (text) {
return text.replace(EMOJI_REGEX, '<span class="message-emoji">$&</span>')
}
12 changes: 8 additions & 4 deletions src/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -43,7 +43,7 @@ import { usePollute } from "./hooks/user-pollute";
* @property {() => void=} onClick
* @property {() => void=} onFocus
* @property {() => void=} onBlur
* @property {boolean=} shouldReturn
* @property {boolean} shouldReturn
* @property {number=} maxLength
* @property {boolean=} keepOpened
* @property {(event: KeyboardEvent) => void=} onKeyDown
Expand All @@ -61,6 +61,7 @@ import { usePollute } from "./hooks/user-pollute";
* @property {(text: string) => Promise<MetionUser[]>=} searchMention
* @property {HTMLDivElement=} buttonElement
* @property {React.MutableRefObject=} buttonRef
* @property {boolean} shouldConvertEmojiToImage
*/

/**
Expand All @@ -73,7 +74,6 @@ function InputEmoji(props, ref) {
const {
onChange,
onEnter,
shouldReturn,
onResize,
onClick,
onFocus,
Expand All @@ -93,6 +93,8 @@ function InputEmoji(props, ref) {
searchMention,
buttonElement,
buttonRef,
shouldReturn,
shouldConvertEmojiToImage,
// style
borderRadius,
borderColor,
Expand All @@ -108,7 +110,7 @@ function InputEmoji(props, ref) {

const { addEventListener, listeners } = useEventListeners();

const { addSanitizeFn, sanitize, sanitizedTextRef } = useSanitize(props.shouldReturn);
const { addSanitizeFn, sanitize, sanitizedTextRef } = useSanitize(shouldReturn, shouldConvertEmojiToImage);

const { addPolluteFn, pollute } = usePollute();

Expand Down Expand Up @@ -139,7 +141,8 @@ function InputEmoji(props, ref) {
ref,
setValue,
textInputRef,
emitChange
emitChange,
shouldConvertEmojiToImage
});

useEffect(() => {
Expand Down Expand Up @@ -360,6 +363,7 @@ InputEmojiWithRef.defaultProps = {
background: "white",
tabIndex: 0,
shouldReturn: false,
shouldConvertEmojiToImage: false,
customEmojis: [],
language: undefined,
};
Expand Down

0 comments on commit be7e4cc

Please sign in to comment.