From c410a5857312c90d2e5f0265289ebf0f24ea2aa6 Mon Sep 17 00:00:00 2001 From: Philip Molares Date: Fri, 7 Aug 2020 18:54:37 +0200 Subject: [PATCH] Add emoji picker (#329) * Added emoji-mart as emoji-picker * Fixed JSON to TypeScript-object parsing * added fork awesome to emoji-picker added ForkAwesomeIcons enum, because it's not possible to iterate over a typescript type consisting of strings [1]. This is a bit unfortunate since we now have two lists of all the fork awesome icons, but sadly it can not be done another way. added fork awesome as a custom category to the emoji picker. [1]: https://stackoverflow.com/questions/40863488/how-to-iterate-over-a-custom-literal-type-in-typescript * made picker close, when clicking away added react-use dependency for useClickAway hook * Fixed emoji-picker loading images from unpkg instead of using font * fixed addEmoji function added tests * Extract customIcons into useMemo Signed-off-by: Tilman Vatteroth Co-authored-by: Erik Michelson Co-authored-by: Tilman Vatteroth --- CHANGELOG.md | 1 + package.json | 5 +- public/img/forkawesome.png | Bin 0 -> 32532 bytes .../tool-bar/emoji-picker/emoji-picker.scss | 8 + .../tool-bar/emoji-picker/emoji-picker.tsx | 47 ++ .../tool-bar/emoji-picker/icon-names.ts | 760 ++++++++++++++++++ .../editor-window/tool-bar/tool-bar.tsx | 127 +-- .../editor-window/tool-bar/utils.test.ts | 191 +++++ .../editor/editor-window/tool-bar/utils.ts | 22 + yarn.lock | 236 +++++- 10 files changed, 1321 insertions(+), 76 deletions(-) create mode 100644 public/img/forkawesome.png create mode 100644 src/components/editor/editor-window/tool-bar/emoji-picker/emoji-picker.scss create mode 100644 src/components/editor/editor-window/tool-bar/emoji-picker/emoji-picker.tsx create mode 100644 src/components/editor/editor-window/tool-bar/emoji-picker/icon-names.ts diff --git a/CHANGELOG.md b/CHANGELOG.md index 7643c5ad1..75459f821 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -34,6 +34,7 @@ - CodiMD instances can now be branded either with a '@ ' or '@ ' after the CodiMD logo and text - Images will be loaded via proxy if an image proxy is configured in the backend - Asciinema videos may now be embedded by pasting the URL of one video into a single line +- The Toolbar includes an EmojiPicker ### Changed diff --git a/package.json b/package.json index 76d19cd22..333966b17 100644 --- a/package.json +++ b/package.json @@ -8,6 +8,7 @@ "@testing-library/user-event": "12.1.0", "@types/codemirror": "0.0.97", "@types/deep-equal": "1.0.1", + "@types/emoji-mart": "3.0.2", "@types/highlight.js": "9.12.4", "@types/jest": "26.0.8", "@types/js-yaml": "3.12.5", @@ -31,6 +32,7 @@ "bootstrap": "4.5.0", "codemirror": "5.56.0", "deep-equal": "2.0.3", + "emoji-mart": "3.0.0", "eslint-config-react-app": "5.2.1", "eslint-config-standard": "14.1.1", "eslint-plugin-flowtype": "5.2.0", @@ -80,8 +82,9 @@ "react-router-bootstrap": "0.25.0", "react-router-dom": "5.2.0", "react-scripts": "3.4.1", + "react-use": "15.3.3", "redux": "4.0.5", - "ts-mockery": "^1.2.0", + "ts-mockery": "1.2.0", "typescript": "3.9.7", "use-media": "1.4.0", "use-resize-observer": "6.1.0" diff --git a/public/img/forkawesome.png b/public/img/forkawesome.png new file mode 100644 index 0000000000000000000000000000000000000000..c1a97679575f6114ef523fdfc5b996f3eee449ea GIT binary patch literal 32532 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 void + onDismiss: () => void +} + +export const EmojiPicker: React.FC = ({ show, onEmojiSelected, onDismiss }) => { + const pickerRef = useRef(null) + const customIcons = useMemo(() => + Object.keys(ForkAwesomeIcons).map((name) => ({ + name: `fa-${name}`, + short_names: [`fa-${name.toLowerCase()}`], + text: '', + emoticons: [], + keywords: ['fork awesome'], + imageUrl: '/img/forkawesome.png', + customCategory: 'ForkAwesome' + })), []) + + useClickAway(pickerRef, () => { + onDismiss() + }) + + return ( + +
+ +
+
+ ) +} diff --git a/src/components/editor/editor-window/tool-bar/emoji-picker/icon-names.ts b/src/components/editor/editor-window/tool-bar/emoji-picker/icon-names.ts new file mode 100644 index 000000000..e9c21ecc8 --- /dev/null +++ b/src/components/editor/editor-window/tool-bar/emoji-picker/icon-names.ts @@ -0,0 +1,760 @@ +export enum ForkAwesomeIcons { + '500px'='500px', + 'activitypub'='activitypub', + 'address-book-o'='address-book-o', + 'address-book'='address-book', + 'address-card-o'='address-card-o', + 'address-card'='address-card', + 'adjust'='adjust', + 'adn'='adn', + 'align-center'='align-center', + 'align-justify'='align-justify', + 'align-left'='align-left', + 'align-right'='align-right', + 'amazon'='amazon', + 'ambulance'='ambulance', + 'american-sign-language-interpreting'='american-sign-language-interpreting', + 'anchor'='anchor', + 'android'='android', + 'angellist'='angellist', + 'angle-double-down'='angle-double-down', + 'angle-double-left'='angle-double-left', + 'angle-double-right'='angle-double-right', + 'angle-double-up'='angle-double-up', + 'angle-down'='angle-down', + 'angle-left'='angle-left', + 'angle-right'='angle-right', + 'angle-up'='angle-up', + 'apple'='apple', + 'archive-org'='archive-org', + 'archive'='archive', + 'archlinux'='archlinux', + 'area-chart'='area-chart', + 'arrow-circle-down'='arrow-circle-down', + 'arrow-circle-left'='arrow-circle-left', + 'arrow-circle-o-down'='arrow-circle-o-down', + 'arrow-circle-o-left'='arrow-circle-o-left', + 'arrow-circle-o-right'='arrow-circle-o-right', + 'arrow-circle-o-up'='arrow-circle-o-up', + 'arrow-circle-right'='arrow-circle-right', + 'arrow-circle-up'='arrow-circle-up', + 'arrow-down'='arrow-down', + 'arrow-left'='arrow-left', + 'arrow-right'='arrow-right', + 'arrows-alt'='arrows-alt', + 'arrows-h'='arrows-h', + 'arrows'='arrows', + 'arrows-v'='arrows-v', + 'arrow-up'='arrow-up', + 'artstation'='artstation', + 'assistive-listening-systems'='assistive-listening-systems', + 'asterisk'='asterisk', + 'at'='at', + 'att'='att', + 'audio-description'='audio-description', + 'backward'='backward', + 'balance-scale'='balance-scale', + 'bandcamp'='bandcamp', + 'ban'='ban', + 'bar-chart'='bar-chart', + 'barcode'='barcode', + 'bars'='bars', + 'bath'='bath', + 'battery-empty'='battery-empty', + 'battery-full'='battery-full', + 'battery-half'='battery-half', + 'battery-quarter'='battery-quarter', + 'battery-three-quarters'='battery-three-quarters', + 'bed'='bed', + 'beer'='beer', + 'behance-square'='behance-square', + 'behance'='behance', + 'bell-o'='bell-o', + 'bell-rigning-o'='bell-rigning-o', + 'bell-ringing'='bell-ringing', + 'bell-slash-o'='bell-slash-o', + 'bell-slash'='bell-slash', + 'bell'='bell', + 'bicycle'='bicycle', + 'binoculars'='binoculars', + 'biometric'='biometric', + 'birthday-cake'='birthday-cake', + 'bitbucket-square'='bitbucket-square', + 'bitbucket'='bitbucket', + 'black-tie'='black-tie', + 'blind'='blind', + 'bluetooth-b'='bluetooth-b', + 'bluetooth'='bluetooth', + 'bold'='bold', + 'bolt'='bolt', + 'bomb'='bomb', + 'bookmark-o'='bookmark-o', + 'bookmark'='bookmark', + 'book'='book', + 'bootstrap'='bootstrap', + 'braille'='braille', + 'briefcase'='briefcase', + 'btc'='btc', + 'bug'='bug', + 'building-o'='building-o', + 'building'='building', + 'bullhorn'='bullhorn', + 'bullseye'='bullseye', + 'bus'='bus', + 'buysellads'='buysellads', + 'calculator'='calculator', + 'calendar-check-o'='calendar-check-o', + 'calendar-minus-o'='calendar-minus-o', + 'calendar-o'='calendar-o', + 'calendar-plus-o'='calendar-plus-o', + 'calendar'='calendar', + 'calendar-times-o'='calendar-times-o', + 'camera-retro'='camera-retro', + 'camera'='camera', + 'caret-down'='caret-down', + 'caret-left'='caret-left', + 'caret-right'='caret-right', + 'caret-square-o-down'='caret-square-o-down', + 'caret-square-o-left'='caret-square-o-left', + 'caret-square-o-right'='caret-square-o-right', + 'caret-square-o-up'='caret-square-o-up', + 'caret-up'='caret-up', + 'car'='car', + 'cart-arrow-down'='cart-arrow-down', + 'cart-plus'='cart-plus', + 'cc-amex'='cc-amex', + 'cc-diners-club'='cc-diners-club', + 'cc-discover'='cc-discover', + 'cc-jcb'='cc-jcb', + 'cc-mastercard'='cc-mastercard', + 'cc-paypal'='cc-paypal', + 'cc-stripe'='cc-stripe', + 'cc'='cc', + 'cc-visa'='cc-visa', + 'certificate'='certificate', + 'chain-broken'='chain-broken', + 'check-circle-o'='check-circle-o', + 'check-circle'='check-circle', + 'check-square-o'='check-square-o', + 'check-square'='check-square', + 'check'='check', + 'chevron-circle-down'='chevron-circle-down', + 'chevron-circle-left'='chevron-circle-left', + 'chevron-circle-right'='chevron-circle-right', + 'chevron-circle-up'='chevron-circle-up', + 'chevron-down'='chevron-down', + 'chevron-left'='chevron-left', + 'chevron-right'='chevron-right', + 'chevron-up'='chevron-up', + 'child'='child', + 'chrome'='chrome', + 'circle-o-notch'='circle-o-notch', + 'circle-o'='circle-o', + 'circle'='circle', + 'circle-thin'='circle-thin', + 'classicpress-circle'='classicpress-circle', + 'classicpress'='classicpress', + 'clipboard'='clipboard', + 'clock-o'='clock-o', + 'clone'='clone', + 'cloud-download'='cloud-download', + 'cloud'='cloud', + 'cloud-upload'='cloud-upload', + 'code-fork'='code-fork', + 'codepen'='codepen', + 'code'='code', + 'codiepie'='codiepie', + 'coffee'='coffee', + 'cogs'='cogs', + 'cog'='cog', + 'columns'='columns', + 'commenting-o'='commenting-o', + 'commenting'='commenting', + 'comment-o'='comment-o', + 'comments-o'='comments-o', + 'comments'='comments', + 'comment'='comment', + 'compass'='compass', + 'compress'='compress', + 'connectdevelop'='connectdevelop', + 'contao'='contao', + 'copyright'='copyright', + 'creative-commons'='creative-commons', + 'credit-card-alt'='credit-card-alt', + 'credit-card'='credit-card', + 'crop'='crop', + 'crosshairs'='crosshairs', + 'css3'='css3', + 'c'='c', + 'cubes'='cubes', + 'cube'='cube', + 'cutlery'='cutlery', + 'dashcube'='dashcube', + 'database'='database', + 'deaf'='deaf', + 'debian'='debian', + 'delicious'='delicious', + 'desktop'='desktop', + 'deviantart'='deviantart', + 'dev-to'='dev-to', + 'diamond'='diamond', + 'diaspora'='diaspora', + 'digg'='digg', + 'digitalocean'='digitalocean', + 'discord-alt'='discord-alt', + 'discord'='discord', + 'dogmazic'='dogmazic', + 'dot-circle-o'='dot-circle-o', + 'download'='download', + 'dribbble'='dribbble', + 'dropbox'='dropbox', + 'drupal'='drupal', + 'edge'='edge', + 'eercast'='eercast', + 'eject'='eject', + 'ellipsis-h'='ellipsis-h', + 'ellipsis-v'='ellipsis-v', + 'emby'='emby', + 'empire'='empire', + 'envelope-open-o'='envelope-open-o', + 'envelope-open'='envelope-open', + 'envelope-o'='envelope-o', + 'envelope-square'='envelope-square', + 'envelope'='envelope', + 'envira'='envira', + 'eraser'='eraser', + 'ethereum'='ethereum', + 'etsy'='etsy', + 'eur'='eur', + 'exchange'='exchange', + 'exclamation-circle'='exclamation-circle', + 'exclamation'='exclamation', + 'exclamation-triangle'='exclamation-triangle', + 'expand'='expand', + 'expeditedssl'='expeditedssl', + 'external-link-square'='external-link-square', + 'external-link'='external-link', + 'eyedropper'='eyedropper', + 'eye-slash'='eye-slash', + 'eye'='eye', + 'facebook-messenger'='facebook-messenger', + 'facebook-official'='facebook-official', + 'facebook-square'='facebook-square', + 'facebook'='facebook', + 'fast-backward'='fast-backward', + 'fast-forward'='fast-forward', + 'fax'='fax', + 'f-droid'='f-droid', + 'female'='female', + 'ffmpeg'='ffmpeg', + 'fighter-jet'='fighter-jet', + 'file-archive-o'='file-archive-o', + 'file-audio-o'='file-audio-o', + 'file-code-o'='file-code-o', + 'file-epub'='file-epub', + 'file-excel-o'='file-excel-o', + 'file-image-o'='file-image-o', + 'file-o'='file-o', + 'file-pdf-o'='file-pdf-o', + 'file-powerpoint-o'='file-powerpoint-o', + 'files-o'='files-o', + 'file'='file', + 'file-text-o'='file-text-o', + 'file-text'='file-text', + 'file-video-o'='file-video-o', + 'file-word-o'='file-word-o', + 'film'='film', + 'filter'='filter', + 'fire-extinguisher'='fire-extinguisher', + 'firefox'='firefox', + 'fire'='fire', + 'first-order'='first-order', + 'flag-checkered'='flag-checkered', + 'flag-o'='flag-o', + 'flag'='flag', + 'flask'='flask', + 'flickr'='flickr', + 'floppy-o'='floppy-o', + 'folder-open-o'='folder-open-o', + 'folder-open'='folder-open', + 'folder-o'='folder-o', + 'folder'='folder', + 'font-awesome'='font-awesome', + 'fonticons'='fonticons', + 'font'='font', + 'fork-awesome'='fork-awesome', + 'fort-awesome'='fort-awesome', + 'forumbee'='forumbee', + 'forward'='forward', + 'foursquare'='foursquare', + 'free-code-camp'='free-code-camp', + 'freedombox'='freedombox', + 'friendica'='friendica', + 'frown-o'='frown-o', + 'funkwhale'='funkwhale', + 'futbol-o'='futbol-o', + 'gamepad'='gamepad', + 'gavel'='gavel', + 'gbp'='gbp', + 'genderless'='genderless', + 'get-pocket'='get-pocket', + 'gg-circle'='gg-circle', + 'gg'='gg', + 'gift'='gift', + 'gimp'='gimp', + 'gitea'='gitea', + 'github-alt'='github-alt', + 'github-square'='github-square', + 'github'='github', + 'gitlab'='gitlab', + 'git-square'='git-square', + 'git'='git', + 'glass'='glass', + 'glide-g'='glide-g', + 'glide'='glide', + 'globe-e'='globe-e', + 'globe'='globe', + 'globe-w'='globe-w', + 'gnupg'='gnupg', + 'gnu-social'='gnu-social', + 'google-plus-official'='google-plus-official', + 'google-plus-square'='google-plus-square', + 'google-plus'='google-plus', + 'google'='google', + 'google-wallet'='google-wallet', + 'graduation-cap'='graduation-cap', + 'gratipay'='gratipay', + 'grav'='grav', + 'hackaday'='hackaday', + 'hacker-news'='hacker-news', + 'hackster'='hackster', + 'hal'='hal', + 'hand-lizard-o'='hand-lizard-o', + 'hand-o-down'='hand-o-down', + 'hand-o-left'='hand-o-left', + 'hand-o-right'='hand-o-right', + 'hand-o-up'='hand-o-up', + 'hand-paper-o'='hand-paper-o', + 'hand-peace-o'='hand-peace-o', + 'hand-pointer-o'='hand-pointer-o', + 'hand-rock-o'='hand-rock-o', + 'hand-scissors-o'='hand-scissors-o', + 'handshake-o'='handshake-o', + 'hand-spock-o'='hand-spock-o', + 'hashnode'='hashnode', + 'hashtag'='hashtag', + 'hdd-o'='hdd-o', + 'header'='header', + 'headphones'='headphones', + 'heartbeat'='heartbeat', + 'heart-o'='heart-o', + 'heart'='heart', + 'history'='history', + 'home'='home', + 'hospital-o'='hospital-o', + 'hourglass-end'='hourglass-end', + 'hourglass-half'='hourglass-half', + 'hourglass-o'='hourglass-o', + 'hourglass-start'='hourglass-start', + 'hourglass'='hourglass', + 'houzz'='houzz', + 'h-square'='h-square', + 'html5'='html5', + 'hubzilla'='hubzilla', + 'i-cursor'='i-cursor', + 'id-badge'='id-badge', + 'id-card-o'='id-card-o', + 'id-card'='id-card', + 'ils'='ils', + 'imdb'='imdb', + 'inbox'='inbox', + 'indent'='indent', + 'industry'='industry', + 'info-circle'='info-circle', + 'info'='info', + 'inkscape'='inkscape', + 'inr'='inr', + 'instagram'='instagram', + 'internet-explorer'='internet-explorer', + 'ioxhost'='ioxhost', + 'italic'='italic', + 'jirafeau'='jirafeau', + 'joomla'='joomla', + 'joplin'='joplin', + 'jpy'='jpy', + 'jsfiddle'='jsfiddle', + 'julia'='julia', + 'jupyter'='jupyter', + 'keybase'='keybase', + 'keyboard-o'='keyboard-o', + 'key-modern'='key-modern', + 'key'='key', + 'krw'='krw', + 'language'='language', + 'laptop'='laptop', + 'laravel'='laravel', + 'lastfm-square'='lastfm-square', + 'lastfm'='lastfm', + 'leaf'='leaf', + 'leanpub'='leanpub', + 'lemon-o'='lemon-o', + 'level-down'='level-down', + 'level-up'='level-up', + 'liberapay-square'='liberapay-square', + 'liberapay'='liberapay', + 'life-ring'='life-ring', + 'lightbulb-o'='lightbulb-o', + 'line-chart'='line-chart', + 'linkedin-square'='linkedin-square', + 'linkedin'='linkedin', + 'link'='link', + 'linode'='linode', + 'linux'='linux', + 'list-alt'='list-alt', + 'list-ol'='list-ol', + 'list'='list', + 'list-ul'='list-ul', + 'location-arrow'='location-arrow', + 'lock'='lock', + 'long-arrow-down'='long-arrow-down', + 'long-arrow-left'='long-arrow-left', + 'long-arrow-right'='long-arrow-right', + 'long-arrow-up'='long-arrow-up', + 'low-vision'='low-vision', + 'magic'='magic', + 'magnet'='magnet', + 'male'='male', + 'map-marker'='map-marker', + 'map-o'='map-o', + 'map-pin'='map-pin', + 'map-signs'='map-signs', + 'map'='map', + 'mars-double'='mars-double', + 'mars-stroke-h'='mars-stroke-h', + 'mars-stroke'='mars-stroke', + 'mars-stroke-v'='mars-stroke-v', + 'mars'='mars', + 'mastodon-alt'='mastodon-alt', + 'mastodon-square'='mastodon-square', + 'mastodon'='mastodon', + 'matrix-org'='matrix-org', + 'maxcdn'='maxcdn', + 'meanpath'='meanpath', + 'medium-square'='medium-square', + 'medium'='medium', + 'medkit'='medkit', + 'meetup'='meetup', + 'meh-o'='meh-o', + 'mercury'='mercury', + 'microchip'='microchip', + 'microphone-slash'='microphone-slash', + 'microphone'='microphone', + 'minus-circle'='minus-circle', + 'minus-square-o'='minus-square-o', + 'minus-square'='minus-square', + 'minus'='minus', + 'mixcloud'='mixcloud', + 'mobile'='mobile', + 'modx'='modx', + 'money'='money', + 'moon-o'='moon-o', + 'moon'='moon', + 'motorcycle'='motorcycle', + 'mouse-pointer'='mouse-pointer', + 'music'='music', + 'neuter'='neuter', + 'newspaper-o'='newspaper-o', + 'nextcloud-square'='nextcloud-square', + 'nextcloud'='nextcloud', + 'nodejs'='nodejs', + 'object-group'='object-group', + 'object-ungroup'='object-ungroup', + 'odnoklassniki-square'='odnoklassniki-square', + 'odnoklassniki'='odnoklassniki', + 'opencart'='opencart', + 'open-collective'='open-collective', + 'openid'='openid', + 'opera'='opera', + 'optin-monster'='optin-monster', + 'orcid'='orcid', + 'outdent'='outdent', + 'pagelines'='pagelines', + 'paint-brush'='paint-brush', + 'paperclip'='paperclip', + 'paper-plane-o'='paper-plane-o', + 'paper-plane'='paper-plane', + 'paragraph'='paragraph', + 'patreon'='patreon', + 'pause-circle-o'='pause-circle-o', + 'pause-circle'='pause-circle', + 'pause'='pause', + 'paw'='paw', + 'paypal'='paypal', + 'peertube'='peertube', + 'pencil-square-o'='pencil-square-o', + 'pencil-square'='pencil-square', + 'pencil'='pencil', + 'percent'='percent', + 'phone-square'='phone-square', + 'phone'='phone', + 'php'='php', + 'picture-o'='picture-o', + 'pie-chart'='pie-chart', + 'pinterest-p'='pinterest-p', + 'pinterest-square'='pinterest-square', + 'pinterest'='pinterest', + 'pixelfed'='pixelfed', + 'plane'='plane', + 'play-circle-o'='play-circle-o', + 'play-circle'='play-circle', + 'play'='play', + 'pleroma'='pleroma', + 'plug'='plug', + 'plus-circle'='plus-circle', + 'plus-square-o'='plus-square-o', + 'plus-square'='plus-square', + 'plus'='plus', + 'podcast'='podcast', + 'power-off'='power-off', + 'print'='print', + 'product-hunt'='product-hunt', + 'puzzle-piece'='puzzle-piece', + 'python'='python', + 'qq'='qq', + 'qrcode'='qrcode', + 'question-circle-o'='question-circle-o', + 'question-circle'='question-circle', + 'question'='question', + 'quora'='quora', + 'quote-left'='quote-left', + 'quote-right'='quote-right', + 'random'='random', + 'ravelry'='ravelry', + 'react'='react', + 'rebel'='rebel', + 'recycle'='recycle', + 'reddit-alien'='reddit-alien', + 'reddit-square'='reddit-square', + 'reddit'='reddit', + 'refresh'='refresh', + 'registered'='registered', + 'renren'='renren', + 'repeat'='repeat', + 'reply-all'='reply-all', + 'reply'='reply', + 'researchgate'='researchgate', + 'retweet'='retweet', + 'road'='road', + 'rocket'='rocket', + 'rss-square'='rss-square', + 'rss'='rss', + 'rub'='rub', + 'safari'='safari', + 'scissors'='scissors', + 'scribd'='scribd', + 'scuttlebutt'='scuttlebutt', + 'search-minus'='search-minus', + 'search-plus'='search-plus', + 'search'='search', + 'sellsy'='sellsy', + 'server'='server', + 'shaarli-o'='shaarli-o', + 'shaarli'='shaarli', + 'share-alt-square'='share-alt-square', + 'share-alt'='share-alt', + 'share-square-o'='share-square-o', + 'share-square'='share-square', + 'share'='share', + 'shield'='shield', + 'ship'='ship', + 'shirtsinbulk'='shirtsinbulk', + 'shopping-bag'='shopping-bag', + 'shopping-basket'='shopping-basket', + 'shopping-cart'='shopping-cart', + 'shower'='shower', + 'signalapp'='signalapp', + 'signal'='signal', + 'sign-in'='sign-in', + 'sign-language'='sign-language', + 'sign-out'='sign-out', + 'simplybuilt'='simplybuilt', + 'sitemap'='sitemap', + 'skyatlas'='skyatlas', + 'skype'='skype', + 'slack'='slack', + 'sliders'='sliders', + 'slideshare'='slideshare', + 'smile-o'='smile-o', + 'snapchat-ghost'='snapchat-ghost', + 'snapchat-square'='snapchat-square', + 'snapchat'='snapchat', + 'snowdrift'='snowdrift', + 'snowflake-o'='snowflake-o', + 'social-home'='social-home', + 'sort-alpha-asc'='sort-alpha-asc', + 'sort-alpha-desc'='sort-alpha-desc', + 'sort-amount-asc'='sort-amount-asc', + 'sort-amount-desc'='sort-amount-desc', + 'sort-asc'='sort-asc', + 'sort-desc'='sort-desc', + 'sort-numeric-asc'='sort-numeric-asc', + 'sort-numeric-desc'='sort-numeric-desc', + 'sort'='sort', + 'soundcloud'='soundcloud', + 'space-shuttle'='space-shuttle', + 'spell-check'='spell-check', + 'spinner'='spinner', + 'spoon'='spoon', + 'spotify'='spotify', + 'square-o'='square-o', + 'square'='square', + 'stack-exchange'='stack-exchange', + 'stack-overflow'='stack-overflow', + 'star-half-o'='star-half-o', + 'star-half'='star-half', + 'star-o'='star-o', + 'star'='star', + 'steam-square'='steam-square', + 'steam'='steam', + 'step-backward'='step-backward', + 'step-forward'='step-forward', + 'stethoscope'='stethoscope', + 'sticky-note-o'='sticky-note-o', + 'sticky-note'='sticky-note', + 'stop-circle-o'='stop-circle-o', + 'stop-circle'='stop-circle', + 'stop'='stop', + 'street-view'='street-view', + 'strikethrough'='strikethrough', + 'stumbleupon-circle'='stumbleupon-circle', + 'stumbleupon'='stumbleupon', + 'subscript'='subscript', + 'subway'='subway', + 'suitcase'='suitcase', + 'sun-o'='sun-o', + 'sun'='sun', + 'superpowers'='superpowers', + 'superscript'='superscript', + 'syncthing'='syncthing', + 'table'='table', + 'tablet'='tablet', + 'tachometer'='tachometer', + 'tags'='tags', + 'tag'='tag', + 'tasks'='tasks', + 'taxi'='taxi', + 'telegram'='telegram', + 'television'='television', + 'tencent-weibo'='tencent-weibo', + 'terminal'='terminal', + 'text-height'='text-height', + 'text-width'='text-width', + 'themeisle'='themeisle', + 'thermometer-empty'='thermometer-empty', + 'thermometer-full'='thermometer-full', + 'thermometer-half'='thermometer-half', + 'thermometer-quarter'='thermometer-quarter', + 'thermometer-three-quarters'='thermometer-three-quarters', + 'th-large'='th-large', + 'th-list'='th-list', + 'th'='th', + 'thumbs-down'='thumbs-down', + 'thumbs-o-down'='thumbs-o-down', + 'thumbs-o-up'='thumbs-o-up', + 'thumbs-up'='thumbs-up', + 'thumb-tack'='thumb-tack', + 'ticket'='ticket', + 'times-circle-o'='times-circle-o', + 'times-circle'='times-circle', + 'times'='times', + 'tint'='tint', + 'tipeee'='tipeee', + 'toggle-off'='toggle-off', + 'toggle-on'='toggle-on', + 'tor-onion'='tor-onion', + 'trademark'='trademark', + 'train'='train', + 'transgender-alt'='transgender-alt', + 'transgender'='transgender', + 'trash-o'='trash-o', + 'trash'='trash', + 'tree'='tree', + 'trello'='trello', + 'tripadvisor'='tripadvisor', + 'trophy'='trophy', + 'truck'='truck', + 'try'='try', + 'tty'='tty', + 'tumblr-square'='tumblr-square', + 'tumblr'='tumblr', + 'twitch'='twitch', + 'twitter-square'='twitter-square', + 'twitter'='twitter', + 'umbrella'='umbrella', + 'underline'='underline', + 'undo'='undo', + 'universal-access'='universal-access', + 'university'='university', + 'unlock-alt'='unlock-alt', + 'unlock'='unlock', + 'unslpash'='unslpash', + 'upload'='upload', + 'usb'='usb', + 'usd'='usd', + 'user-circle-o'='user-circle-o', + 'user-circle'='user-circle', + 'user-md'='user-md', + 'user-o'='user-o', + 'user-plus'='user-plus', + 'user-secret'='user-secret', + 'users'='users', + 'user'='user', + 'user-times'='user-times', + 'venus-double'='venus-double', + 'venus-mars'='venus-mars', + 'venus'='venus', + 'viacoin'='viacoin', + 'viadeo-square'='viadeo-square', + 'viadeo'='viadeo', + 'video-camera'='video-camera', + 'vimeo-square'='vimeo-square', + 'vimeo'='vimeo', + 'vine'='vine', + 'vk'='vk', + 'volume-control-phone'='volume-control-phone', + 'volume-down'='volume-down', + 'volume-mute'='volume-mute', + 'volume-off'='volume-off', + 'volume-up'='volume-up', + 'weibo'='weibo', + 'weixin'='weixin', + 'whatsapp'='whatsapp', + 'wheelchair-alt'='wheelchair-alt', + 'wheelchair'='wheelchair', + 'wifi'='wifi', + 'wikidata'='wikidata', + 'wikipedia-w'='wikipedia-w', + 'window-close-o'='window-close-o', + 'window-close'='window-close', + 'window-maximize'='window-maximize', + 'window-minimize'='window-minimize', + 'window-restore'='window-restore', + 'windows'='windows', + 'wire'='wire', + 'wordpress'='wordpress', + 'wpbeginner'='wpbeginner', + 'wpexplorer'='wpexplorer', + 'wpforms'='wpforms', + 'wrench'='wrench', + 'xing-square'='xing-square', + 'xing'='xing', + 'xmpp'='xmpp', + 'yahoo'='yahoo', + 'y-combinator'='y-combinator', + 'yelp'='yelp', + 'yoast'='yoast', + 'youtube-play'='youtube-play', + 'youtube-square'='youtube-square', + 'youtube'='youtube', + 'zotero'='zotero' +} diff --git a/src/components/editor/editor-window/tool-bar/tool-bar.tsx b/src/components/editor/editor-window/tool-bar/tool-bar.tsx index afd693adc..dd59613d4 100644 --- a/src/components/editor/editor-window/tool-bar/tool-bar.tsx +++ b/src/components/editor/editor-window/tool-bar/tool-bar.tsx @@ -1,12 +1,14 @@ import { Editor } from 'codemirror' -import React from 'react' +import React, { Fragment, useState } from 'react' import { Button, ButtonToolbar } from 'react-bootstrap' import { useTranslation } from 'react-i18next' import { ForkAwesomeIcon } from '../../../common/fork-awesome/fork-awesome-icon' +import { EmojiPicker } from './emoji-picker/emoji-picker' import './tool-bar.scss' import { addCodeFences, addComment, + addEmoji, addHeaderLevel, addImage, addLine, @@ -30,6 +32,8 @@ export interface ToolBarProps { export const ToolBar: React.FC = ({ editor }) => { const { t } = useTranslation() + const [showEmojiPicker, setShowEmojiPicker] = useState(false) + const notImplemented = () => { alert('This feature is not yet implemented') } @@ -39,61 +43,70 @@ export const ToolBar: React.FC = ({ editor }) => { } return ( - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + { + setShowEmojiPicker(false) + addEmoji(emoji, editor) + }} onDismiss={() => setShowEmojiPicker(false)}/> + + + ) } diff --git a/src/components/editor/editor-window/tool-bar/utils.test.ts b/src/components/editor/editor-window/tool-bar/utils.test.ts index 2b93087b5..e09c4483f 100644 --- a/src/components/editor/editor-window/tool-bar/utils.test.ts +++ b/src/components/editor/editor-window/tool-bar/utils.test.ts @@ -1,8 +1,10 @@ import { Editor, Position, Range } from 'codemirror' +import { EmojiData } from 'emoji-mart' import { Mock } from 'ts-mockery' import { addCodeFences, addComment, + addEmoji, addHeaderLevel, addImage, addLine, @@ -1639,3 +1641,192 @@ describe('test addTable', () => { addTable(editor) }) }) + +describe('test addEmoji with native emoji', () => { + const { cursor, firstLine, multiline, multilineOffset } = buildRanges() + const textFirstLine = testContent.split('\n')[0] + const emoji = Mock.of({ + native: '👍' + }) + it('just cursor', done => { + Mock.extend(editor).with({ + listSelections: () => ( + Mock.of([{ + anchor: cursor.from, + head: cursor.to, + from: () => cursor.from, + to: () => cursor.to, + empty: () => true + }]) + ), + getLine: (): string => (textFirstLine), + replaceRange: (replacement: string | string[]) => { + expect(replacement).toEqual('👍') + done() + } + }) + addEmoji(emoji, editor) + }) + + it('1st line', done => { + Mock.extend(editor).with({ + listSelections: () => ( + Mock.of([{ + anchor: firstLine.from, + head: firstLine.to, + from: () => firstLine.from, + to: () => firstLine.to, + empty: () => false + }]) + ), + getLine: (): string => (textFirstLine), + replaceRange: (replacement: string | string[], from: CodeMirror.Position, to?: CodeMirror.Position) => { + expect(from).toEqual(firstLine.from) + expect(to).toEqual(firstLine.to) + expect(replacement).toEqual('👍') + done() + } + }) + addEmoji(emoji, editor) + }) + + it('multiple lines', done => { + Mock.extend(editor).with({ + listSelections: () => ( + Mock.of([{ + anchor: multiline.from, + head: multiline.to, + from: () => multiline.from, + to: () => multiline.to, + empty: () => false + }]) + ), + getLine: (): string => '2nd line', + replaceRange: (replacement: string | string[], from: CodeMirror.Position, to?: CodeMirror.Position) => { + expect(from).toEqual(multiline.from) + expect(to).toEqual(multiline.to) + expect(replacement).toEqual('👍') + done() + } + }) + addEmoji(emoji, editor) + }) + + it('multiple lines with offset', done => { + Mock.extend(editor).with({ + listSelections: () => ( + Mock.of([{ + anchor: multilineOffset.from, + head: multilineOffset.to, + from: () => multilineOffset.from, + to: () => multilineOffset.to, + empty: () => false + }]) + ), + getLine: (): string => '2nd line', + replaceRange: (replacement: string | string[], from: CodeMirror.Position, to?: CodeMirror.Position) => { + expect(from).toEqual(multilineOffset.from) + expect(to).toEqual(multilineOffset.to) + expect(replacement).toEqual('👍') + done() + } + }) + addEmoji(emoji, editor) + }) +}) + +describe('test addEmoji with native emoji', () => { + const { cursor, firstLine, multiline, multilineOffset } = buildRanges() + const textFirstLine = testContent.split('\n')[0] + // noinspection CheckTagEmptyBody + const forkAwesomeIcon = '' + const emoji = Mock.of({ + name: 'star', + imageUrl: '/img/forkawesome.png' + }) + it('just cursor', done => { + Mock.extend(editor).with({ + listSelections: () => ( + Mock.of([{ + anchor: cursor.from, + head: cursor.to, + from: () => cursor.from, + to: () => cursor.to, + empty: () => true + }]) + ), + getLine: (): string => (textFirstLine), + replaceRange: (replacement: string | string[]) => { + expect(replacement).toEqual(forkAwesomeIcon) + done() + } + }) + addEmoji(emoji, editor) + }) + + it('1st line', done => { + Mock.extend(editor).with({ + listSelections: () => ( + Mock.of([{ + anchor: firstLine.from, + head: firstLine.to, + from: () => firstLine.from, + to: () => firstLine.to, + empty: () => false + }]) + ), + getLine: (): string => (textFirstLine), + replaceRange: (replacement: string | string[], from: CodeMirror.Position, to?: CodeMirror.Position) => { + expect(from).toEqual(firstLine.from) + expect(to).toEqual(firstLine.to) + expect(replacement).toEqual(forkAwesomeIcon) + done() + } + }) + addEmoji(emoji, editor) + }) + + it('multiple lines', done => { + Mock.extend(editor).with({ + listSelections: () => ( + Mock.of([{ + anchor: multiline.from, + head: multiline.to, + from: () => multiline.from, + to: () => multiline.to, + empty: () => false + }]) + ), + getLine: (): string => '2nd line', + replaceRange: (replacement: string | string[], from: CodeMirror.Position, to?: CodeMirror.Position) => { + expect(from).toEqual(multiline.from) + expect(to).toEqual(multiline.to) + expect(replacement).toEqual(forkAwesomeIcon) + done() + } + }) + addEmoji(emoji, editor) + }) + + it('multiple lines with offset', done => { + Mock.extend(editor).with({ + listSelections: () => ( + Mock.of([{ + anchor: multilineOffset.from, + head: multilineOffset.to, + from: () => multilineOffset.from, + to: () => multilineOffset.to, + empty: () => false + }]) + ), + getLine: (): string => '2nd line', + replaceRange: (replacement: string | string[], from: CodeMirror.Position, to?: CodeMirror.Position) => { + expect(from).toEqual(multilineOffset.from) + expect(to).toEqual(multilineOffset.to) + expect(replacement).toEqual(forkAwesomeIcon) + done() + } + }) + addEmoji(emoji, editor) + }) +}) diff --git a/src/components/editor/editor-window/tool-bar/utils.ts b/src/components/editor/editor-window/tool-bar/utils.ts index 43e753fab..70a2bdf1b 100644 --- a/src/components/editor/editor-window/tool-bar/utils.ts +++ b/src/components/editor/editor-window/tool-bar/utils.ts @@ -1,4 +1,5 @@ import { Editor } from 'codemirror' +import { BaseEmoji, CustomEmoji, EmojiData } from 'emoji-mart' export const makeSelectionBold = (editor: Editor): void => wrapTextWith(editor, '**') export const makeSelectionItalic = (editor: Editor): void => wrapTextWith(editor, '*') @@ -22,6 +23,17 @@ export const addLine = (editor: Editor): void => changeLines(editor, line => `${ export const addComment = (editor: Editor): void => changeLines(editor, line => `${line}\n> []`) export const addTable = (editor: Editor): void => changeLines(editor, line => `${line}\n| Column 1 | Column 2 | Column 3 |\n| -------- | -------- | -------- |\n| Text | Text | Text |`) +export const addEmoji = (emoji: EmojiData, editor: Editor): void => { + let replacement = '' + if ((emoji as BaseEmoji).native) { + replacement = (emoji as BaseEmoji).native + } else if ((emoji as CustomEmoji).imageUrl) { + // noinspection CheckTagEmptyBody + replacement = `` + } + insertAtCursor(editor, replacement) +} + export const wrapTextWith = (editor: Editor, symbol: string, endSymbol?: string): void => { if (!editor.getSelection()) { return @@ -98,3 +110,13 @@ export const addLink = (editor: Editor, prefix?: string): void => { } } } + +export const insertAtCursor = (editor: Editor, text: string): void => { + const cursor = editor.getCursor() + const ranges = editor.listSelections() + for (const range of ranges) { + const from = range.empty() ? { line: cursor.line, ch: cursor.ch } : range.from() + const to = range.empty() ? { line: cursor.line, ch: cursor.ch } : range.to() + editor.replaceRange(`${text}`, from, to, '+input') + } +} diff --git a/yarn.lock b/yarn.lock index b6ce33ad6..af53aca65 100644 --- a/yarn.lock +++ b/yarn.lock @@ -1559,9 +1559,9 @@ "@types/testing-library__cypress" "^5.0.3" "@testing-library/dom@^7.0.2", "@testing-library/dom@^7.11.0", "@testing-library/dom@^7.17.1": - version "7.21.4" - resolved "https://registry.yarnpkg.com/@testing-library/dom/-/dom-7.21.4.tgz#24b045f3161b7c91fdb35da7c001908cdc99b55b" - integrity sha512-IXjKRTAH31nQ+mx6q3IPw85RTLul8VlWBm1rxURoxDt7JI0HPlAAfbtrKTdeq83XYCYO7HSHogyV+OsD+6FX0Q== + version "7.21.5" + resolved "https://registry.yarnpkg.com/@testing-library/dom/-/dom-7.21.5.tgz#d87312efc5039313f9ea246ed722d808f2ffcbb3" + integrity sha512-zZqC5T/9Upjs0/3hyrYNpGxw75dr/bLLD27pUdb3WWJ50JHwutvnQ1FJNHbVth9f2hLzEnh7hBdZ9pD++8pJ8g== dependencies: "@babel/runtime" "^7.10.3" "@types/aria-query" "^4.2.0" @@ -1672,6 +1672,13 @@ dependencies: "@types/domhandler" "*" +"@types/emoji-mart@3.0.2": + version "3.0.2" + resolved "https://registry.yarnpkg.com/@types/emoji-mart/-/emoji-mart-3.0.2.tgz#5814064ce7c622069adf1583e17b3851a00802cb" + integrity sha512-Cmq8xpPK5Va+fjQE7ZaE5oykXzACBQ64CpNnYOIU7gWcR6nYTxWjMR3yPhnAMzw4yQn9R9761FpTvAyi/SH9MQ== + dependencies: + "@types/react" "*" + "@types/eslint-visitor-keys@^1.0.0": version "1.0.0" resolved "https://registry.yarnpkg.com/@types/eslint-visitor-keys/-/eslint-visitor-keys-1.0.0.tgz#1ee30d79544ca84d68d4b3cdb0af4f205663dd2d" @@ -1758,6 +1765,11 @@ jest-diff "^25.2.1" pretty-format "^25.2.1" +"@types/js-cookie@2.2.6": + version "2.2.6" + resolved "https://registry.yarnpkg.com/@types/js-cookie/-/js-cookie-2.2.6.tgz#f1a1cb35aff47bc5cfb05cb0c441ca91e914c26f" + integrity sha512-+oY0FDTO2GYKEV0YPvSshGq9t7YozVkgvXLty7zogQNuCxBhT9/3INX9Q7H1aRZ4SUDRXAKlJuA4EA5nTt7SNw== + "@types/js-yaml@3.12.5": version "3.12.5" resolved "https://registry.yarnpkg.com/@types/js-yaml/-/js-yaml-3.12.5.tgz#136d5e6a57a931e1cce6f9d8126aa98a9c92a6bb" @@ -2259,6 +2271,11 @@ "@webassemblyjs/wast-parser" "1.8.5" "@xtuc/long" "4.2.2" +"@xobotyi/scrollbar-width@1.9.5": + version "1.9.5" + resolved "https://registry.yarnpkg.com/@xobotyi/scrollbar-width/-/scrollbar-width-1.9.5.tgz#80224a6919272f405b87913ca13b92929bdf3c4d" + integrity sha512-N8tkAACJx2ww8vFMneJmaAgmjAG1tnVBZJRLRcx061tmsLRZHSEZSLuGWnwPtunsSLvSqXQ2wfp7Mgqg1I+2dQ== + "@xtuc/ieee754@^1.2.0": version "1.2.0" resolved "https://registry.yarnpkg.com/@xtuc/ieee754/-/ieee754-1.2.0.tgz#eef014a3145ae477a1cbc00cd1e552336dceb790" @@ -2994,6 +3011,11 @@ bootstrap@4.5.0: resolved "https://registry.yarnpkg.com/bootstrap/-/bootstrap-4.5.0.tgz#97d9dbcb5a8972f8722c9962483543b907d9b9ec" integrity sha512-Z93QoXvodoVslA+PWNdk23Hze4RBYIkpb5h8I2HY2Tu2h7A0LpAgLcyrhrSUyo2/Oxm2l1fRZPs1e5hnxnliXA== +bowser@^1.7.3: + version "1.9.4" + resolved "https://registry.yarnpkg.com/bowser/-/bowser-1.9.4.tgz#890c58a2813a9d3243704334fa81b96a5c150c9a" + integrity sha512-9IdMmj2KjigRq6oWhmwv1W36pDuA4STQZ8q6YO9um+x07xgYNCD3Oou+WP/3L1HNz7iqythGet3/p4wvc8AAwQ== + brace-expansion@^1.1.7: version "1.1.11" resolved "https://registry.yarnpkg.com/brace-expansion/-/brace-expansion-1.1.11.tgz#3c7fcbf529d87226f3d2f52b966ff5271eb441dd" @@ -3310,9 +3332,9 @@ caniuse-api@^3.0.0: lodash.uniq "^4.5.0" caniuse-lite@^1.0.0, caniuse-lite@^1.0.30000981, caniuse-lite@^1.0.30001035, caniuse-lite@^1.0.30001093, caniuse-lite@^1.0.30001097: - version "1.0.30001105" - resolved "https://registry.yarnpkg.com/caniuse-lite/-/caniuse-lite-1.0.30001105.tgz#d2cb0b31e5cf2f3ce845033b61c5c01566549abf" - integrity sha512-JupOe6+dGMr7E20siZHIZQwYqrllxotAhiaej96y6x00b/48rPt42o+SzOSCPbrpsDWvRja40Hwrj0g0q6LZJg== + version "1.0.30001107" + resolved "https://registry.yarnpkg.com/caniuse-lite/-/caniuse-lite-1.0.30001107.tgz#809360df7a5b3458f627aa46b0f6ed6d5239da9a" + integrity sha512-86rCH+G8onCmdN4VZzJet5uPELII59cUzDphko3thQFgAQG1RNa+sVLDoALIhRYmflo5iSIzWY3vu1XTWtNMQQ== capture-exit@^2.0.0: version "2.0.0" @@ -3792,6 +3814,13 @@ copy-descriptor@^0.1.0: resolved "https://registry.yarnpkg.com/copy-descriptor/-/copy-descriptor-0.1.1.tgz#676f6eb3c39997c2ee1ac3a924fd6124748f578d" integrity sha1-Z29us8OZl8LuGsOpJP1hJHSPV40= +copy-to-clipboard@^3.2.0: + version "3.3.1" + resolved "https://registry.yarnpkg.com/copy-to-clipboard/-/copy-to-clipboard-3.3.1.tgz#115aa1a9998ffab6196f93076ad6da3b913662ae" + integrity sha512-i13qo6kIHTTpCm8/Wup+0b1mVWETvu2kIMzKoK8FpkLkFxlt0znUAHcMzox+T8sPlqtZXq3CulEjQHsYiGFJUw== + dependencies: + toggle-selection "^1.0.6" + core-js-compat@^3.6.2: version "3.6.5" resolved "https://registry.yarnpkg.com/core-js-compat/-/core-js-compat-3.6.5.tgz#2a51d9a4e25dfd6e690251aa81f99e3c05481f1c" @@ -3962,6 +3991,14 @@ css-has-pseudo@^0.10.0: postcss "^7.0.6" postcss-selector-parser "^5.0.0-rc.4" +css-in-js-utils@^2.0.0: + version "2.0.1" + resolved "https://registry.yarnpkg.com/css-in-js-utils/-/css-in-js-utils-2.0.1.tgz#3b472b398787291b47cfe3e44fecfdd9e914ba99" + integrity sha512-PJF0SpJT+WdbVVt0AOYp9C8GnuruRlL/UFW7932nLWmFLQTaWEzTBQEx7/hn4BuV+WON75iAViSUJLiU3PKbpA== + dependencies: + hyphenate-style-name "^1.0.2" + isobject "^3.0.1" + css-loader@3.4.2: version "3.4.2" resolved "https://registry.yarnpkg.com/css-loader/-/css-loader-3.4.2.tgz#d3fdb3358b43f233b78501c5ed7b1c6da6133202" @@ -4020,7 +4057,7 @@ css-tree@1.0.0-alpha.37: mdn-data "2.0.4" source-map "^0.6.1" -css-tree@1.0.0-alpha.39: +css-tree@1.0.0-alpha.39, css-tree@^1.0.0-alpha.28: version "1.0.0-alpha.39" resolved "https://registry.yarnpkg.com/css-tree/-/css-tree-1.0.0-alpha.39.tgz#2bff3ffe1bb3f776cf7eefd91ee5cba77a149eeb" integrity sha512-7UvkEYgBAHRG9Nt980lYxjsTrCyHFN53ky3wVsDkiMdVqylqRt+Zc+jm5qw7/qyOvN2dHSYtX0e4MbCCExSvnA== @@ -4164,7 +4201,7 @@ cssstyle@^1.0.0, cssstyle@^1.1.1: dependencies: cssom "0.3.x" -csstype@^2.2.0, csstype@^2.6.7: +csstype@^2.2.0, csstype@^2.5.5, csstype@^2.6.7: version "2.6.11" resolved "https://registry.yarnpkg.com/csstype/-/csstype-2.6.11.tgz#452f4d024149ecf260a852b025e36562a253ffc5" integrity sha512-l8YyEC9NBkSm783PFTvh0FmJy7s5pFKrDp49ZL7zBGX3fWkO+N4EEyan1qqp8cwPLDcD0OSdyY6hAMoxp34JFw== @@ -4652,6 +4689,14 @@ elliptic@^6.0.0, elliptic@^6.5.2: minimalistic-assert "^1.0.0" minimalistic-crypto-utils "^1.0.0" +emoji-mart@3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/emoji-mart/-/emoji-mart-3.0.0.tgz#eca24a04881e27752a6921e09f65a86ce8539a50" + integrity sha512-r5DXyzOLJttdwRYfJmPq/XL3W5tiAE/VsRnS0Hqyn27SqPA/GOYwVUSx50px/dXdJyDSnvmoPbuJ/zzhwSaU4A== + dependencies: + "@babel/runtime" "^7.0.0" + prop-types "^15.6.0" + emoji-regex@^7.0.1, emoji-regex@^7.0.2: version "7.0.3" resolved "https://registry.yarnpkg.com/emoji-regex/-/emoji-regex-7.0.3.tgz#933a04052860c85e83c122479c4748a8e4c72156" @@ -4722,6 +4767,13 @@ error-ex@^1.2.0, error-ex@^1.3.1: dependencies: is-arrayish "^0.2.1" +error-stack-parser@^2.0.6: + version "2.0.6" + resolved "https://registry.yarnpkg.com/error-stack-parser/-/error-stack-parser-2.0.6.tgz#5a99a707bd7a4c58a797902d48d82803ede6aad8" + integrity sha512-d51brTeqC+BHlwF0BhPtcYgF5nlzf9ZZ0ZIUQNZpc9ZB9qw5IJ2diTrBY9jlCJkTLITYPjmiX6OWCwH+fuyNgQ== + dependencies: + stackframe "^1.1.1" + es-abstract@^1.17.0, es-abstract@^1.17.0-next.1, es-abstract@^1.17.2, es-abstract@^1.17.4, es-abstract@^1.17.5: version "1.17.6" resolved "https://registry.yarnpkg.com/es-abstract/-/es-abstract-1.17.6.tgz#9142071707857b2cacc7b89ecb670316c3e2d52a" @@ -5358,7 +5410,7 @@ extsprintf@^1.2.0: resolved "https://registry.yarnpkg.com/extsprintf/-/extsprintf-1.4.0.tgz#e2689f8f356fad62cca65a3a91c5df5f9551692f" integrity sha1-4mifjzVvrWLMplo6kcXfX5VRaS8= -fast-deep-equal@^3.1.1: +fast-deep-equal@^3.1.1, fast-deep-equal@^3.1.3: version "3.1.3" resolved "https://registry.yarnpkg.com/fast-deep-equal/-/fast-deep-equal-3.1.3.tgz#3a7d56b559d6cbc3eb512325244e619a65c6c525" integrity sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q== @@ -5385,6 +5437,16 @@ fast-levenshtein@~2.0.6: resolved "https://registry.yarnpkg.com/fast-levenshtein/-/fast-levenshtein-2.0.6.tgz#3d8a5c66883a16a30ca8643e851f19baa7797917" integrity sha1-PYpcZog6FqMMqGQ+hR8Zuqd5eRc= +fast-shallow-equal@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/fast-shallow-equal/-/fast-shallow-equal-1.0.0.tgz#d4dcaf6472440dcefa6f88b98e3251e27f25628b" + integrity sha512-HPtaa38cPgWvaCFmRNhlc6NG7pv6NUHqjPgVAkWGoB9mQMwYB27/K0CvOM5Czy+qpT3e8XJ6Q4aPAnzpNpzNaw== + +fastest-stable-stringify@^1.0.1: + version "1.0.1" + resolved "https://registry.yarnpkg.com/fastest-stable-stringify/-/fastest-stable-stringify-1.0.1.tgz#9122d406d4c9d98bea644a6b6853d5874b87b028" + integrity sha1-kSLUBtTJ2YvqZEpraFPVh0uHsCg= + faye-websocket@^0.10.0: version "0.10.0" resolved "https://registry.yarnpkg.com/faye-websocket/-/faye-websocket-0.10.0.tgz#4e492f8d04dfb6f89003507f6edbf2d501e7c6f4" @@ -6289,6 +6351,11 @@ human-signals@^1.1.1: resolved "https://registry.yarnpkg.com/human-signals/-/human-signals-1.1.1.tgz#c5b1cd14f50aeae09ab6c59fe63ba3395fe4dfa3" integrity sha512-SEQu7vl8KjNL2eoGBLF3+wAjpsNfA9XMlXAYj/3EdaNfAlxKthD1xjEQfGOUhllCGGJVNY34bRr6lPINhNjyZw== +hyphenate-style-name@^1.0.2: + version "1.0.4" + resolved "https://registry.yarnpkg.com/hyphenate-style-name/-/hyphenate-style-name-1.0.4.tgz#691879af8e220aea5750e8827db4ef62a54e361d" + integrity sha512-ygGZLjmXfPHj+ZWh6LwbC37l43MhfztxetbFCoYTM2VjkIUpeHgSNn7QIyVFj7YQ1Wl9Cbw5sholVJPzWvC2MQ== + i18next-browser-languagedetector@5.0.0: version "5.0.0" resolved "https://registry.yarnpkg.com/i18next-browser-languagedetector/-/i18next-browser-languagedetector-5.0.0.tgz#9e946ed2ea5514a636913fe020a32455e82946e3" @@ -6464,6 +6531,14 @@ ini@^1.3.5: resolved "https://registry.yarnpkg.com/ini/-/ini-1.3.5.tgz#eee25f56db1c9ec6085e0c22778083f596abf927" integrity sha512-RZY5huIKCMRWDUqZlEi72f/lmXKMvuszcMBduliQ3nnWbx9X/ZBQO7DijMEYS9EhHBb2qacRUMtC7svLwe0lcw== +inline-style-prefixer@^4.0.0: + version "4.0.2" + resolved "https://registry.yarnpkg.com/inline-style-prefixer/-/inline-style-prefixer-4.0.2.tgz#d390957d26f281255fe101da863158ac6eb60911" + integrity sha512-N8nVhwfYga9MiV9jWlwfdj1UDIaZlBFu4cJSJkIr7tZX7sHpHhGR5su1qdpW+7KPL8ISTvCIkcaFi/JdBknvPg== + dependencies: + bowser "^1.7.3" + css-in-js-utils "^2.0.0" + inquirer@7.0.4: version "7.0.4" resolved "https://registry.yarnpkg.com/inquirer/-/inquirer-7.0.4.tgz#99af5bde47153abca23f5c7fc30db247f39da703" @@ -7433,6 +7508,11 @@ js-base64@^2.1.8: resolved "https://registry.yarnpkg.com/js-base64/-/js-base64-2.6.3.tgz#7afdb9b57aa7717e15d370b66e8f36a9cb835dc3" integrity sha512-fiUvdfCaAXoQTHdKMgTvg6IkecXDcVz6V5rlftUTclF9IKBjMizvSdQaCl/z/6TApDeby5NL+axYou3i0mu1Pg== +js-cookie@^2.2.1: + version "2.2.1" + resolved "https://registry.yarnpkg.com/js-cookie/-/js-cookie-2.2.1.tgz#69e106dc5d5806894562902aa5baec3744e9b2b8" + integrity sha512-HvdH2LzI/EAZcUwA8+0nKNtWHqS+ZmijLA30RwZA0bo7ToCckjK5MkGhjED9KoRcXO6BaGI3I9UIzSA1FKFPOQ== + "js-tokens@^3.0.0 || ^4.0.0", js-tokens@^4.0.0: version "4.0.0" resolved "https://registry.yarnpkg.com/js-tokens/-/js-tokens-4.0.0.tgz#19203fb59991df98e3a287050d4647cdeaf32499" @@ -8485,6 +8565,20 @@ nan@^2.12.1, nan@^2.13.2: resolved "https://registry.yarnpkg.com/nan/-/nan-2.14.1.tgz#d7be34dfa3105b91494c3147089315eff8874b01" integrity sha512-isWHgVjnFjh2x2yuJ/tj3JbwoHu3UC2dX5G/88Cm24yB6YopVgxvBObDY7n5xW6ExmFhJpSEQqFPvq9zaXc8Jw== +nano-css@^5.2.1: + version "5.3.0" + resolved "https://registry.yarnpkg.com/nano-css/-/nano-css-5.3.0.tgz#9d3cd29788d48b6a07f52aa4aec7cf4da427b6b5" + integrity sha512-uM/9NGK9/E9/sTpbIZ/bQ9xOLOIHZwrrb/CRlbDHBU/GFS7Gshl24v/WJhwsVViWkpOXUmiZ66XO7fSB4Wd92Q== + dependencies: + css-tree "^1.0.0-alpha.28" + csstype "^2.5.5" + fastest-stable-stringify "^1.0.1" + inline-style-prefixer "^4.0.0" + rtl-css-js "^1.9.0" + sourcemap-codec "^1.4.1" + stacktrace-js "^2.0.0" + stylis "3.5.0" + nanomatch@^1.2.9: version "1.2.13" resolved "https://registry.yarnpkg.com/nanomatch/-/nanomatch-1.2.13.tgz#b87a8aa4fc0de8fe6be88895b38983ff265bd119" @@ -9703,14 +9797,14 @@ postcss-modules-extract-imports@^2.0.0: postcss "^7.0.5" postcss-modules-local-by-default@^3.0.2: - version "3.0.2" - resolved "https://registry.yarnpkg.com/postcss-modules-local-by-default/-/postcss-modules-local-by-default-3.0.2.tgz#e8a6561be914aaf3c052876377524ca90dbb7915" - integrity sha512-jM/V8eqM4oJ/22j0gx4jrp63GSvDH6v86OqyTHHUvk4/k1vceipZsaymiZ5PvocqZOl5SFHiFJqjs3la0wnfIQ== + version "3.0.3" + resolved "https://registry.yarnpkg.com/postcss-modules-local-by-default/-/postcss-modules-local-by-default-3.0.3.tgz#bb14e0cc78279d504dbdcbfd7e0ca28993ffbbb0" + integrity sha512-e3xDq+LotiGesympRlKNgaJ0PCzoUIdpH0dj47iWAui/kyTgh3CiAr1qP54uodmJhl6p9rN6BoNcdEDVJx9RDw== dependencies: icss-utils "^4.1.1" - postcss "^7.0.16" + postcss "^7.0.32" postcss-selector-parser "^6.0.2" - postcss-value-parser "^4.0.0" + postcss-value-parser "^4.1.0" postcss-modules-scope@^2.1.1: version "2.2.0" @@ -10010,7 +10104,7 @@ postcss-value-parser@^3.0.0: resolved "https://registry.yarnpkg.com/postcss-value-parser/-/postcss-value-parser-3.3.1.tgz#9ff822547e2893213cf1c30efa51ac5fd1ba8281" integrity sha512-pISE66AbVkp4fDQ7VHBwRNXzAAKJjw4Vw7nWI/+Q3vuly7SNfgYXvm6i5IgFylHGK5sP/xHAbB7N49OS4gWNyQ== -postcss-value-parser@^4.0.0, postcss-value-parser@^4.0.2, postcss-value-parser@^4.1.0: +postcss-value-parser@^4.0.2, postcss-value-parser@^4.1.0: version "4.1.0" resolved "https://registry.yarnpkg.com/postcss-value-parser/-/postcss-value-parser-4.1.0.tgz#443f6a20ced6481a2bda4fa8532a6e55d789a2cb" integrity sha512-97DXOFbQJhk71ne5/Mt6cOu6yxsSfM0QGQyl0L25Gca4yGWEGJaig7l7gbCX623VqTBNGLRLaVUCnNkcedlRSQ== @@ -10033,7 +10127,7 @@ postcss@7.0.21: source-map "^0.6.1" supports-color "^6.1.0" -postcss@^7, postcss@^7.0.0, postcss@^7.0.1, postcss@^7.0.14, postcss@^7.0.16, postcss@^7.0.17, postcss@^7.0.2, postcss@^7.0.23, postcss@^7.0.27, postcss@^7.0.32, postcss@^7.0.5, postcss@^7.0.6: +postcss@^7, postcss@^7.0.0, postcss@^7.0.1, postcss@^7.0.14, postcss@^7.0.17, postcss@^7.0.2, postcss@^7.0.23, postcss@^7.0.27, postcss@^7.0.32, postcss@^7.0.5, postcss@^7.0.6: version "7.0.32" resolved "https://registry.yarnpkg.com/postcss/-/postcss-7.0.32.tgz#4310d6ee347053da3433db2be492883d62cec59d" integrity sha512-03eXong5NLnNCD05xscnGKGDZ98CyzoqPSMjOe6SuoQY7Z2hIj0Ld1g/O/UQRuOle2aRtiIRDg9tDcTGAkLfKw== @@ -10128,7 +10222,7 @@ prop-types-extra@^1.1.0: react-is "^16.3.2" warning "^4.0.0" -prop-types@^15.5.10, prop-types@^15.5.7, prop-types@^15.5.8, prop-types@^15.6.1, prop-types@^15.6.2, prop-types@^15.7.2: +prop-types@^15.5.10, prop-types@^15.5.7, prop-types@^15.5.8, prop-types@^15.6.0, prop-types@^15.6.1, prop-types@^15.6.2, prop-types@^15.7.2: version "15.7.2" resolved "https://registry.yarnpkg.com/prop-types/-/prop-types-15.7.2.tgz#52c41e75b8c87e72b9d9360e0206b99dcbffa6c5" integrity sha512-8QQikdH7//R2vurIJSutZ1smHYTcLpRWEOlHnzcWHmBYrOGUysKwSsrC89BCiFj3CbrfJ/nXFdJepOVrY1GCHQ== @@ -10591,6 +10685,31 @@ react-transition-group@^4.4.1: loose-envify "^1.4.0" prop-types "^15.6.2" +react-universal-interface@^0.6.2: + version "0.6.2" + resolved "https://registry.yarnpkg.com/react-universal-interface/-/react-universal-interface-0.6.2.tgz#5e8d438a01729a4dbbcbeeceb0b86be146fe2b3b" + integrity sha512-dg8yXdcQmvgR13RIlZbTRQOoUrDciFVoSBZILwjE2LFISxZZ8loVJKAkuzswl5js8BHda79bIb2b84ehU8IjXw== + +react-use@15.3.3: + version "15.3.3" + resolved "https://registry.yarnpkg.com/react-use/-/react-use-15.3.3.tgz#f16de7a16286c446388e8bd99680952fc3dc9a95" + integrity sha512-nYb94JbmDCaLZg3sOXmFW8HN+lXWxnl0caspXoYfZG1CON8JfLN9jMOyxRDUpm7dUq7WZ5mIept/ByqBQKJ0wQ== + dependencies: + "@types/js-cookie" "2.2.6" + "@xobotyi/scrollbar-width" "1.9.5" + copy-to-clipboard "^3.2.0" + fast-deep-equal "^3.1.3" + fast-shallow-equal "^1.0.0" + js-cookie "^2.2.1" + nano-css "^5.2.1" + react-universal-interface "^0.6.2" + resize-observer-polyfill "^1.5.1" + screenfull "^5.0.0" + set-harmonic-interval "^1.0.1" + throttle-debounce "^2.1.0" + ts-easing "^0.2.0" + tslib "^2.0.0" + react@16.13.1: version "16.13.1" resolved "https://registry.yarnpkg.com/react/-/react-16.13.1.tgz#2e818822f1a9743122c063d6410d85c1e3afe48e" @@ -11091,6 +11210,13 @@ rsvp@^4.8.4: resolved "https://registry.yarnpkg.com/rsvp/-/rsvp-4.8.5.tgz#c8f155311d167f68f21e168df71ec5b083113734" integrity sha512-nfMOlASu9OnRJo1mbEk2cz0D56a1MBNrJ7orjRZQG10XDyuvwksKbuXNp6qa+kbn839HwjwhBzhFmdsaEAfauA== +rtl-css-js@^1.9.0: + version "1.14.0" + resolved "https://registry.yarnpkg.com/rtl-css-js/-/rtl-css-js-1.14.0.tgz#daa4f192a92509e292a0519f4b255e6e3c076b7d" + integrity sha512-Dl5xDTeN3e7scU1cWX8c9b6/Nqz3u/HgR4gePc1kWXYiQWVQbKCEyK6+Hxve9LbcJ5EieHy1J9nJCN3grTtGwg== + dependencies: + "@babel/runtime" "^7.1.2" + run-async@^2.2.0, run-async@^2.4.0: version "2.4.1" resolved "https://registry.yarnpkg.com/run-async/-/run-async-2.4.1.tgz#8440eccf99ea3e70bd409d49aab88e10c189a455" @@ -11211,6 +11337,11 @@ schema-utils@^2.5.0, schema-utils@^2.6.0, schema-utils@^2.6.1, schema-utils@^2.6 ajv "^6.12.2" ajv-keywords "^3.4.1" +screenfull@^5.0.0: + version "5.0.2" + resolved "https://registry.yarnpkg.com/screenfull/-/screenfull-5.0.2.tgz#b9acdcf1ec676a948674df5cd0ff66b902b0bed7" + integrity sha512-cCF2b+L/mnEiORLN5xSAz6H3t18i2oHh9BA8+CQlAh5DRw2+NFAGQJOSYbcGw8B2k04g/lVvFcfZ83b3ysH5UQ== + scroll-into-view-if-needed@^2.2.20: version "2.2.25" resolved "https://registry.yarnpkg.com/scroll-into-view-if-needed/-/scroll-into-view-if-needed-2.2.25.tgz#117b7bc7c61bc7a2b7872a0984bc73a19bc6e961" @@ -11322,6 +11453,11 @@ set-blocking@^2.0.0, set-blocking@~2.0.0: resolved "https://registry.yarnpkg.com/set-blocking/-/set-blocking-2.0.0.tgz#045f9782d011ae9a6803ddd382b24392b3d890f7" integrity sha1-BF+XgtARrppoA93TgrJDkrPYkPc= +set-harmonic-interval@^1.0.1: + version "1.0.1" + resolved "https://registry.yarnpkg.com/set-harmonic-interval/-/set-harmonic-interval-1.0.1.tgz#e1773705539cdfb80ce1c3d99e7f298bb3995249" + integrity sha512-AhICkFV84tBP1aWqPwLZqFvAwqEoVA9kxNMniGEUvzOlm4vLmOFLiTT3UZ6bziJTy4bOVpzWGTfSCbmaayGx8g== + set-value@^2.0.0, set-value@^2.0.1: version "2.0.1" resolved "https://registry.yarnpkg.com/set-value/-/set-value-2.0.1.tgz#a18d40530e6f07de4228c7defe4227af8cad005b" @@ -11554,6 +11690,11 @@ source-map-url@^0.4.0: resolved "https://registry.yarnpkg.com/source-map-url/-/source-map-url-0.4.0.tgz#3e935d7ddd73631b97659956d55128e87b5084a3" integrity sha1-PpNdfd1zYxuXZZlW1VEo6HtQhKM= +source-map@0.5.6: + version "0.5.6" + resolved "https://registry.yarnpkg.com/source-map/-/source-map-0.5.6.tgz#75ce38f52bf0733c5a7f0c118d81334a2bb5f412" + integrity sha1-dc449SvwczxafwwRjYEzSiu19BI= + source-map@0.6.1, source-map@^0.6.0, source-map@^0.6.1, source-map@~0.6.0, source-map@~0.6.1: version "0.6.1" resolved "https://registry.yarnpkg.com/source-map/-/source-map-0.6.1.tgz#74722af32e9614e9c287a8d0bbde48b5e2f1a263" @@ -11571,6 +11712,11 @@ source-map@^0.5.0, source-map@^0.5.6: resolved "https://registry.yarnpkg.com/source-map/-/source-map-0.5.7.tgz#8a039d2d1021d22d1ea14c80d8ea468ba2ef3fcc" integrity sha1-igOdLRAh0i0eoUyA2OpGi6LvP8w= +sourcemap-codec@^1.4.1: + version "1.4.8" + resolved "https://registry.yarnpkg.com/sourcemap-codec/-/sourcemap-codec-1.4.8.tgz#ea804bd94857402e6992d05a38ef1ae35a9ab4c4" + integrity sha512-9NykojV5Uih4lgo5So5dtw+f0JgJX30KCNI8gwhz2J9A15wD0Ml6tjHKwf6fTSa6fAdVBdZeNOs9eJ71qCk8vA== + spdx-correct@^3.0.0: version "3.1.1" resolved "https://registry.yarnpkg.com/spdx-correct/-/spdx-correct-3.1.1.tgz#dece81ac9c1e6713e5f7d1b6f17d468fa53d89a9" @@ -11674,11 +11820,40 @@ stable@^0.1.8: resolved "https://registry.yarnpkg.com/stable/-/stable-0.1.8.tgz#836eb3c8382fe2936feaf544631017ce7d47a3cf" integrity sha512-ji9qxRnOVfcuLDySj9qzhGSEFVobyt1kIOSkj1qZzYLzq7Tos/oUUWvotUPQLlrsidqsK6tBH89Bc9kL5zHA6w== +stack-generator@^2.0.5: + version "2.0.5" + resolved "https://registry.yarnpkg.com/stack-generator/-/stack-generator-2.0.5.tgz#fb00e5b4ee97de603e0773ea78ce944d81596c36" + integrity sha512-/t1ebrbHkrLrDuNMdeAcsvynWgoH/i4o8EGGfX7dEYDoTXOYVAkEpFdtshlvabzc6JlJ8Kf9YdFEoz7JkzGN9Q== + dependencies: + stackframe "^1.1.1" + stack-utils@^1.0.1: version "1.0.2" resolved "https://registry.yarnpkg.com/stack-utils/-/stack-utils-1.0.2.tgz#33eba3897788558bebfc2db059dc158ec36cebb8" integrity sha512-MTX+MeG5U994cazkjd/9KNAapsHnibjMLnfXodlkXw76JEea0UiNzrqidzo1emMwk7w5Qhc9jd4Bn9TBb1MFwA== +stackframe@^1.1.1: + version "1.2.0" + resolved "https://registry.yarnpkg.com/stackframe/-/stackframe-1.2.0.tgz#52429492d63c62eb989804c11552e3d22e779303" + integrity sha512-GrdeshiRmS1YLMYgzF16olf2jJ/IzxXY9lhKOskuVziubpTYcYqyOwYeJKzQkwy7uN0fYSsbsC4RQaXf9LCrYA== + +stacktrace-gps@^3.0.4: + version "3.0.4" + resolved "https://registry.yarnpkg.com/stacktrace-gps/-/stacktrace-gps-3.0.4.tgz#7688dc2fc09ffb3a13165ebe0dbcaf41bcf0c69a" + integrity sha512-qIr8x41yZVSldqdqe6jciXEaSCKw1U8XTXpjDuy0ki/apyTn/r3w9hDAAQOhZdxvsC93H+WwwEu5cq5VemzYeg== + dependencies: + source-map "0.5.6" + stackframe "^1.1.1" + +stacktrace-js@^2.0.0: + version "2.0.2" + resolved "https://registry.yarnpkg.com/stacktrace-js/-/stacktrace-js-2.0.2.tgz#4ca93ea9f494752d55709a081d400fdaebee897b" + integrity sha512-Je5vBeY4S1r/RnLydLl0TBTi3F2qdfWmYsGvtfZgEI+SCprPppaIhQf5nGcal4gI4cGpCV/duLcAzT1np6sQqg== + dependencies: + error-stack-parser "^2.0.6" + stack-generator "^2.0.5" + stacktrace-gps "^3.0.4" + start-server-and-test@1.11.2: version "1.11.2" resolved "https://registry.yarnpkg.com/start-server-and-test/-/start-server-and-test-1.11.2.tgz#9144b7b6f25197148f159f261ae80119afbb17d5" @@ -11962,6 +12137,11 @@ stylehacks@^4.0.0: postcss "^7.0.0" postcss-selector-parser "^3.0.0" +stylis@3.5.0: + version "3.5.0" + resolved "https://registry.yarnpkg.com/stylis/-/stylis-3.5.0.tgz#016fa239663d77f868fef5b67cf201c4b7c701e1" + integrity sha512-pP7yXN6dwMzAR29Q0mBrabPCe0/mNO1MSr93bhay+hcZondvMMTpeGyd8nbhYJdyperNT2DRxONQuUGcJr5iPw== + supports-color@7.1.0, supports-color@^7.0.0, supports-color@^7.1.0: version "7.1.0" resolved "https://registry.yarnpkg.com/supports-color/-/supports-color-7.1.0.tgz#68e32591df73e25ad1c4b49108a2ec507962bfd1" @@ -12105,6 +12285,11 @@ throat@^4.0.0: resolved "https://registry.yarnpkg.com/throat/-/throat-4.1.0.tgz#89037cbc92c56ab18926e6ba4cbb200e15672a6a" integrity sha1-iQN8vJLFarGJJua6TLsgDhVnKmo= +throttle-debounce@^2.1.0: + version "2.2.1" + resolved "https://registry.yarnpkg.com/throttle-debounce/-/throttle-debounce-2.2.1.tgz#fbd933ae6793448816f7d5b3cae259d464c98137" + integrity sha512-i9hAVld1f+woAiyNGqWelpDD5W1tpMroL3NofTz9xzwq6acWBlO2dC8k5EFSZepU6oOINtV5Q3aSPoRg7o4+fA== + throttleit@^1.0.0: version "1.0.0" resolved "https://registry.yarnpkg.com/throttleit/-/throttleit-1.0.0.tgz#9e785836daf46743145a5984b6268d828528ac6c" @@ -12211,6 +12396,11 @@ to-regex@^3.0.1, to-regex@^3.0.2: regex-not "^1.0.2" safe-regex "^1.1.0" +toggle-selection@^1.0.6: + version "1.0.6" + resolved "https://registry.yarnpkg.com/toggle-selection/-/toggle-selection-1.0.6.tgz#6e45b1263f2017fa0acc7d89d78b15b8bf77da32" + integrity sha1-bkWxJj8gF/oKzH2J14sVuL932jI= + toidentifier@1.0.0: version "1.0.0" resolved "https://registry.yarnpkg.com/toidentifier/-/toidentifier-1.0.0.tgz#7e1be3470f1e77948bc43d94a3c8f4d7752ba553" @@ -12243,6 +12433,11 @@ trim-newlines@^1.0.0: dependencies: glob "^7.1.2" +ts-easing@^0.2.0: + version "0.2.0" + resolved "https://registry.yarnpkg.com/ts-easing/-/ts-easing-0.2.0.tgz#c8a8a35025105566588d87dbda05dd7fbfa5a4ec" + integrity sha512-Z86EW+fFFh/IFB1fqQ3/+7Zpf9t2ebOAxNI/V6Wo7r5gqiqtxmgTlQ1qbqQcjLKYeSHPTsEmvlJUDg/EuL0uHQ== + ts-loader@8.0.2: version "8.0.2" resolved "https://registry.yarnpkg.com/ts-loader/-/ts-loader-8.0.2.tgz#ee73ca9350f745799396fff8578ba29b1e95616b" @@ -12254,7 +12449,7 @@ ts-loader@8.0.2: micromatch "^4.0.0" semver "^6.0.0" -ts-mockery@^1.2.0: +ts-mockery@1.2.0: version "1.2.0" resolved "https://registry.yarnpkg.com/ts-mockery/-/ts-mockery-1.2.0.tgz#aa76521653d729e99b3808836817f64e61a213dd" integrity sha512-ArGPMUzO4H25KBYVTWmmE36y5bCOFAwC7XdW4CLTqYg+gQcvxJzKoj5URSc+luzwI8QdtwAkHtazBmrKepX81g== @@ -12284,6 +12479,11 @@ tslib@^1.10.0, tslib@^1.8.1, tslib@^1.9.0: resolved "https://registry.yarnpkg.com/tslib/-/tslib-1.13.0.tgz#c881e13cc7015894ed914862d276436fa9a47043" integrity sha512-i/6DQjL8Xf3be4K/E6Wgpekn5Qasl1usyw++dAA35Ue5orEn65VIxOA+YvNNl9HV3qv70T7CNwjODHZrLwvd1Q== +tslib@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/tslib/-/tslib-2.0.0.tgz#18d13fc2dce04051e20f074cc8387fd8089ce4f3" + integrity sha512-lTqkx847PI7xEDYJntxZH89L2/aXInsyF2luSafe/+0fHOMjlBNXdH6th7f70qxLDhul7KZK0zC8V5ZIyHl0/g== + tsutils@^3.17.1: version "3.17.1" resolved "https://registry.yarnpkg.com/tsutils/-/tsutils-3.17.1.tgz#ed719917f11ca0dee586272b2ac49e015a2dd759"