From 92c65f40dfee824eacf670baf4619b31b109097d Mon Sep 17 00:00:00 2001 From: Ian Sanders Date: Wed, 8 Mar 2023 22:45:25 +0000 Subject: [PATCH 1/5] Add support for custom emoji suggestions --- .../MarkdownEditor/MarkdownEditor.stories.tsx | 1 + .../suggestions/_useEmojiSuggestions.tsx | 24 +++++++++++++++---- 2 files changed, 21 insertions(+), 4 deletions(-) diff --git a/src/drafts/MarkdownEditor/MarkdownEditor.stories.tsx b/src/drafts/MarkdownEditor/MarkdownEditor.stories.tsx index f140894d2c2..de951a2eac9 100644 --- a/src/drafts/MarkdownEditor/MarkdownEditor.stories.tsx +++ b/src/drafts/MarkdownEditor/MarkdownEditor.stories.tsx @@ -163,6 +163,7 @@ const emojis: Emoji[] = [ {name: 'raised_hand', character: '✋'}, {name: 'thumbsup', character: '👍'}, {name: 'thumbsdown', character: '👎'}, + {name: 'octocat', url: 'https://github.githubassets.com/images/icons/emoji/octocat.png'}, ] const references: Reference[] = [ diff --git a/src/drafts/MarkdownEditor/suggestions/_useEmojiSuggestions.tsx b/src/drafts/MarkdownEditor/suggestions/_useEmojiSuggestions.tsx index c9e78942680..ec3108f1387 100644 --- a/src/drafts/MarkdownEditor/suggestions/_useEmojiSuggestions.tsx +++ b/src/drafts/MarkdownEditor/suggestions/_useEmojiSuggestions.tsx @@ -3,24 +3,40 @@ import {suggestionsCalculator, UseSuggestionsHook} from '.' import {ActionList} from '../../../ActionList' import {Suggestion, Trigger} from '../../InlineAutocomplete' -export type Emoji = { +type BaseEmoji = { /** Name (shortcode) of the emoji. Do not include the wrapping `:` symbols. */ name: string +} + +type UnicodeEmoji = BaseEmoji & { /** Unicode representation of the emoji. */ character: string } +type CustomEmoji = BaseEmoji & { + /** URL to an image of the emoji. */ + url: string +} + +export type Emoji = UnicodeEmoji | CustomEmoji + const trigger: Trigger = { triggerChar: ':', keepTriggerCharOnCommit: false, } const emojiToSugggestion = (emoji: Emoji): Suggestion => ({ - value: emoji.character, - key: emoji.name, // emoji characters may not be unique - ie haircut and haircut_man both have the same emoji codepoint. But names are guarunteed to be unique. + value: 'character' in emoji ? emoji.character : `:${emoji.name}:`, + key: emoji.name, // emoji characters may not be unique - ie haircut and haircut_man both have the same emoji codepoint. But names are guaranteed to be unique. render: props => ( - {emoji.character} + + {'character' in emoji ? ( + emoji.character + ) : ( + {`${emoji.name} + )} + {emoji.name} ), From 684cd19f1e218d6e799506cca43e39ecf25dd14e Mon Sep 17 00:00:00 2001 From: Ian Sanders Date: Thu, 9 Mar 2023 16:27:10 +0000 Subject: [PATCH 2/5] Allow declaratively setting suggestions as "loading" --- src/drafts/MarkdownEditor/suggestions/index.ts | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/src/drafts/MarkdownEditor/suggestions/index.ts b/src/drafts/MarkdownEditor/suggestions/index.ts index 664180f3438..a00939c8ffd 100644 --- a/src/drafts/MarkdownEditor/suggestions/index.ts +++ b/src/drafts/MarkdownEditor/suggestions/index.ts @@ -2,11 +2,11 @@ import {Suggestion, Trigger} from '../../InlineAutocomplete' const MAX_SUGGESTIONS = 5 -export type SuggestionOptions = T[] | (() => Promise) +export type SuggestionOptions = T[] | (() => Promise) | 'loading' export type UseSuggestionsHook = (options: SuggestionOptions) => { trigger: Trigger - calculateSuggestions: (query: string) => Promise + calculateSuggestions: (query: string) => Promise } export const suggestionsCalculator = @@ -16,6 +16,8 @@ export const suggestionsCalculator = toSuggestion: (option: T) => Suggestion, ) => async (query: string) => { + if (options === 'loading') return 'loading' + const optionsArray = Array.isArray(options) ? options : await options() // If the query is empty, scores will be -INFINITY From 0892f6262fc5e746b4b6a16fb4e3d4412f1cab0b Mon Sep 17 00:00:00 2001 From: Ian Sanders Date: Thu, 9 Mar 2023 11:32:29 -0500 Subject: [PATCH 3/5] Create .changeset/wise-months-taste.md --- .changeset/wise-months-taste.md | 5 +++++ 1 file changed, 5 insertions(+) create mode 100644 .changeset/wise-months-taste.md diff --git a/.changeset/wise-months-taste.md b/.changeset/wise-months-taste.md new file mode 100644 index 00000000000..d60d758db09 --- /dev/null +++ b/.changeset/wise-months-taste.md @@ -0,0 +1,5 @@ +--- +"@primer/react": patch +--- + +Add support for custom emojis and a declarative "loading" state in `MarkdownEditor` suggestions From 00e4be7a2082bab1d8049cf44b203b7e6c4fa08d Mon Sep 17 00:00:00 2001 From: Ian Sanders Date: Thu, 9 Mar 2023 16:44:38 +0000 Subject: [PATCH 4/5] Add test for custom emoji --- .../MarkdownEditor/MarkdownEditor.test.tsx | 16 ++++++++++++++-- 1 file changed, 14 insertions(+), 2 deletions(-) diff --git a/src/drafts/MarkdownEditor/MarkdownEditor.test.tsx b/src/drafts/MarkdownEditor/MarkdownEditor.test.tsx index b946c373b6c..19a418d3780 100644 --- a/src/drafts/MarkdownEditor/MarkdownEditor.test.tsx +++ b/src/drafts/MarkdownEditor/MarkdownEditor.test.tsx @@ -866,13 +866,14 @@ describe('MarkdownEditor', () => { }) describe('suggestions', () => { - const emojis: Emoji[] = [ + const emojis = [ {name: '+1', character: '👍'}, {name: '-1', character: '👎'}, {name: 'heart', character: '❤️'}, {name: 'wave', character: '👋'}, {name: 'raised_hands', character: '🙌'}, - ] + {name: 'octocat', url: 'https://github.githubassets.com/images/icons/emoji/octocat.png'}, + ] satisfies Emoji[] const mentionables: Mentionable[] = [ {identifier: 'monalisa', description: 'Monalisa Octocat'}, @@ -1076,6 +1077,17 @@ describe('MarkdownEditor', () => { expect(getAllSuggestions()[0]).toHaveTextContent('+1') expect(getAllSuggestions()[1]).toHaveTextContent('-1') }) + + it('inserts shortcode for custom emojis', async () => { + const {queryForSuggestionsList, getAllSuggestions, getInput, user} = await render() + + const input = getInput() + await user.type(input, `Mona Lisa :octo`) + await user.click(getAllSuggestions()[0]) + + expect(input.value).toBe(`Mona Lisa :octocat: `) + expect(queryForSuggestionsList()).not.toBeInTheDocument() + }) }) describe('saved replies', () => { From 19f6833244010265e00f38505a46c14197018bf6 Mon Sep 17 00:00:00 2001 From: Ian Sanders Date: Thu, 9 Mar 2023 16:52:21 +0000 Subject: [PATCH 5/5] Remove `satisfies` (seems to be unsupported by Jest's transpiler) --- src/drafts/MarkdownEditor/MarkdownEditor.test.tsx | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/drafts/MarkdownEditor/MarkdownEditor.test.tsx b/src/drafts/MarkdownEditor/MarkdownEditor.test.tsx index 19a418d3780..ce0b57c93c4 100644 --- a/src/drafts/MarkdownEditor/MarkdownEditor.test.tsx +++ b/src/drafts/MarkdownEditor/MarkdownEditor.test.tsx @@ -4,7 +4,7 @@ import userEvent from '@testing-library/user-event' import {UserEvent} from '@testing-library/user-event/dist/types/setup/setup' import React, {forwardRef, useRef, useState} from 'react' import {act} from 'react-dom/test-utils' -import MarkdownEditor, {Emoji, MarkdownEditorHandle, MarkdownEditorProps, Mentionable, Reference, SavedReply} from '.' +import MarkdownEditor, {MarkdownEditorHandle, MarkdownEditorProps, Mentionable, Reference, SavedReply} from '.' import ThemeProvider from '../../ThemeProvider' declare const REACT_VERSION_LATEST: boolean @@ -873,7 +873,7 @@ describe('MarkdownEditor', () => { {name: 'wave', character: '👋'}, {name: 'raised_hands', character: '🙌'}, {name: 'octocat', url: 'https://github.githubassets.com/images/icons/emoji/octocat.png'}, - ] satisfies Emoji[] + ] const mentionables: Mentionable[] = [ {identifier: 'monalisa', description: 'Monalisa Octocat'},