@atlaskit/emoji 67.0.7 → 67.2.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +37 -0
- package/dist/cjs/api/EmojiResource.js +41 -25
- package/dist/cjs/api/media/TokenManager.js +4 -4
- package/dist/cjs/components/common/CachingEmoji.js +14 -6
- package/dist/cjs/components/common/Emoji.js +48 -12
- package/dist/cjs/components/common/EmojiActions.js +62 -26
- package/dist/cjs/components/common/EmojiErrorMessage.js +12 -7
- package/dist/cjs/components/common/EmojiPlaceholder.js +1 -0
- package/dist/cjs/components/common/{EmojiButton.js → EmojiRadioButton.js} +28 -19
- package/dist/cjs/components/common/EmojiUploadPicker.js +80 -37
- package/dist/cjs/components/common/EmojiUploadPreview.js +11 -2
- package/dist/cjs/components/common/FileChooser.js +2 -2
- package/dist/cjs/components/common/ResourcedEmojiComponent.js +4 -0
- package/dist/cjs/components/common/RetryableButton.js +7 -3
- package/dist/cjs/components/common/TonePreviewButton.js +44 -0
- package/dist/cjs/components/common/ToneSelector.js +53 -25
- package/dist/cjs/components/common/styles.js +45 -16
- package/dist/cjs/components/i18n.js +44 -4
- package/dist/cjs/components/picker/CategorySelector.js +112 -90
- package/dist/cjs/components/picker/CategoryTracker.js +0 -28
- package/dist/cjs/components/picker/EmojiPickerCategoryHeading.js +2 -1
- package/dist/cjs/components/picker/EmojiPickerComponent.js +33 -44
- package/dist/cjs/components/picker/EmojiPickerEmojiRow.js +32 -4
- package/dist/cjs/components/picker/EmojiPickerList.js +154 -88
- package/dist/cjs/components/picker/EmojiPickerListSearch.js +66 -117
- package/dist/cjs/components/picker/EmojiPickerVirtualItems.js +5 -2
- package/dist/cjs/components/picker/VirtualList.js +273 -171
- package/dist/cjs/components/picker/styles.js +43 -51
- package/dist/cjs/components/typeahead/EmojiTypeAheadComponent.js +0 -10
- package/dist/cjs/context/EmojiPickerListContext.js +33 -0
- package/dist/cjs/hooks/useEmojiPickerListContext.js +12 -0
- package/dist/cjs/hooks/useIsMounted.js +17 -0
- package/dist/cjs/i18n/cs.js +35 -34
- package/dist/cjs/i18n/da.js +35 -34
- package/dist/cjs/i18n/de.js +35 -34
- package/dist/cjs/i18n/en.js +35 -34
- package/dist/cjs/i18n/en_GB.js +35 -34
- package/dist/cjs/i18n/es.js +35 -34
- package/dist/cjs/i18n/fi.js +35 -34
- package/dist/cjs/i18n/fr.js +35 -34
- package/dist/cjs/i18n/hu.js +35 -34
- package/dist/cjs/i18n/it.js +35 -34
- package/dist/cjs/i18n/ja.js +35 -34
- package/dist/cjs/i18n/ko.js +35 -34
- package/dist/cjs/i18n/nb.js +35 -34
- package/dist/cjs/i18n/nl.js +35 -34
- package/dist/cjs/i18n/pl.js +35 -34
- package/dist/cjs/i18n/pt_BR.js +35 -34
- package/dist/cjs/i18n/ru.js +35 -34
- package/dist/cjs/i18n/sv.js +35 -34
- package/dist/cjs/i18n/th.js +35 -34
- package/dist/cjs/i18n/tr.js +35 -34
- package/dist/cjs/i18n/uk.js +35 -34
- package/dist/cjs/i18n/vi.js +35 -34
- package/dist/cjs/i18n/zh.js +35 -34
- package/dist/cjs/i18n/zh_TW.js +35 -34
- package/dist/cjs/types.js +7 -1
- package/dist/cjs/util/constants.js +43 -2
- package/dist/cjs/util/shared-styles.js +3 -4
- package/dist/cjs/version.json +1 -1
- package/dist/es2019/api/EmojiResource.js +42 -26
- package/dist/es2019/api/media/TokenManager.js +4 -4
- package/dist/es2019/components/common/CachingEmoji.js +10 -3
- package/dist/es2019/components/common/Emoji.js +44 -11
- package/dist/es2019/components/common/EmojiActions.js +55 -24
- package/dist/es2019/components/common/EmojiErrorMessage.js +7 -3
- package/dist/es2019/components/common/EmojiPlaceholder.js +1 -0
- package/dist/es2019/components/common/EmojiRadioButton.js +54 -0
- package/dist/es2019/components/common/EmojiUploadPicker.js +75 -36
- package/dist/es2019/components/common/EmojiUploadPreview.js +11 -2
- package/dist/es2019/components/common/FileChooser.js +1 -1
- package/dist/es2019/components/common/ResourcedEmojiComponent.js +4 -0
- package/dist/es2019/components/common/RetryableButton.js +7 -3
- package/dist/es2019/components/common/TonePreviewButton.js +34 -0
- package/dist/es2019/components/common/ToneSelector.js +55 -21
- package/dist/es2019/components/common/styles.js +41 -10
- package/dist/es2019/components/i18n.js +44 -4
- package/dist/es2019/components/picker/CategorySelector.js +114 -89
- package/dist/es2019/components/picker/CategoryTracker.js +0 -24
- package/dist/es2019/components/picker/EmojiPickerCategoryHeading.js +2 -2
- package/dist/es2019/components/picker/EmojiPickerComponent.js +36 -46
- package/dist/es2019/components/picker/EmojiPickerEmojiRow.js +51 -21
- package/dist/es2019/components/picker/EmojiPickerList.js +113 -55
- package/dist/es2019/components/picker/EmojiPickerListSearch.js +61 -98
- package/dist/es2019/components/picker/EmojiPickerVirtualItems.js +4 -1
- package/dist/es2019/components/picker/VirtualList.js +247 -108
- package/dist/es2019/components/picker/styles.js +20 -28
- package/dist/es2019/components/typeahead/EmojiTypeAheadComponent.js +0 -10
- package/dist/es2019/context/EmojiPickerListContext.js +17 -0
- package/dist/es2019/hooks/useEmojiPickerListContext.js +3 -0
- package/dist/es2019/hooks/useIsMounted.js +11 -0
- package/dist/es2019/i18n/cs.js +35 -34
- package/dist/es2019/i18n/da.js +35 -34
- package/dist/es2019/i18n/de.js +35 -34
- package/dist/es2019/i18n/en.js +35 -34
- package/dist/es2019/i18n/en_GB.js +35 -34
- package/dist/es2019/i18n/es.js +35 -34
- package/dist/es2019/i18n/fi.js +35 -34
- package/dist/es2019/i18n/fr.js +35 -34
- package/dist/es2019/i18n/hu.js +35 -34
- package/dist/es2019/i18n/it.js +35 -34
- package/dist/es2019/i18n/ja.js +35 -34
- package/dist/es2019/i18n/ko.js +35 -34
- package/dist/es2019/i18n/nb.js +35 -34
- package/dist/es2019/i18n/nl.js +35 -34
- package/dist/es2019/i18n/pl.js +35 -34
- package/dist/es2019/i18n/pt_BR.js +35 -34
- package/dist/es2019/i18n/ru.js +35 -34
- package/dist/es2019/i18n/sv.js +35 -34
- package/dist/es2019/i18n/th.js +35 -34
- package/dist/es2019/i18n/tr.js +35 -34
- package/dist/es2019/i18n/uk.js +35 -34
- package/dist/es2019/i18n/vi.js +35 -34
- package/dist/es2019/i18n/zh.js +35 -34
- package/dist/es2019/i18n/zh_TW.js +35 -34
- package/dist/es2019/types.js +5 -0
- package/dist/es2019/util/constants.js +32 -0
- package/dist/es2019/util/shared-styles.js +1 -2
- package/dist/es2019/version.json +1 -1
- package/dist/esm/api/EmojiResource.js +42 -26
- package/dist/esm/api/media/TokenManager.js +4 -4
- package/dist/esm/components/common/CachingEmoji.js +14 -6
- package/dist/esm/components/common/Emoji.js +48 -12
- package/dist/esm/components/common/EmojiActions.js +62 -26
- package/dist/esm/components/common/EmojiErrorMessage.js +7 -3
- package/dist/esm/components/common/EmojiPlaceholder.js +1 -0
- package/dist/esm/components/common/EmojiRadioButton.js +52 -0
- package/dist/esm/components/common/EmojiUploadPicker.js +77 -36
- package/dist/esm/components/common/EmojiUploadPreview.js +11 -2
- package/dist/esm/components/common/FileChooser.js +1 -1
- package/dist/esm/components/common/ResourcedEmojiComponent.js +4 -0
- package/dist/esm/components/common/RetryableButton.js +7 -3
- package/dist/esm/components/common/TonePreviewButton.js +33 -0
- package/dist/esm/components/common/ToneSelector.js +49 -18
- package/dist/esm/components/common/styles.js +40 -12
- package/dist/esm/components/i18n.js +44 -4
- package/dist/esm/components/picker/CategorySelector.js +114 -95
- package/dist/esm/components/picker/CategoryTracker.js +0 -28
- package/dist/esm/components/picker/EmojiPickerCategoryHeading.js +2 -2
- package/dist/esm/components/picker/EmojiPickerComponent.js +35 -46
- package/dist/esm/components/picker/EmojiPickerEmojiRow.js +32 -4
- package/dist/esm/components/picker/EmojiPickerList.js +156 -86
- package/dist/esm/components/picker/EmojiPickerListSearch.js +64 -117
- package/dist/esm/components/picker/EmojiPickerVirtualItems.js +5 -2
- package/dist/esm/components/picker/VirtualList.js +274 -172
- package/dist/esm/components/picker/styles.js +37 -45
- package/dist/esm/components/typeahead/EmojiTypeAheadComponent.js +0 -10
- package/dist/esm/context/EmojiPickerListContext.js +21 -0
- package/dist/esm/hooks/useEmojiPickerListContext.js +5 -0
- package/dist/esm/hooks/useIsMounted.js +11 -0
- package/dist/esm/i18n/cs.js +35 -34
- package/dist/esm/i18n/da.js +35 -34
- package/dist/esm/i18n/de.js +35 -34
- package/dist/esm/i18n/en.js +35 -34
- package/dist/esm/i18n/en_GB.js +35 -34
- package/dist/esm/i18n/es.js +35 -34
- package/dist/esm/i18n/fi.js +35 -34
- package/dist/esm/i18n/fr.js +35 -34
- package/dist/esm/i18n/hu.js +35 -34
- package/dist/esm/i18n/it.js +35 -34
- package/dist/esm/i18n/ja.js +35 -34
- package/dist/esm/i18n/ko.js +35 -34
- package/dist/esm/i18n/nb.js +35 -34
- package/dist/esm/i18n/nl.js +35 -34
- package/dist/esm/i18n/pl.js +35 -34
- package/dist/esm/i18n/pt_BR.js +35 -34
- package/dist/esm/i18n/ru.js +35 -34
- package/dist/esm/i18n/sv.js +35 -34
- package/dist/esm/i18n/th.js +35 -34
- package/dist/esm/i18n/tr.js +35 -34
- package/dist/esm/i18n/uk.js +35 -34
- package/dist/esm/i18n/vi.js +35 -34
- package/dist/esm/i18n/zh.js +35 -34
- package/dist/esm/i18n/zh_TW.js +35 -34
- package/dist/esm/types.js +5 -0
- package/dist/esm/util/constants.js +32 -0
- package/dist/esm/util/shared-styles.js +1 -2
- package/dist/esm/version.json +1 -1
- package/dist/types/api/EmojiResource.d.ts +2 -0
- package/dist/types/components/common/Emoji.d.ts +7 -1
- package/dist/types/components/common/EmojiActions.d.ts +4 -3
- package/dist/types/components/common/{EmojiButton.d.ts → EmojiRadioButton.d.ts} +3 -4
- package/dist/types/components/common/EmojiUploadPicker.d.ts +6 -4
- package/dist/types/components/common/RetryableButton.d.ts +1 -0
- package/dist/types/components/common/TonePreviewButton.d.ts +14 -0
- package/dist/types/components/common/ToneSelector.d.ts +8 -5
- package/dist/types/components/common/internal-types.d.ts +9 -0
- package/dist/types/components/common/styles.d.ts +2 -1
- package/dist/types/components/i18n.d.ts +40 -0
- package/dist/types/components/picker/CategorySelector.d.ts +3 -10
- package/dist/types/components/picker/CategoryTracker.d.ts +0 -2
- package/dist/types/components/picker/EmojiPickerCategoryHeading.d.ts +2 -1
- package/dist/types/components/picker/EmojiPickerEmojiRow.d.ts +5 -0
- package/dist/types/components/picker/EmojiPickerList.d.ts +14 -7
- package/dist/types/components/picker/EmojiPickerListSearch.d.ts +4 -8
- package/dist/types/components/picker/EmojiPickerVirtualItems.d.ts +1 -1
- package/dist/types/components/picker/VirtualList.d.ts +7 -24
- package/dist/types/components/picker/styles.d.ts +1 -1
- package/dist/types/context/EmojiPickerListContext.d.ts +10 -0
- package/dist/types/hooks/useEmojiPickerListContext.d.ts +1 -0
- package/dist/types/hooks/useIsMounted.d.ts +1 -0
- package/dist/types/i18n/cs.d.ts +34 -34
- package/dist/types/i18n/da.d.ts +34 -34
- package/dist/types/i18n/de.d.ts +34 -34
- package/dist/types/i18n/en.d.ts +34 -34
- package/dist/types/i18n/en_GB.d.ts +34 -34
- package/dist/types/i18n/es.d.ts +34 -34
- package/dist/types/i18n/fi.d.ts +34 -34
- package/dist/types/i18n/fr.d.ts +34 -34
- package/dist/types/i18n/hu.d.ts +34 -34
- package/dist/types/i18n/it.d.ts +34 -34
- package/dist/types/i18n/ja.d.ts +34 -34
- package/dist/types/i18n/ko.d.ts +34 -34
- package/dist/types/i18n/nb.d.ts +34 -34
- package/dist/types/i18n/nl.d.ts +34 -34
- package/dist/types/i18n/pl.d.ts +34 -34
- package/dist/types/i18n/pt_BR.d.ts +34 -34
- package/dist/types/i18n/ru.d.ts +34 -34
- package/dist/types/i18n/sv.d.ts +34 -34
- package/dist/types/i18n/th.d.ts +34 -34
- package/dist/types/i18n/tr.d.ts +34 -34
- package/dist/types/i18n/uk.d.ts +34 -34
- package/dist/types/i18n/vi.d.ts +34 -34
- package/dist/types/i18n/zh.d.ts +34 -34
- package/dist/types/i18n/zh_TW.d.ts +34 -34
- package/dist/types/types.d.ts +5 -0
- package/dist/types/util/constants.d.ts +28 -0
- package/dist/types/util/shared-styles.d.ts +1 -1
- package/dist/types/util/type-helpers.d.ts +1 -1
- package/package.json +12 -8
- package/report.api.md +62 -1
- package/README.md +0 -3
- package/dist/cjs/components/hooks.js +0 -14
- package/dist/es2019/components/common/EmojiButton.js +0 -49
- package/dist/es2019/components/hooks.js +0 -8
- package/dist/esm/components/common/EmojiButton.js +0 -43
- package/dist/esm/components/hooks.js +0 -8
- package/dist/types/components/hooks.d.ts +0 -1
|
@@ -40,10 +40,10 @@ export default class TokenManager {
|
|
|
40
40
|
// still valid
|
|
41
41
|
return Promise.resolve(mediaApiToken);
|
|
42
42
|
}
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
43
|
+
}
|
|
44
|
+
if (activeTokenRefresh) {
|
|
45
|
+
// refresh token promise already active, return that
|
|
46
|
+
return activeTokenRefresh;
|
|
47
47
|
}
|
|
48
48
|
|
|
49
49
|
// request a new token and track the promise for future requests until completed
|
|
@@ -19,7 +19,9 @@ export const CachingEmoji = props => {
|
|
|
19
19
|
// Optimisation to only render CachingMediaEmoji if necessary
|
|
20
20
|
// slight performance hit, which accumulates for a large number of emoji.
|
|
21
21
|
const {
|
|
22
|
-
emoji
|
|
22
|
+
emoji,
|
|
23
|
+
placeholderSize,
|
|
24
|
+
...restProps
|
|
23
25
|
} = props;
|
|
24
26
|
// start emoji rendered experience, it may have already started earlier in `ResourcedEmoji`.
|
|
25
27
|
useSampledUFOComponentExperience(ufoExperiences['emoji-rendered'].getInstance(emoji.id || emoji.shortName), SAMPLING_RATE_EMOJI_RENDERED_EXP, {
|
|
@@ -34,9 +36,14 @@ export const CachingEmoji = props => {
|
|
|
34
36
|
}, []);
|
|
35
37
|
const emojiNode = () => {
|
|
36
38
|
if (isMediaEmoji(emoji)) {
|
|
37
|
-
return /*#__PURE__*/React.createElement(CachingMediaEmoji,
|
|
39
|
+
return /*#__PURE__*/React.createElement(CachingMediaEmoji, _extends({
|
|
40
|
+
emoji: emoji,
|
|
41
|
+
placeholderSize: placeholderSize
|
|
42
|
+
}, restProps));
|
|
38
43
|
}
|
|
39
|
-
return /*#__PURE__*/React.createElement(Emoji,
|
|
44
|
+
return /*#__PURE__*/React.createElement(Emoji, _extends({
|
|
45
|
+
emoji: emoji
|
|
46
|
+
}, restProps));
|
|
40
47
|
};
|
|
41
48
|
return /*#__PURE__*/React.createElement(UfoErrorBoundary, {
|
|
42
49
|
experiences: [ufoExperiences['emoji-rendered'].getInstance(props.emoji.id || props.emoji.shortName)]
|
|
@@ -50,6 +50,15 @@ const handleMouseMove = (props, event) => {
|
|
|
50
50
|
onMouseMove(toEmojiId(emoji), emoji, event);
|
|
51
51
|
}
|
|
52
52
|
};
|
|
53
|
+
const handleFocus = (props, event) => {
|
|
54
|
+
const {
|
|
55
|
+
emoji,
|
|
56
|
+
onFocus
|
|
57
|
+
} = props;
|
|
58
|
+
if (onFocus) {
|
|
59
|
+
onFocus(toEmojiId(emoji), emoji, event);
|
|
60
|
+
}
|
|
61
|
+
};
|
|
53
62
|
const handleDelete = (props, event) => {
|
|
54
63
|
const {
|
|
55
64
|
emoji,
|
|
@@ -86,7 +95,18 @@ export const SpriteEmoji = props => {
|
|
|
86
95
|
selectOnHover,
|
|
87
96
|
className,
|
|
88
97
|
showTooltip,
|
|
89
|
-
shouldBeInteractive
|
|
98
|
+
shouldBeInteractive = false,
|
|
99
|
+
tabIndex,
|
|
100
|
+
onSelected,
|
|
101
|
+
onMouseMove,
|
|
102
|
+
onFocus,
|
|
103
|
+
onDelete,
|
|
104
|
+
onLoadError,
|
|
105
|
+
onLoadSuccess,
|
|
106
|
+
showDelete,
|
|
107
|
+
disableLazyLoad,
|
|
108
|
+
autoWidth,
|
|
109
|
+
...other
|
|
90
110
|
} = props;
|
|
91
111
|
const representation = emoji.representation;
|
|
92
112
|
const sprite = representation.sprite;
|
|
@@ -108,11 +128,11 @@ export const SpriteEmoji = props => {
|
|
|
108
128
|
backgroundSize: `${sprite.column * 100}% ${sprite.row * 100}%`,
|
|
109
129
|
...sizing
|
|
110
130
|
};
|
|
111
|
-
return jsx("span", {
|
|
131
|
+
return jsx("span", _extends({
|
|
112
132
|
"data-testid": `sprite-emoji-${emoji.shortName}`,
|
|
113
133
|
"data-emoji-type": "sprite",
|
|
114
|
-
tabIndex: shouldBeInteractive ? 0 : undefined,
|
|
115
|
-
role: shouldBeInteractive ? 'button' :
|
|
134
|
+
tabIndex: shouldBeInteractive ? tabIndex || 0 : undefined,
|
|
135
|
+
role: shouldBeInteractive ? 'button' : 'img',
|
|
116
136
|
css: emojiContainer,
|
|
117
137
|
className: classes,
|
|
118
138
|
onKeyPress: event => handleKeyPress(props, event),
|
|
@@ -122,9 +142,12 @@ export const SpriteEmoji = props => {
|
|
|
122
142
|
onMouseEnter: event => {
|
|
123
143
|
handleMouseMove(props, event);
|
|
124
144
|
},
|
|
145
|
+
onFocus: event => {
|
|
146
|
+
handleFocus(props, event);
|
|
147
|
+
},
|
|
125
148
|
"aria-label": emoji.shortName,
|
|
126
149
|
title: showTooltip ? emoji.shortName : ''
|
|
127
|
-
}, jsx("span", {
|
|
150
|
+
}, other), jsx("span", {
|
|
128
151
|
className: emojiSprite,
|
|
129
152
|
style: style
|
|
130
153
|
}, "\xA0"));
|
|
@@ -140,10 +163,17 @@ export const ImageEmoji = props => {
|
|
|
140
163
|
className,
|
|
141
164
|
showTooltip,
|
|
142
165
|
showDelete,
|
|
143
|
-
shouldBeInteractive,
|
|
166
|
+
shouldBeInteractive = false,
|
|
167
|
+
tabIndex,
|
|
168
|
+
onSelected,
|
|
169
|
+
onMouseMove,
|
|
170
|
+
onFocus,
|
|
171
|
+
onDelete,
|
|
172
|
+
onLoadError,
|
|
144
173
|
onLoadSuccess,
|
|
145
174
|
disableLazyLoad,
|
|
146
|
-
autoWidth
|
|
175
|
+
autoWidth,
|
|
176
|
+
...other
|
|
147
177
|
} = props;
|
|
148
178
|
const [ref, inView] = useInView({
|
|
149
179
|
triggerOnce: true
|
|
@@ -233,12 +263,12 @@ export const ImageEmoji = props => {
|
|
|
233
263
|
onError: onError,
|
|
234
264
|
onLoad: onLoad
|
|
235
265
|
}, sizing));
|
|
236
|
-
return jsx("span", {
|
|
266
|
+
return jsx("span", _extends({
|
|
237
267
|
"data-testid": `image-emoji-${emoji.shortName}`,
|
|
238
268
|
"data-emoji-type": "image",
|
|
239
269
|
css: emojiStyles,
|
|
240
|
-
tabIndex: shouldBeInteractive ? 0 : undefined,
|
|
241
|
-
role: shouldBeInteractive ? 'button' :
|
|
270
|
+
tabIndex: shouldBeInteractive ? tabIndex || 0 : undefined,
|
|
271
|
+
role: shouldBeInteractive ? 'button' : 'img',
|
|
242
272
|
className: classes,
|
|
243
273
|
onKeyPress: event => handleKeyPress(props, event),
|
|
244
274
|
onMouseDown: event => {
|
|
@@ -247,10 +277,13 @@ export const ImageEmoji = props => {
|
|
|
247
277
|
onMouseEnter: event => {
|
|
248
278
|
handleMouseMove(props, event);
|
|
249
279
|
},
|
|
280
|
+
onFocus: event => {
|
|
281
|
+
handleFocus(props, event);
|
|
282
|
+
},
|
|
250
283
|
"aria-label": emoji.shortName,
|
|
251
284
|
title: showTooltip ? emoji.shortName : '',
|
|
252
285
|
ref: ref
|
|
253
|
-
}, deleteButton, emojiNode);
|
|
286
|
+
}, other), deleteButton, emojiNode);
|
|
254
287
|
};
|
|
255
288
|
export const Emoji = props => {
|
|
256
289
|
const {
|
|
@@ -1,19 +1,20 @@
|
|
|
1
1
|
import _extends from "@babel/runtime/helpers/extends";
|
|
2
2
|
/** @jsx jsx */
|
|
3
|
-
import { Fragment, useState } from 'react';
|
|
3
|
+
import { Fragment, useState, useRef, useEffect, memo } from 'react';
|
|
4
4
|
import { jsx } from '@emotion/react';
|
|
5
5
|
import { FormattedMessage, injectIntl } from 'react-intl-next';
|
|
6
6
|
import EmojiDeletePreview from '../common/EmojiDeletePreview';
|
|
7
7
|
import EmojiUploadPicker from '../common/EmojiUploadPicker';
|
|
8
|
-
import EmojiPickerListSearch from '../picker/EmojiPickerListSearch';
|
|
8
|
+
import { EmojiPickerListSearch } from '../picker/EmojiPickerListSearch';
|
|
9
9
|
import ToneSelector from './ToneSelector';
|
|
10
|
-
import
|
|
10
|
+
import TonePreviewButton from './TonePreviewButton';
|
|
11
11
|
import { messages } from '../i18n';
|
|
12
12
|
import AkButton from '@atlaskit/button/standard-button';
|
|
13
13
|
import AddIcon from '@atlaskit/icon/glyph/add';
|
|
14
14
|
import { setSkinToneAriaLabelText } from './setSkinToneAriaLabelText';
|
|
15
15
|
import { addCustomEmoji, addCustomEmojiButton, emojiActionsWrapper, emojiPickerAddEmoji, emojiToneSelectorContainer } from './styles';
|
|
16
16
|
import { emojiActionsContainerWithBottomShadow, emojiPickerFooter } from '../picker/styles';
|
|
17
|
+
import { DEFAULT_TONE } from '../../util/constants';
|
|
17
18
|
export const emojiActionsTestId = 'emoji-actions';
|
|
18
19
|
export const uploadEmojiTestId = 'upload-emoji';
|
|
19
20
|
|
|
@@ -22,10 +23,7 @@ export const uploadEmojiTestId = 'upload-emoji';
|
|
|
22
23
|
const AddOwnEmoji = props => {
|
|
23
24
|
const {
|
|
24
25
|
onOpenUpload,
|
|
25
|
-
uploadEnabled
|
|
26
|
-
intl: {
|
|
27
|
-
formatMessage
|
|
28
|
-
}
|
|
26
|
+
uploadEnabled
|
|
29
27
|
} = props;
|
|
30
28
|
return jsx(Fragment, null, uploadEnabled && jsx("div", {
|
|
31
29
|
css: addCustomEmoji,
|
|
@@ -33,47 +31,76 @@ const AddOwnEmoji = props => {
|
|
|
33
31
|
}, jsx(FormattedMessage, messages.addCustomEmojiLabel, label => jsx(AkButton, {
|
|
34
32
|
onClick: onOpenUpload,
|
|
35
33
|
iconBefore: jsx(AddIcon, {
|
|
36
|
-
label:
|
|
34
|
+
label: "",
|
|
37
35
|
size: "small"
|
|
38
36
|
}),
|
|
39
37
|
appearance: "subtle",
|
|
40
38
|
css: addCustomEmojiButton,
|
|
41
|
-
className: emojiPickerAddEmoji
|
|
39
|
+
className: emojiPickerAddEmoji,
|
|
40
|
+
tabIndex: 0,
|
|
41
|
+
id: "add-custom-emoji"
|
|
42
42
|
}, label))));
|
|
43
43
|
};
|
|
44
44
|
const TonesWrapper = props => {
|
|
45
45
|
const {
|
|
46
46
|
toneEmoji,
|
|
47
|
-
selectedTone,
|
|
47
|
+
selectedTone = DEFAULT_TONE,
|
|
48
48
|
intl,
|
|
49
|
-
onToneSelected,
|
|
50
49
|
onToneOpen,
|
|
51
50
|
showToneSelector
|
|
52
51
|
} = props;
|
|
53
52
|
const {
|
|
54
53
|
formatMessage
|
|
55
54
|
} = intl;
|
|
55
|
+
const tonePreviewButtonRef = useRef(null);
|
|
56
|
+
const [focusTonePreviewButton, setFocusTonePreviewButton] = useState(false);
|
|
57
|
+
useEffect(() => {
|
|
58
|
+
if (focusTonePreviewButton && tonePreviewButtonRef.current) {
|
|
59
|
+
tonePreviewButtonRef.current.focus();
|
|
60
|
+
}
|
|
61
|
+
return () => {
|
|
62
|
+
setFocusTonePreviewButton(false);
|
|
63
|
+
};
|
|
64
|
+
});
|
|
65
|
+
const onToneCloseHandler = () => {
|
|
66
|
+
const {
|
|
67
|
+
onToneClose
|
|
68
|
+
} = props;
|
|
69
|
+
onToneClose();
|
|
70
|
+
setFocusTonePreviewButton(true);
|
|
71
|
+
};
|
|
72
|
+
const onToneSelectedHandler = toneValue => {
|
|
73
|
+
const {
|
|
74
|
+
onToneSelected
|
|
75
|
+
} = props;
|
|
76
|
+
onToneSelected(toneValue);
|
|
77
|
+
setFocusTonePreviewButton(true);
|
|
78
|
+
};
|
|
56
79
|
if (!toneEmoji) {
|
|
57
80
|
return null;
|
|
58
81
|
}
|
|
59
|
-
let
|
|
60
|
-
if (selectedTone &&
|
|
61
|
-
|
|
82
|
+
let previewToneEmoji = toneEmoji;
|
|
83
|
+
if (selectedTone !== DEFAULT_TONE && previewToneEmoji.skinVariations) {
|
|
84
|
+
previewToneEmoji = previewToneEmoji.skinVariations[selectedTone - 1];
|
|
62
85
|
}
|
|
63
86
|
return jsx("div", {
|
|
64
87
|
css: emojiToneSelectorContainer
|
|
65
|
-
},
|
|
88
|
+
}, jsx(ToneSelector, {
|
|
66
89
|
emoji: toneEmoji,
|
|
67
|
-
onToneSelected:
|
|
68
|
-
|
|
69
|
-
|
|
90
|
+
onToneSelected: onToneSelectedHandler,
|
|
91
|
+
onToneClose: onToneCloseHandler,
|
|
92
|
+
selectedTone: selectedTone,
|
|
93
|
+
isVisible: showToneSelector
|
|
94
|
+
}), jsx(TonePreviewButton, {
|
|
95
|
+
ref: tonePreviewButtonRef,
|
|
70
96
|
ariaExpanded: showToneSelector,
|
|
71
|
-
emoji:
|
|
97
|
+
emoji: previewToneEmoji,
|
|
72
98
|
selectOnHover: true,
|
|
73
99
|
onSelected: onToneOpen,
|
|
74
100
|
ariaLabelText: formatMessage(messages.emojiSelectSkinToneButtonAriaLabelText, {
|
|
75
|
-
selectedTone: `${setSkinToneAriaLabelText(
|
|
76
|
-
})
|
|
101
|
+
selectedTone: `${setSkinToneAriaLabelText(previewToneEmoji.name)}`
|
|
102
|
+
}),
|
|
103
|
+
isVisible: !showToneSelector
|
|
77
104
|
}));
|
|
78
105
|
};
|
|
79
106
|
export const EmojiActions = props => {
|
|
@@ -90,11 +117,13 @@ export const EmojiActions = props => {
|
|
|
90
117
|
onFileChooserClicked,
|
|
91
118
|
emojiToDelete,
|
|
92
119
|
onChange,
|
|
93
|
-
query
|
|
120
|
+
query,
|
|
121
|
+
resultsCount = 0
|
|
94
122
|
} = props;
|
|
95
123
|
const [showToneSelector, setShowToneSelector] = useState(false);
|
|
96
124
|
const previewFooterClassnames = [emojiPickerFooter, emojiActionsContainerWithBottomShadow];
|
|
97
125
|
const onToneOpenHandler = () => setShowToneSelector(true);
|
|
126
|
+
const onToneCloseHandler = () => setShowToneSelector(false);
|
|
98
127
|
const onToneSelectedHandler = toneValue => {
|
|
99
128
|
setShowToneSelector(false);
|
|
100
129
|
if (onToneSelected) {
|
|
@@ -135,11 +164,13 @@ export const EmojiActions = props => {
|
|
|
135
164
|
css: emojiActionsWrapper
|
|
136
165
|
}, !showToneSelector && jsx(EmojiPickerListSearch, {
|
|
137
166
|
onChange: onChange,
|
|
138
|
-
query: query
|
|
167
|
+
query: query,
|
|
168
|
+
resultsCount: resultsCount
|
|
139
169
|
}), jsx(TonesWrapper, _extends({}, props, {
|
|
140
170
|
onToneOpen: onToneOpenHandler,
|
|
171
|
+
onToneClose: onToneCloseHandler,
|
|
141
172
|
onToneSelected: onToneSelectedHandler,
|
|
142
173
|
showToneSelector: showToneSelector
|
|
143
174
|
}))), jsx(AddOwnEmoji, props));
|
|
144
175
|
};
|
|
145
|
-
export default injectIntl(EmojiActions);
|
|
176
|
+
export default injectIntl( /*#__PURE__*/memo(EmojiActions));
|
|
@@ -1,8 +1,9 @@
|
|
|
1
1
|
/** @jsx jsx */
|
|
2
|
-
|
|
2
|
+
import { Fragment } from 'react';
|
|
3
3
|
import { jsx } from '@emotion/react';
|
|
4
4
|
import Tooltip from '@atlaskit/tooltip';
|
|
5
5
|
import ErrorIcon from '@atlaskit/icon/glyph/error';
|
|
6
|
+
import VisuallyHidden from '@atlaskit/visually-hidden';
|
|
6
7
|
export const emojiErrorMessageTestId = 'emoji-error-message';
|
|
7
8
|
export const emojiErrorMessageTooltipTestId = 'emoji-error-message-tooltip';
|
|
8
9
|
export const emojiErrorIconTestId = 'emoji-error-icon';
|
|
@@ -12,7 +13,7 @@ const EmojiErrorMessage = props => {
|
|
|
12
13
|
message,
|
|
13
14
|
tooltip
|
|
14
15
|
} = props;
|
|
15
|
-
|
|
16
|
+
const visualContent = tooltip ? jsx("div", {
|
|
16
17
|
css: messageStyles,
|
|
17
18
|
"data-testid": emojiErrorMessageTestId
|
|
18
19
|
}, jsx(Tooltip, {
|
|
@@ -29,6 +30,9 @@ const EmojiErrorMessage = props => {
|
|
|
29
30
|
}, jsx(ErrorIcon, {
|
|
30
31
|
label: "Error",
|
|
31
32
|
size: "small"
|
|
32
|
-
}),
|
|
33
|
+
}), message);
|
|
34
|
+
return jsx(Fragment, null, jsx(VisuallyHidden, {
|
|
35
|
+
role: "alert"
|
|
36
|
+
}, message), visualContent);
|
|
33
37
|
};
|
|
34
38
|
export default EmojiErrorMessage;
|
|
@@ -32,6 +32,7 @@ const EmojiPlaceholder = props => {
|
|
|
32
32
|
return jsx("span", {
|
|
33
33
|
"data-testid": emojiPlaceholderTestId(shortName),
|
|
34
34
|
"aria-busy": loading,
|
|
35
|
+
role: "status",
|
|
35
36
|
"aria-label": shortName,
|
|
36
37
|
className: placeholder,
|
|
37
38
|
css: loading ? [placeholderContainer, placeholderContainerAnimated] : placeholderContainer,
|
|
@@ -0,0 +1,54 @@
|
|
|
1
|
+
/** @jsx jsx */
|
|
2
|
+
import React, { memo, forwardRef } from 'react';
|
|
3
|
+
import { jsx } from '@emotion/react';
|
|
4
|
+
import { leftClick } from '../../util/mouse';
|
|
5
|
+
import { emojiButton, emojiRadio } from './styles';
|
|
6
|
+
import Emoji from './Emoji';
|
|
7
|
+
import { TONESELECTOR_KEYBOARD_KEYS_SUPPORTED } from '../../util/constants';
|
|
8
|
+
import VisuallyHidden from '@atlaskit/visually-hidden';
|
|
9
|
+
const handleMouseDown = (props, event) => {
|
|
10
|
+
const {
|
|
11
|
+
onSelected
|
|
12
|
+
} = props;
|
|
13
|
+
event.preventDefault();
|
|
14
|
+
if (onSelected && leftClick(event)) {
|
|
15
|
+
onSelected();
|
|
16
|
+
}
|
|
17
|
+
};
|
|
18
|
+
const handleKeyPress = (props, event) => {
|
|
19
|
+
if (TONESELECTOR_KEYBOARD_KEYS_SUPPORTED.includes(event.key)) {
|
|
20
|
+
const {
|
|
21
|
+
onSelected
|
|
22
|
+
} = props;
|
|
23
|
+
event.preventDefault();
|
|
24
|
+
if (onSelected) {
|
|
25
|
+
onSelected();
|
|
26
|
+
}
|
|
27
|
+
}
|
|
28
|
+
};
|
|
29
|
+
export const EmojiRadioButton = /*#__PURE__*/forwardRef((props, ref) => {
|
|
30
|
+
const {
|
|
31
|
+
emoji,
|
|
32
|
+
selectOnHover,
|
|
33
|
+
ariaLabelText,
|
|
34
|
+
defaultChecked
|
|
35
|
+
} = props;
|
|
36
|
+
return jsx("label", {
|
|
37
|
+
css: emojiButton,
|
|
38
|
+
onMouseDown: event => handleMouseDown(props, event),
|
|
39
|
+
onKeyDown: event => handleKeyPress(props, event)
|
|
40
|
+
}, jsx(VisuallyHidden, null, ariaLabelText), jsx("input", {
|
|
41
|
+
ref: ref,
|
|
42
|
+
"data-testid": ariaLabelText,
|
|
43
|
+
type: "radio",
|
|
44
|
+
name: "skin-tone",
|
|
45
|
+
css: emojiRadio,
|
|
46
|
+
defaultChecked: defaultChecked
|
|
47
|
+
}), jsx(Emoji, {
|
|
48
|
+
emoji: emoji,
|
|
49
|
+
selectOnHover: selectOnHover,
|
|
50
|
+
shouldBeInteractive: false,
|
|
51
|
+
"aria-hidden": true
|
|
52
|
+
}));
|
|
53
|
+
});
|
|
54
|
+
export default /*#__PURE__*/memo(EmojiRadioButton);
|
|
@@ -1,10 +1,11 @@
|
|
|
1
1
|
/** @jsx jsx */
|
|
2
|
-
import
|
|
2
|
+
import { Fragment, useEffect, useState, useRef, memo, useCallback, useMemo } from 'react';
|
|
3
3
|
import { jsx } from '@emotion/react';
|
|
4
4
|
import { FormattedMessage, injectIntl } from 'react-intl-next';
|
|
5
5
|
import TextField from '@atlaskit/textfield';
|
|
6
6
|
import CrossIcon from '@atlaskit/icon/glyph/cross';
|
|
7
7
|
import AkButton from '@atlaskit/button/standard-button';
|
|
8
|
+
import FocusLock from 'react-focus-lock';
|
|
8
9
|
import * as ImageUtil from '../../util/image';
|
|
9
10
|
import debug from '../../util/logger';
|
|
10
11
|
import { messages } from '../i18n';
|
|
@@ -14,6 +15,8 @@ import FileChooser from './FileChooser';
|
|
|
14
15
|
import { UploadStatus } from './internal-types';
|
|
15
16
|
import { closeEmojiUploadButton, emojiChooseFileErrorMessage, emojiUpload, emojiUploadBottom, emojiUploadTop, uploadChooseFileBrowse, uploadChooseFileEmojiName, uploadChooseFileMessage, uploadChooseFileRow } from './styles';
|
|
16
17
|
export const uploadEmojiNameInputTestId = 'upload-emoji-name-input';
|
|
18
|
+
export const uploadEmojiComponentTestId = 'upload-emoji-component';
|
|
19
|
+
export const cancelEmojiUploadPickerTestId = 'cancel-emoji-upload-picker';
|
|
17
20
|
const disallowedReplacementsMap = new Map([[':', ''], ['!', ''], ['@', ''], ['#', ''], ['%', ''], ['^', ''], ['&', ''], ['*', ''], ['(', ''], [')', ''], [' ', '_']]);
|
|
18
21
|
const sanitizeName = name => {
|
|
19
22
|
// prevent / replace certain characters, allow others
|
|
@@ -27,7 +30,7 @@ const toEmojiName = uploadName => {
|
|
|
27
30
|
const name = uploadName.split('_').join(' ');
|
|
28
31
|
return `${name.substr(0, 1).toLocaleUpperCase()}${name.substr(1)}`;
|
|
29
32
|
};
|
|
30
|
-
const ChooseEmojiFile = props => {
|
|
33
|
+
const ChooseEmojiFile = /*#__PURE__*/memo(props => {
|
|
31
34
|
const {
|
|
32
35
|
name = '',
|
|
33
36
|
onChooseFile,
|
|
@@ -42,13 +45,31 @@ const ChooseEmojiFile = props => {
|
|
|
42
45
|
} = intl;
|
|
43
46
|
const disableChooser = !name;
|
|
44
47
|
const fileChooserButtonDescriptionId = 'choose.emoji.file.button.screen.reader.description.id';
|
|
45
|
-
const
|
|
48
|
+
const inputRef = useRef(null);
|
|
49
|
+
const onKeyDownHandler = useCallback(event => {
|
|
46
50
|
if (event.key === 'Escape') {
|
|
47
51
|
onUploadCancelled();
|
|
48
52
|
}
|
|
49
|
-
};
|
|
53
|
+
}, [onUploadCancelled]);
|
|
54
|
+
const setInputFocus = useCallback(() => {
|
|
55
|
+
var _inputRef$current, _document$activeEleme, _inputRef$current2;
|
|
56
|
+
(_inputRef$current = inputRef.current) === null || _inputRef$current === void 0 ? void 0 : _inputRef$current.focus();
|
|
57
|
+
if (((_document$activeEleme = document.activeElement) === null || _document$activeEleme === void 0 ? void 0 : _document$activeEleme.id) !== ((_inputRef$current2 = inputRef.current) === null || _inputRef$current2 === void 0 ? void 0 : _inputRef$current2.id)) {
|
|
58
|
+
setInputFocus();
|
|
59
|
+
}
|
|
60
|
+
}, []);
|
|
61
|
+
|
|
62
|
+
// make sure input has focus after update
|
|
63
|
+
useEffect(() => {
|
|
64
|
+
window.requestAnimationFrame(setInputFocus);
|
|
65
|
+
}, [setInputFocus]);
|
|
66
|
+
const cancelLabel = formatMessage(messages.cancelLabel);
|
|
67
|
+
const emojiPlaceholder = formatMessage(messages.emojiPlaceholder);
|
|
68
|
+
const emojiNameAriaLabel = formatMessage(messages.emojiNameAriaLabel);
|
|
69
|
+
const emojiChooseFileTitle = formatMessage(messages.emojiChooseFileTitle);
|
|
50
70
|
return jsx("div", {
|
|
51
|
-
css: emojiUpload
|
|
71
|
+
css: emojiUpload,
|
|
72
|
+
"data-testid": uploadEmojiComponentTestId
|
|
52
73
|
}, jsx("div", {
|
|
53
74
|
css: emojiUploadTop
|
|
54
75
|
}, jsx("span", {
|
|
@@ -57,34 +78,37 @@ const ChooseEmojiFile = props => {
|
|
|
57
78
|
css: closeEmojiUploadButton
|
|
58
79
|
}, jsx(AkButton, {
|
|
59
80
|
onClick: onUploadCancelled,
|
|
60
|
-
"aria-
|
|
81
|
+
"aria-label": cancelLabel,
|
|
61
82
|
appearance: "subtle",
|
|
62
83
|
spacing: "none",
|
|
63
|
-
shouldFitContainer: true
|
|
84
|
+
shouldFitContainer: true,
|
|
85
|
+
testId: cancelEmojiUploadPickerTestId
|
|
64
86
|
}, jsx(CrossIcon, {
|
|
65
87
|
size: "small",
|
|
66
|
-
label:
|
|
88
|
+
label: cancelLabel
|
|
67
89
|
})))), jsx("div", {
|
|
68
90
|
css: uploadChooseFileRow
|
|
69
91
|
}, jsx("span", {
|
|
70
92
|
css: uploadChooseFileEmojiName
|
|
71
93
|
}, jsx(TextField, {
|
|
72
|
-
placeholder:
|
|
73
|
-
"aria-label":
|
|
94
|
+
placeholder: emojiPlaceholder,
|
|
95
|
+
"aria-label": emojiNameAriaLabel,
|
|
74
96
|
maxLength: maxNameLength,
|
|
75
97
|
onChange: onNameChange,
|
|
76
98
|
onKeyDown: onKeyDownHandler,
|
|
77
99
|
value: name,
|
|
78
100
|
isCompact: true,
|
|
79
101
|
autoFocus: true,
|
|
80
|
-
testId: uploadEmojiNameInputTestId
|
|
102
|
+
testId: uploadEmojiNameInputTestId,
|
|
103
|
+
ref: inputRef,
|
|
104
|
+
id: "new-emoji-name-input"
|
|
81
105
|
})), jsx("span", {
|
|
82
106
|
css: uploadChooseFileBrowse
|
|
83
107
|
}, jsx(FormattedMessage, messages.emojiChooseFileScreenReaderDescription, screenReaderDescription => jsx(Fragment, null, jsx("span", {
|
|
84
108
|
hidden: true,
|
|
85
109
|
id: fileChooserButtonDescriptionId
|
|
86
110
|
}, screenReaderDescription), jsx(FileChooser, {
|
|
87
|
-
label:
|
|
111
|
+
label: emojiChooseFileTitle,
|
|
88
112
|
onChange: onChooseFile,
|
|
89
113
|
onClick: onClick,
|
|
90
114
|
accept: "image/png,image/jpeg,image/gif",
|
|
@@ -96,8 +120,9 @@ const ChooseEmojiFile = props => {
|
|
|
96
120
|
messageStyles: emojiChooseFileErrorMessage,
|
|
97
121
|
message: errorMessage
|
|
98
122
|
})));
|
|
99
|
-
};
|
|
123
|
+
});
|
|
100
124
|
const EmojiUploadPicker = props => {
|
|
125
|
+
var _document$activeEleme2;
|
|
101
126
|
const {
|
|
102
127
|
errorMessage,
|
|
103
128
|
initialUploadName,
|
|
@@ -111,6 +136,8 @@ const EmojiUploadPicker = props => {
|
|
|
111
136
|
const [name, setName] = useState(initialUploadName && sanitizeName(initialUploadName));
|
|
112
137
|
const [filename, setFilename] = useState();
|
|
113
138
|
const [previewImage, setPreviewImage] = useState();
|
|
139
|
+
// document is undefined during ssr rendering and throws an error
|
|
140
|
+
const lastFocusedElementId = useRef(typeof document !== 'undefined' ? (_document$activeEleme2 = document.activeElement) === null || _document$activeEleme2 === void 0 ? void 0 : _document$activeEleme2.id : '');
|
|
114
141
|
useEffect(() => {
|
|
115
142
|
if (errorMessage) {
|
|
116
143
|
setUploadStatus(UploadStatus.Error);
|
|
@@ -126,13 +153,18 @@ const EmojiUploadPicker = props => {
|
|
|
126
153
|
setName(sanitizeName(initialUploadName));
|
|
127
154
|
}
|
|
128
155
|
}, [initialUploadName]);
|
|
129
|
-
const
|
|
156
|
+
const clearUploadPicker = useCallback(() => {
|
|
157
|
+
setName(undefined);
|
|
158
|
+
setPreviewImage(undefined);
|
|
159
|
+
setUploadStatus(UploadStatus.Waiting);
|
|
160
|
+
}, []);
|
|
161
|
+
const onNameChange = useCallback(event => {
|
|
130
162
|
let newName = sanitizeName(event.target.value);
|
|
131
163
|
if (name !== newName) {
|
|
132
164
|
setName(newName);
|
|
133
165
|
}
|
|
134
|
-
};
|
|
135
|
-
const onAddEmoji = () => {
|
|
166
|
+
}, [name]);
|
|
167
|
+
const onAddEmoji = useCallback(() => {
|
|
136
168
|
if (uploadStatus === UploadStatus.Uploading) {
|
|
137
169
|
return;
|
|
138
170
|
}
|
|
@@ -164,13 +196,16 @@ const EmojiUploadPicker = props => {
|
|
|
164
196
|
});
|
|
165
197
|
});
|
|
166
198
|
}
|
|
167
|
-
};
|
|
168
|
-
const
|
|
199
|
+
}, [clearUploadPicker, filename, name, onUploadEmoji, previewImage, uploadStatus]);
|
|
200
|
+
const cancelChooseFile = useCallback(() => {
|
|
201
|
+
setPreviewImage(undefined);
|
|
202
|
+
}, []);
|
|
203
|
+
const errorOnUpload = useCallback(event => {
|
|
169
204
|
debug('File load error: ', event);
|
|
170
205
|
setChooseEmojiErrorMessage(messages.emojiUploadFailed);
|
|
171
206
|
cancelChooseFile();
|
|
172
|
-
};
|
|
173
|
-
const onFileLoad = file => async f => {
|
|
207
|
+
}, [cancelChooseFile]);
|
|
208
|
+
const onFileLoad = useCallback(file => async f => {
|
|
174
209
|
try {
|
|
175
210
|
setFilename(file.name);
|
|
176
211
|
await ImageUtil.parseImage(f.target.result);
|
|
@@ -179,11 +214,8 @@ const EmojiUploadPicker = props => {
|
|
|
179
214
|
setChooseEmojiErrorMessage(messages.emojiInvalidImage);
|
|
180
215
|
cancelChooseFile();
|
|
181
216
|
}
|
|
182
|
-
};
|
|
183
|
-
const
|
|
184
|
-
setPreviewImage(undefined);
|
|
185
|
-
};
|
|
186
|
-
const onChooseFile = event => {
|
|
217
|
+
}, [cancelChooseFile]);
|
|
218
|
+
const onChooseFile = useCallback(event => {
|
|
187
219
|
const files = event.target.files;
|
|
188
220
|
if (files.length) {
|
|
189
221
|
const reader = new FileReader();
|
|
@@ -200,17 +232,23 @@ const EmojiUploadPicker = props => {
|
|
|
200
232
|
} else {
|
|
201
233
|
cancelChooseFile();
|
|
202
234
|
}
|
|
203
|
-
};
|
|
204
|
-
const
|
|
205
|
-
setName(undefined);
|
|
206
|
-
setPreviewImage(undefined);
|
|
207
|
-
setUploadStatus(UploadStatus.Waiting);
|
|
208
|
-
};
|
|
209
|
-
const cancelUpload = () => {
|
|
235
|
+
}, [cancelChooseFile, errorOnUpload, onFileLoad]);
|
|
236
|
+
const cancelUpload = useCallback(() => {
|
|
210
237
|
clearUploadPicker();
|
|
211
238
|
onUploadCancelled();
|
|
212
|
-
|
|
213
|
-
|
|
239
|
+
|
|
240
|
+
// using setTimeout here to allow the UI to update before setting focus
|
|
241
|
+
setTimeout(lastFocus => {
|
|
242
|
+
if (lastFocus) {
|
|
243
|
+
var _document$getElementB;
|
|
244
|
+
(_document$getElementB = document.getElementById(lastFocus)) === null || _document$getElementB === void 0 ? void 0 : _document$getElementB.focus();
|
|
245
|
+
}
|
|
246
|
+
}, 0, lastFocusedElementId.current);
|
|
247
|
+
}, [clearUploadPicker, onUploadCancelled]);
|
|
248
|
+
const chooseErrorMessage = useMemo(() => chooseEmojiErrorMessage ? jsx(FormattedMessage, chooseEmojiErrorMessage) : undefined, [chooseEmojiErrorMessage]);
|
|
249
|
+
return jsx(FocusLock, {
|
|
250
|
+
noFocusGuards: true
|
|
251
|
+
}, name && previewImage ? jsx(EmojiUploadPreview, {
|
|
214
252
|
errorMessage: errorMessage,
|
|
215
253
|
name: name,
|
|
216
254
|
onAddEmoji: onAddEmoji,
|
|
@@ -223,8 +261,9 @@ const EmojiUploadPicker = props => {
|
|
|
223
261
|
onClick: onFileChooserClicked,
|
|
224
262
|
onNameChange: onNameChange,
|
|
225
263
|
onUploadCancelled: cancelUpload,
|
|
226
|
-
errorMessage:
|
|
264
|
+
errorMessage: chooseErrorMessage,
|
|
227
265
|
intl: intl
|
|
228
266
|
}));
|
|
229
267
|
};
|
|
230
|
-
|
|
268
|
+
const EmojiUploadPickerComponent = injectIntl( /*#__PURE__*/memo(EmojiUploadPicker));
|
|
269
|
+
export default EmojiUploadPickerComponent;
|
|
@@ -11,8 +11,10 @@ import EmojiErrorMessage from './EmojiErrorMessage';
|
|
|
11
11
|
import { UploadStatus } from './internal-types';
|
|
12
12
|
import RetryableButton from './RetryableButton';
|
|
13
13
|
import { bigEmojiPreview, cancelButton, emojiPreviewErrorMessage, uploadAddRow, uploadPreview, uploadPreviewFooter, uploadPreviewText } from './styles';
|
|
14
|
+
import VisuallyHidden from '@atlaskit/visually-hidden';
|
|
14
15
|
export const uploadPreviewTestId = 'upload-preview';
|
|
15
16
|
export const cancelUploadButtonTestId = 'cancel-upload-button';
|
|
17
|
+
const addEmojiButtonDescriptionId = 'add.emoji.button.screen.reader.description.id';
|
|
16
18
|
class EmojiUploadPreview extends PureComponent {
|
|
17
19
|
render() {
|
|
18
20
|
const {
|
|
@@ -64,12 +66,19 @@ class EmojiUploadPreview extends PureComponent {
|
|
|
64
66
|
messageStyles: emojiPreviewErrorMessage,
|
|
65
67
|
message: errorMessage,
|
|
66
68
|
tooltip: true
|
|
67
|
-
}) : null, jsx(
|
|
69
|
+
}) : null, !errorMessage && jsx(VisuallyHidden, {
|
|
70
|
+
id: addEmojiButtonDescriptionId
|
|
71
|
+
}, jsx(FormattedMessage, _extends({}, messages.emojiPreview, {
|
|
72
|
+
values: {
|
|
73
|
+
emoji: name
|
|
74
|
+
}
|
|
75
|
+
}))), jsx(RetryableButton, {
|
|
68
76
|
label: formatMessage(messages.addEmojiLabel),
|
|
69
77
|
onSubmit: onAddEmoji,
|
|
70
78
|
appearance: "primary",
|
|
71
79
|
loading: uploading,
|
|
72
|
-
error: !!errorMessage
|
|
80
|
+
error: !!errorMessage,
|
|
81
|
+
ariaDescribedby: addEmojiButtonDescriptionId
|
|
73
82
|
}), jsx(AkButton, {
|
|
74
83
|
onClick: onUploadCancelled,
|
|
75
84
|
appearance: "subtle",
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import React, { useRef } from 'react';
|
|
2
|
-
import AkButton from '@atlaskit/button/
|
|
2
|
+
import AkButton from '@atlaskit/button/standard-button';
|
|
3
3
|
export const chooseFileButtonTestId = 'choose-file-button';
|
|
4
4
|
export const fileUploadInputTestId = 'file-upload';
|
|
5
5
|
const FileChooser = props => {
|