@atlaskit/emoji 71.0.0 → 71.0.1

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.
Files changed (55) hide show
  1. package/CHANGELOG.md +8 -0
  2. package/afm-cc/tsconfig.json +3 -0
  3. package/afm-products/tsconfig.json +3 -0
  4. package/dist/cjs/components/common/Emoji.js +2 -1
  5. package/dist/cjs/components/common/EmojiActions.compiled.css +8 -0
  6. package/dist/cjs/components/common/EmojiActions.js +69 -3
  7. package/dist/cjs/components/common/Popup.js +20 -5
  8. package/dist/cjs/components/common/ProductivityColorSelector.compiled.css +59 -0
  9. package/dist/cjs/components/common/ProductivityColorSelector.js +112 -0
  10. package/dist/cjs/components/common/TonePreviewButton.js +4 -2
  11. package/dist/cjs/components/i18n.js +10 -0
  12. package/dist/cjs/components/picker/EmojiPickerComponent.js +51 -36
  13. package/dist/cjs/components/picker/EmojiPickerList.js +36 -14
  14. package/dist/cjs/components/picker/VirtualList.js +4 -5
  15. package/dist/cjs/util/analytics/analytics.js +1 -1
  16. package/dist/cjs/util/hidden-emojis.js +33 -0
  17. package/dist/cjs/util/productivity-colors.js +51 -0
  18. package/dist/es2019/components/common/Emoji.js +2 -1
  19. package/dist/es2019/components/common/EmojiActions.compiled.css +8 -0
  20. package/dist/es2019/components/common/EmojiActions.js +67 -3
  21. package/dist/es2019/components/common/Popup.js +19 -5
  22. package/dist/es2019/components/common/ProductivityColorSelector.compiled.css +59 -0
  23. package/dist/es2019/components/common/ProductivityColorSelector.js +98 -0
  24. package/dist/es2019/components/common/TonePreviewButton.js +3 -2
  25. package/dist/es2019/components/i18n.js +10 -0
  26. package/dist/es2019/components/picker/EmojiPickerComponent.js +26 -14
  27. package/dist/es2019/components/picker/EmojiPickerList.js +32 -14
  28. package/dist/es2019/components/picker/VirtualList.js +4 -5
  29. package/dist/es2019/util/analytics/analytics.js +1 -1
  30. package/dist/es2019/util/hidden-emojis.js +25 -0
  31. package/dist/es2019/util/productivity-colors.js +37 -0
  32. package/dist/esm/components/common/Emoji.js +2 -1
  33. package/dist/esm/components/common/EmojiActions.compiled.css +8 -0
  34. package/dist/esm/components/common/EmojiActions.js +70 -4
  35. package/dist/esm/components/common/Popup.js +20 -5
  36. package/dist/esm/components/common/ProductivityColorSelector.compiled.css +59 -0
  37. package/dist/esm/components/common/ProductivityColorSelector.js +103 -0
  38. package/dist/esm/components/common/TonePreviewButton.js +4 -2
  39. package/dist/esm/components/i18n.js +10 -0
  40. package/dist/esm/components/picker/EmojiPickerComponent.js +51 -36
  41. package/dist/esm/components/picker/EmojiPickerList.js +36 -14
  42. package/dist/esm/components/picker/VirtualList.js +4 -5
  43. package/dist/esm/util/analytics/analytics.js +1 -1
  44. package/dist/esm/util/hidden-emojis.js +27 -0
  45. package/dist/esm/util/productivity-colors.js +45 -0
  46. package/dist/types/components/common/EmojiActions.d.ts +6 -0
  47. package/dist/types/components/common/Popup.d.ts +1 -0
  48. package/dist/types/components/common/ProductivityColorSelector.d.ts +17 -0
  49. package/dist/types/components/common/TonePreviewButton.d.ts +1 -0
  50. package/dist/types/components/i18n.d.ts +10 -0
  51. package/dist/types/components/picker/EmojiPickerList.d.ts +3 -0
  52. package/dist/types/types.d.ts +7 -0
  53. package/dist/types/util/hidden-emojis.d.ts +3 -0
  54. package/dist/types/util/productivity-colors.d.ts +8 -0
  55. package/package.json +3 -2
@@ -3,13 +3,15 @@ import _extends from "@babel/runtime/helpers/extends";
3
3
  import "./EmojiActions.compiled.css";
4
4
  import * as React from 'react';
5
5
  import { ax, ix } from "@compiled/react/runtime";
6
- import { Fragment, useState, useRef, memo, useLayoutEffect, useCallback } from 'react';
6
+ import { Fragment, useState, useRef, memo, useLayoutEffect, useCallback, useEffect } from 'react';
7
7
  import { fg } from '@atlaskit/platform-feature-flags';
8
8
  import { FormattedMessage, injectIntl } from 'react-intl';
9
9
  import EmojiDeletePreview from './EmojiDeletePreview';
10
10
  import EmojiUploadPicker from './EmojiUploadPicker';
11
11
  import TonePreviewButton from './TonePreviewButton';
12
12
  import ToneSelector from './ToneSelector';
13
+ import ProductivityColorSelector, { productivityColorSelectorId } from './ProductivityColorSelector';
14
+ import Popup from './Popup';
13
15
  import { EmojiPickerListSearch } from '../picker/EmojiPickerListSearch';
14
16
  import { messages } from '../i18n';
15
17
  import AkButton from '@atlaskit/button/standard-button';
@@ -26,6 +28,7 @@ const addCustomEmoji = null;
26
28
  const addCustomEmojiButton = null;
27
29
  const emojiActionsWrapper = null;
28
30
  const emojiToneSelectorContainer = null;
31
+ const productivityColorPopup = null;
29
32
  const previewFooter = null;
30
33
  const previewFooterNew = null;
31
34
  export const emojiActionsTestId = 'emoji-actions';
@@ -68,10 +71,16 @@ export const AddOwnEmoji = props => {
68
71
  };
69
72
  const TonesWrapper = props => {
70
73
  const {
74
+ activeCategoryId,
75
+ onProductivityColorSelected,
76
+ productivityColorPreviewEmojis,
77
+ selectedProductivityColor,
71
78
  toneEmoji,
72
79
  selectedTone = DEFAULT_TONE,
73
80
  intl,
81
+ onToneClose,
74
82
  onToneOpen,
83
+ onToneToggle,
75
84
  showToneSelector
76
85
  } = props;
77
86
  const {
@@ -102,6 +111,41 @@ const TonesWrapper = props => {
102
111
  onToneSelected(toneValue);
103
112
  setFocusTonePreviewButton(true);
104
113
  }, [props]);
114
+ const onProductivityColorSelectedHandler = useCallback(color => {
115
+ onProductivityColorSelected === null || onProductivityColorSelected === void 0 ? void 0 : onProductivityColorSelected(color);
116
+ onToneClose();
117
+ setFocusTonePreviewButton(true);
118
+ }, [onProductivityColorSelected, onToneClose]);
119
+ const shouldShowProductivityColorSelector = !!(activeCategoryId === 'ATLASSIAN' && productivityColorPreviewEmojis && selectedProductivityColor && onProductivityColorSelected && FeatureGates.getExperimentValue('platform_teamoji_26_refresh_emoji_picker', 'isEnabled', false));
120
+ if (shouldShowProductivityColorSelector) {
121
+ const previewEmoji = (productivityColorPreviewEmojis === null || productivityColorPreviewEmojis === void 0 ? void 0 : productivityColorPreviewEmojis[selectedProductivityColor]) || Object.values(productivityColorPreviewEmojis || {})[0];
122
+ if (!previewEmoji) {
123
+ return null;
124
+ }
125
+ return /*#__PURE__*/React.createElement("div", {
126
+ className: ax(["_16jlkb7n _1o9zkb7n _i0dlf1ug _ca0q1skh _u5f319bv _n3td1crf _19bvidpf _1e0c1txw _1bahesu3"])
127
+ }, showToneSelector && tonePreviewButtonRef.current && /*#__PURE__*/React.createElement(Popup, {
128
+ target: tonePreviewButtonRef.current,
129
+ relativePosition: "below",
130
+ horizontalAlign: "end-to-start",
131
+ offsetY: 4,
132
+ zIndex: 510
133
+ }, /*#__PURE__*/React.createElement("div", {
134
+ className: ax(["_19itia51 _2rkofajl _bfhk1bhr _16qs130s _ca0q12x7 _u5f312x7 _n3td12x7 _19bv12x7"])
135
+ }, /*#__PURE__*/React.createElement(ProductivityColorSelector, {
136
+ colorPreviewEmojis: productivityColorPreviewEmojis,
137
+ selectedColor: selectedProductivityColor,
138
+ onColorSelected: onProductivityColorSelectedHandler
139
+ }))), /*#__PURE__*/React.createElement(TonePreviewButton, {
140
+ ref: tonePreviewButtonRef,
141
+ ariaControls: productivityColorSelectorId,
142
+ ariaExpanded: showToneSelector,
143
+ emoji: previewEmoji,
144
+ selectOnHover: true,
145
+ onSelected: onToneToggle,
146
+ ariaLabelText: formatMessage(messages.emojiSelectColorButtonAriaLabelText)
147
+ }));
148
+ }
105
149
  if (!toneEmoji) {
106
150
  return null;
107
151
  }
@@ -148,8 +192,13 @@ export const EmojiActions = props => {
148
192
  resultsCount = 0
149
193
  } = props;
150
194
  const [showToneSelector, setShowToneSelector] = useState(false);
195
+ const wasProductivityColorSelectorOpen = useRef(false);
196
+ const shouldUseProductivityColorControl = !!(props.activeCategoryId === 'ATLASSIAN' && props.productivityColorPreviewEmojis && props.selectedProductivityColor && props.onProductivityColorSelected && FeatureGates.getExperimentValue('platform_teamoji_26_refresh_emoji_picker', 'isEnabled', false));
151
197
  const onToneOpenHandler = useCallback(() => setShowToneSelector(true), []);
152
198
  const onToneCloseHandler = useCallback(() => setShowToneSelector(false), []);
199
+ const onToneToggleHandler = useCallback(() => {
200
+ setShowToneSelector(isOpen => !isOpen);
201
+ }, []);
153
202
  const onToneSelectedHandler = useCallback(toneValue => {
154
203
  setShowToneSelector(false);
155
204
  if (onToneSelected) {
@@ -157,11 +206,24 @@ export const EmojiActions = props => {
157
206
  }
158
207
  }, [onToneSelected]);
159
208
  const onMouseLeaveHandler = useCallback(() => {
209
+ if (shouldUseProductivityColorControl) {
210
+ return;
211
+ }
160
212
  if (showToneSelector && onToneSelectorCancelled) {
161
213
  onToneSelectorCancelled();
162
214
  }
163
215
  setShowToneSelector(false);
164
- }, [showToneSelector, onToneSelectorCancelled]);
216
+ }, [shouldUseProductivityColorControl, showToneSelector, onToneSelectorCancelled]);
217
+ useEffect(() => {
218
+ if (shouldUseProductivityColorControl && showToneSelector) {
219
+ wasProductivityColorSelectorOpen.current = true;
220
+ return;
221
+ }
222
+ if (!shouldUseProductivityColorControl && wasProductivityColorSelectorOpen.current) {
223
+ setShowToneSelector(false);
224
+ wasProductivityColorSelectorOpen.current = false;
225
+ }
226
+ }, [shouldUseProductivityColorControl, showToneSelector]);
165
227
  if (uploading) {
166
228
  return FeatureGates.getExperimentValue('platform_teamoji_26_refresh_emoji_picker', 'isEnabled', false) ? /*#__PURE__*/React.createElement("div", {
167
229
  className: ax(["_16jlidpf _1o9zidpf _i0dl1wug"])
@@ -207,11 +269,12 @@ export const EmojiActions = props => {
207
269
  onChange: onChange,
208
270
  query: query,
209
271
  resultsCount: resultsCount,
210
- isVisible: !showToneSelector
272
+ isVisible: !showToneSelector || shouldUseProductivityColorControl
211
273
  }), /*#__PURE__*/React.createElement(TonesWrapper, _extends({}, props, {
212
274
  onToneOpen: onToneOpenHandler,
213
275
  onToneClose: onToneCloseHandler,
214
276
  onToneSelected: onToneSelectedHandler,
277
+ onToneToggle: onToneToggleHandler,
215
278
  showToneSelector: showToneSelector
216
279
  })))) : /*#__PURE__*/React.createElement("div", {
217
280
  "data-testid": emojiActionsTestId,
@@ -229,6 +292,7 @@ export const EmojiActions = props => {
229
292
  onToneOpen: onToneOpenHandler,
230
293
  onToneClose: onToneCloseHandler,
231
294
  onToneSelected: onToneSelectedHandler,
295
+ onToneToggle: onToneToggleHandler,
232
296
  showToneSelector: showToneSelector
233
297
  }))), /*#__PURE__*/React.createElement(AddOwnEmoji, props));
234
298
  };
@@ -10,6 +10,7 @@ const getTargetNode = target => {
10
10
  const Popup = props => {
11
11
  const {
12
12
  relativePosition = 'auto',
13
+ horizontalAlign = 'start',
13
14
  offsetX = 0,
14
15
  offsetY = 0,
15
16
  zIndex = 9,
@@ -18,17 +19,27 @@ const Popup = props => {
18
19
  } = props;
19
20
  const popup = useRef();
20
21
  const [debounced, setDebounced] = useState(null);
22
+ const getLeftPosition = useCallback(box => {
23
+ if (horizontalAlign === 'end-to-start') {
24
+ return box.left - 152;
25
+ }
26
+ if (horizontalAlign === 'end') {
27
+ var _popup$current;
28
+ return box.right - (((_popup$current = popup.current) === null || _popup$current === void 0 ? void 0 : _popup$current.offsetWidth) || 0) + (offsetX || 0);
29
+ }
30
+ return box.left + (offsetX || 0);
31
+ }, [horizontalAlign, offsetX]);
21
32
  const applyBelowPosition = useCallback(() => {
22
33
  const targetNode = getTargetNode(target);
23
34
  if (targetNode && popup.current) {
24
35
  const box = targetNode.getBoundingClientRect();
25
36
  const top = box.bottom + (offsetY || 0);
26
- const left = box.left + (offsetX || 0);
37
+ const left = getLeftPosition(box);
27
38
  popup.current.style.top = `${top}px`;
28
39
  popup.current.style.bottom = '';
29
40
  popup.current.style.left = `${left}px`;
30
41
  }
31
- }, [offsetX, offsetY, target]);
42
+ }, [getLeftPosition, offsetY, target]);
32
43
  const applyAbovePosition = useCallback(() => {
33
44
  if (typeof window === 'undefined') {
34
45
  return;
@@ -37,12 +48,12 @@ const Popup = props => {
37
48
  if (targetNode && popup.current) {
38
49
  const box = targetNode.getBoundingClientRect();
39
50
  const bottom = window.innerHeight - box.top + (offsetY || 0);
40
- const left = box.left + (offsetX || 0);
51
+ const left = getLeftPosition(box);
41
52
  popup.current.style.top = '';
42
53
  popup.current.style.bottom = `${bottom}px`;
43
54
  popup.current.style.left = `${left}px`;
44
55
  }
45
- }, [offsetX, offsetY, target]);
56
+ }, [getLeftPosition, offsetY, target]);
46
57
  const applyAbsolutePosition = useCallback(() => {
47
58
  if (typeof window === 'undefined') {
48
59
  return;
@@ -97,6 +108,9 @@ const Popup = props => {
97
108
  }
98
109
  applyAbsolutePosition();
99
110
  renderPopup();
111
+ if (horizontalAlign !== 'start') {
112
+ applyAbsolutePosition();
113
+ }
100
114
  return () => {
101
115
  if (typeof window === 'undefined') {
102
116
  return;
@@ -107,7 +121,7 @@ const Popup = props => {
107
121
  document.body.removeChild(popup.current);
108
122
  }
109
123
  };
110
- }, [applyAbsolutePosition, handleResize, renderPopup]);
124
+ }, [applyAbsolutePosition, handleResize, horizontalAlign, renderPopup]);
111
125
  return /*#__PURE__*/React.createElement("div", null);
112
126
  };
113
127
  export default Popup;
@@ -0,0 +1,59 @@
1
+
2
+ ._1355fajl input+span{border-radius:var(--ds-radius-small,3px)}
3
+ ._19itidpf{border:0}
4
+ ._zulp1b66{gap:var(--ds-space-050,4px)}._1030zwfg input+span{height:2pc}
5
+ ._12hvze3t input{margin-right:var(--ds-space-0,0)}
6
+ ._12ultlke input{cursor:pointer}
7
+ ._13yj1o36 input:focus+span{outline-width:medium}
8
+ ._17muzwfg label{height:2pc}
9
+ ._18m915vq{overflow-y:hidden}
10
+ ._18u0ze3t{margin-left:var(--ds-space-0,0)}
11
+ ._19bvidpf{padding-left:0}
12
+ ._19pkze3t{margin-top:var(--ds-space-0,0)}
13
+ ._1bah1h6o{justify-content:center}
14
+ ._1bsbt94y{width:1px}
15
+ ._1bsbzwfg{width:2pc}
16
+ ._1e0c11p5{display:grid}
17
+ ._1e0c1txw{display:flex}
18
+ ._1e7sidpf input{opacity:0}
19
+ ._1eq11h6o label{align-items:center}
20
+ ._1nn0kb7n input{z-index:1}
21
+ ._1p1fzwfg label{width:2pc}
22
+ ._1pi91y54 input:focus+span{box-shadow:0 0 0 2px var(--ds-border-focused,#4688ec)}
23
+ ._1reo15vq{overflow-x:hidden}
24
+ ._1rgfze3t input{margin-left:var(--ds-space-0,0)}
25
+ ._1rgq13zc input:focus+span{transition-duration:0s,.2s}
26
+ ._1ul9idpf{min-width:0}
27
+ ._1vzltlke label{cursor:pointer}
28
+ ._1wqq1h6o label{justify-content:center}
29
+ ._2hwxze3t{margin-right:var(--ds-space-0,0)}
30
+ ._2x4gze3t input{margin-top:var(--ds-space-0,0)}
31
+ ._2z051y6t{grid-template-rows:repeat(2,2pc)}
32
+ ._4cvr1h6o{align-items:center}
33
+ ._4t3it94y{height:1px}
34
+ ._4t3izwfg{height:2pc}
35
+ ._5hv9zwfg input{width:2pc}
36
+ ._6rawzwfg input+span{width:2pc}
37
+ ._6vsr1h6o input+span{justify-content:center}
38
+ ._7kzvidpf input+span{padding-inline-end:0}
39
+ ._8qdiidpf input+span{padding-block-start:0}
40
+ ._ca0qidpf{padding-top:0}
41
+ ._ecyuidpf input+span{padding-block-end:0}
42
+ ._ev8ridpf input+span{padding-inline-start:0}
43
+ ._hxs6glyw input:focus+span{outline-style:none}
44
+ ._khufstnw input{position:absolute}
45
+ ._kqswh2mm{position:relative}
46
+ ._kqswstnw{position:absolute}
47
+ ._n3tdidpf{padding-bottom:0}
48
+ ._ngzz1txw input+span{display:flex}
49
+ ._o5721q9c{white-space:nowrap}
50
+ ._ogtohxbz{clip:rect(0 0 0 0)}
51
+ ._otyrze3t{margin-bottom:var(--ds-space-0,0)}
52
+ ._pytkzwfg input{height:2pc}
53
+ ._smb7plhp input:hover+span{background-color:var(--ds-background-neutral-hovered,#0b120e24)}
54
+ ._soq51h6o input+span{align-items:center}
55
+ ._szw2w5lj input:checked+span{box-shadow:0 0 0 2px var(--ds-border-selected,#1868db)}
56
+ ._tnsm1r31 input:focus+span{outline-color:currentColor}
57
+ ._u5f3idpf{padding-right:0}
58
+ ._x5bdze3t input{margin-bottom:var(--ds-space-0,0)}
59
+ ._yv0e1bbt{grid-template-columns:repeat(5,2pc)}
@@ -0,0 +1,98 @@
1
+ /* ProductivityColorSelector.tsx generated by @compiled/babel-plugin v0.39.1 */
2
+ import "./ProductivityColorSelector.compiled.css";
3
+ import * as React from 'react';
4
+ import { ax, ix } from "@compiled/react/runtime";
5
+ import { memo, useContext, useRef } from 'react';
6
+ import { IntlContext } from 'react-intl';
7
+ import { Radio } from '@atlaskit/radio';
8
+ import { productivityColors } from '../../util/productivity-colors';
9
+ import { messages } from '../i18n';
10
+ import Emoji from './Emoji';
11
+ export const productivityColorSelectorTestId = 'productivity-color-selector';
12
+ export const productivityColorSelectorId = 'emoji-picker-productivity-color-selector';
13
+ const selectorGrid = null;
14
+ const visuallyHiddenLegend = null;
15
+ const colorOption = null;
16
+ const colorOptionEmoji = null;
17
+ const getColorLabel = color => `${color.charAt(0).toUpperCase()}${color.slice(1)} productivity emoji colour`;
18
+ export const ProductivityColorSelector = ({
19
+ colorPreviewEmojis,
20
+ onColorSelected,
21
+ selectedColor
22
+ }) => {
23
+ const intl = useContext(IntlContext);
24
+ const radioRefs = useRef([]);
25
+ const hasFocusedSelectedColor = useRef(false);
26
+ const availableColors = productivityColors.filter(color => colorPreviewEmojis[color]);
27
+ const colorSelectorAriaLabel = intl ? intl.formatMessage(messages.emojiSelectColorListAriaLabelText) : messages.emojiSelectColorListAriaLabelText.defaultMessage;
28
+ if (!availableColors.length) {
29
+ return null;
30
+ }
31
+ const onArrowKey = (currentIndex, direction) => {
32
+ var _radioRefs$current$ne;
33
+ const nextIndex = (currentIndex + direction + availableColors.length) % availableColors.length;
34
+ (_radioRefs$current$ne = radioRefs.current[nextIndex]) === null || _radioRefs$current$ne === void 0 ? void 0 : _radioRefs$current$ne.focus();
35
+ };
36
+ const stopPickerDismissal = event => {
37
+ event.stopPropagation();
38
+ };
39
+ return /*#__PURE__*/React.createElement("fieldset", {
40
+ id: productivityColorSelectorId,
41
+ "data-testid": productivityColorSelectorTestId,
42
+ className: ax(["_19itidpf _zulp1b66 _ca0qidpf _u5f3idpf _n3tdidpf _19bvidpf _1e0c11p5 _yv0e1bbt _2z051y6t _19pkze3t _2hwxze3t _otyrze3t _18u0ze3t _1ul9idpf"])
43
+ }, /*#__PURE__*/React.createElement("legend", {
44
+ className: ax(["_19itidpf _1reo15vq _18m915vq _ca0qidpf _u5f3idpf _n3tdidpf _19bvidpf _ogtohxbz _4t3it94y _kqswstnw _o5721q9c _1bsbt94y"])
45
+ }, colorSelectorAriaLabel), availableColors.map((color, index) => {
46
+ const emoji = colorPreviewEmojis[color];
47
+ if (!emoji) {
48
+ return null;
49
+ }
50
+ const handleKeyDown = event => {
51
+ if (event.key === 'ArrowLeft' || event.key === 'ArrowUp') {
52
+ event.preventDefault();
53
+ onArrowKey(index, -1);
54
+ }
55
+ if (event.key === 'ArrowRight' || event.key === 'ArrowDown') {
56
+ event.preventDefault();
57
+ onArrowKey(index, 1);
58
+ }
59
+ if (event.key === 'Enter') {
60
+ event.preventDefault();
61
+ onColorSelected(color);
62
+ }
63
+ };
64
+ return /*#__PURE__*/React.createElement("div", {
65
+ key: color,
66
+ className: ax(["_4t3izwfg _kqswh2mm _1bsbzwfg _1355fajl _soq51h6o _ngzz1txw _1030zwfg _6vsr1h6o _ecyuidpf _8qdiidpf _7kzvidpf _ev8ridpf _6rawzwfg _tnsm1r31 _hxs6glyw _13yj1o36 _1pi91y54 _1rgq13zc _1eq11h6o _1vzltlke _17muzwfg _1wqq1h6o _1p1fzwfg _12ultlke _pytkzwfg _2x4gze3t _12hvze3t _x5bdze3t _1rgfze3t _1e7sidpf _khufstnw _5hv9zwfg _1nn0kb7n _smb7plhp _szw2w5lj"])
67
+ }, /*#__PURE__*/React.createElement(Radio, {
68
+ ref: el => {
69
+ radioRefs.current[index] = el;
70
+ if (selectedColor === color) {
71
+ if (el && !hasFocusedSelectedColor.current) {
72
+ el.focus();
73
+ hasFocusedSelectedColor.current = true;
74
+ }
75
+ }
76
+ },
77
+ ariaLabel: getColorLabel(color),
78
+ name: "productivity-emoji-colour",
79
+ isChecked: selectedColor === color,
80
+ onChange: () => onColorSelected(color),
81
+ onClick: stopPickerDismissal,
82
+ onKeyDown: handleKeyDown,
83
+ onMouseDown: stopPickerDismissal,
84
+ testId: `productivity-color-${color}`,
85
+ value: color,
86
+ label: /*#__PURE__*/React.createElement("span", {
87
+ className: ax(["_4cvr1h6o _1e0c1txw _4t3izwfg _1bah1h6o _1bsbzwfg"])
88
+ }, /*#__PURE__*/React.createElement(Emoji, {
89
+ emoji: emoji,
90
+ shouldBeInteractive: false,
91
+ "aria-hidden": true,
92
+ fitToHeight: 24
93
+ }))
94
+ }));
95
+ }));
96
+ };
97
+ const _default_1 = /*#__PURE__*/memo(ProductivityColorSelector);
98
+ export default _default_1;
@@ -14,6 +14,7 @@ export const TonePreviewButton = /*#__PURE__*/forwardRef((props, ref) => {
14
14
  const {
15
15
  emoji,
16
16
  selectOnHover,
17
+ ariaControls = 'emoji-picker-tone-selector',
17
18
  ariaLabelText,
18
19
  ariaExpanded,
19
20
  onSelected,
@@ -25,7 +26,7 @@ export const TonePreviewButton = /*#__PURE__*/forwardRef((props, ref) => {
25
26
  onClick: onSelected,
26
27
  "aria-label": ariaLabelText,
27
28
  "aria-expanded": ariaExpanded,
28
- "aria-controls": "emoji-picker-tone-selector"
29
+ "aria-controls": ariaControls
29
30
  // eslint-disable-next-line @atlaskit/ui-styling-standard/enforce-style-prop -- Ignored via go/DSP-18766
30
31
  ,
31
32
  style: {
@@ -45,7 +46,7 @@ export const TonePreviewButton = /*#__PURE__*/forwardRef((props, ref) => {
45
46
  onClick: onSelected,
46
47
  "aria-label": ariaLabelText,
47
48
  "aria-expanded": ariaExpanded,
48
- "aria-controls": "emoji-picker-tone-selector"
49
+ "aria-controls": ariaControls
49
50
  // eslint-disable-next-line @atlaskit/ui-styling-standard/enforce-style-prop -- Ignored via go/DSP-18766
50
51
  ,
51
52
  style: {
@@ -65,6 +65,16 @@ export const messages = defineMessages({
65
65
  defaultMessage: 'Choose your skin tone, {selectedTone} selected',
66
66
  description: 'Message indicating the purpose of the skin tone selection button and the selected tone'
67
67
  },
68
+ emojiSelectColorButtonAriaLabelText: {
69
+ id: 'fabric.emoji.select.color.ariaLabel',
70
+ defaultMessage: 'Productivity emoji color selector',
71
+ description: 'Message indicating the purpose of the color selection button and the selected color'
72
+ },
73
+ emojiSelectColorListAriaLabelText: {
74
+ id: 'fabric.emoji.select.color.list.ariaLabel',
75
+ defaultMessage: 'Productivity emoji colour selector',
76
+ description: 'Message indicating the purpose of the productivity emoji color list selector'
77
+ },
68
78
  emojiSelectSkinToneListAriaLabelText: {
69
79
  id: 'fabric.emoji.select.skin.list.ariaLabel',
70
80
  defaultMessage: 'Skin tone selector',
@@ -26,6 +26,8 @@ import { createAndFireEventInElementsChannel, categoryClickedEvent, closedPicker
26
26
  import { useEmoji } from '../../hooks/useEmoji';
27
27
  import { useIsMounted } from '../../hooks/useIsMounted';
28
28
  import { messages } from '../i18n';
29
+ import { defaultProductivityColor } from '../../util/productivity-colors';
30
+ import { filterHiddenEmojis } from '../../util/hidden-emojis';
29
31
  const emojiPickerBoxShadow = "var(--ds-shadow-overlay, 0px 8px 12px #1E1F2126, 0px 0px 1px #1E1F214f)";
30
32
  const emojiPickerHeight = 295;
31
33
  const emojiPickerHeightWithPreview = 349; // emojiPickerHeight + emojiPickerPreviewHeight;
@@ -78,12 +80,14 @@ const EmojiPickerComponent = ({
78
80
  emojiProvider,
79
81
  isUploadSupported
80
82
  } = useEmoji();
83
+ const isTeamojiExperimentEnabled = FeatureGates.getExperimentValue('platform_teamoji_26_refresh_emoji_picker', 'isEnabled', false);
81
84
  const [filteredEmojis, setFilteredEmojis] = useState([]);
82
85
  const [searchEmojis, setSearchEmojis] = useState([]);
83
86
  const [frequentlyUsedEmojis, setFrequentlyUsedEmojis] = useState([]);
84
87
  const [query, setQuery] = useState('');
85
88
  const [dynamicCategories, setDynamicCategories] = useState([]);
86
89
  const [selectedTone, setSelectedTone] = useState(!hideToneSelector ? emojiProvider.getSelectedTone() : undefined);
90
+ const [selectedProductivityColor, setSelectedProductivityColor] = useState(defaultProductivityColor);
87
91
  const [loading, setLoading] = useState(true);
88
92
  const [uploading, setUploading] = useState(false);
89
93
  const [selectedEmoji, setSelectedEmoji] = useState();
@@ -100,11 +104,11 @@ const EmojiPickerComponent = ({
100
104
  const isProgrammaticScroll = useRef(false);
101
105
  const pickerRef = useRef(null);
102
106
  const setPickerRef = useCallback(el => {
103
- if (FeatureGates.getExperimentValue('platform_teamoji_26_refresh_emoji_picker', 'isEnabled', false)) {
107
+ if (isTeamojiExperimentEnabled) {
104
108
  pickerRef.current = el;
105
109
  }
106
110
  onPickerRef === null || onPickerRef === void 0 ? void 0 : onPickerRef(el);
107
- }, [onPickerRef]);
111
+ }, [isTeamojiExperimentEnabled, onPickerRef]);
108
112
  const currentUser = useMemo(() => {
109
113
  return emojiProvider.getCurrentUser();
110
114
  }, [emojiProvider]);
@@ -206,7 +210,8 @@ const EmojiPickerComponent = ({
206
210
  }, [filteredEmojis.length, getDynamicCategories, onDynamicCategoryChange, selectedEmoji]);
207
211
  const onFrequentEmojiResult = useCallback(frequentEmoji => {
208
212
  // change the category of each of the featured emoji
209
- const recategorised = frequentEmoji.map(emoji => {
213
+ const visibleFrequentEmoji = isTeamojiExperimentEnabled ? filterHiddenEmojis(frequentEmoji) : frequentEmoji;
214
+ const recategorised = visibleFrequentEmoji.map(emoji => {
210
215
  const clone = JSON.parse(JSON.stringify(emoji));
211
216
  clone.category = frequentCategory;
212
217
  return clone;
@@ -214,10 +219,11 @@ const EmojiPickerComponent = ({
214
219
  setStateAfterEmojiChange({
215
220
  frequentEmoji: recategorised
216
221
  });
217
- }, [setStateAfterEmojiChange]);
222
+ }, [isTeamojiExperimentEnabled, setStateAfterEmojiChange]);
218
223
  const onSearchResult = useCallback(searchResults => {
219
224
  const frequentlyUsedEmoji = frequentlyUsedEmojis || [];
220
225
  const searchQuery = searchResults.query || '';
226
+ const visibleSearchEmojis = isTeamojiExperimentEnabled ? filterHiddenEmojis(searchResults.emojis) : searchResults.emojis;
221
227
 
222
228
  /**
223
229
  * If there is no user search in the EmojiPicker then it should display all emoji received from the EmojiRepository and should
@@ -226,20 +232,20 @@ const EmojiPickerComponent = ({
226
232
  */
227
233
  let emojiToRender;
228
234
  if (!frequentlyUsedEmoji.length || query) {
229
- emojiToRender = searchResults.emojis;
235
+ emojiToRender = visibleSearchEmojis;
230
236
  } else {
231
- emojiToRender = [...searchResults.emojis, ...frequentlyUsedEmoji];
237
+ emojiToRender = [...visibleSearchEmojis, ...frequentlyUsedEmoji];
232
238
  }
233
239
  setStateAfterEmojiChange({
234
240
  searchQuery,
235
241
  emojiToRender,
236
- searchEmoji: searchResults.emojis
242
+ searchEmoji: visibleSearchEmojis
237
243
  });
238
244
  fireAnalytics(pickerSearchedEvent({
239
245
  queryLength: searchQuery.length,
240
- numMatches: searchResults.emojis.length
246
+ numMatches: visibleSearchEmojis.length
241
247
  }));
242
- }, [frequentlyUsedEmojis, query, setStateAfterEmojiChange, fireAnalytics]);
248
+ }, [frequentlyUsedEmojis, isTeamojiExperimentEnabled, query, setStateAfterEmojiChange, fireAnalytics]);
243
249
  const onProviderChange = useMemo(() => {
244
250
  return {
245
251
  result: onSearchResult
@@ -282,6 +288,9 @@ const EmojiPickerComponent = ({
282
288
  const onToneSelectorCancelled = useCallback(() => {
283
289
  fireAnalytics(toneSelectorClosedEvent());
284
290
  }, [fireAnalytics]);
291
+ const onProductivityColorSelected = useCallback(color => {
292
+ setSelectedProductivityColor(color);
293
+ }, []);
285
294
  const onSelectWrapper = useCallback((emojiId, emoji, event) => {
286
295
  if (onSelection) {
287
296
  onSelection(emojiId, emoji, event);
@@ -312,17 +321,18 @@ const EmojiPickerComponent = ({
312
321
  emojiProvider.findInCategory(categoryId).then(emojisInCategory => {
313
322
  if (!disableCategories) {
314
323
  let newSelectedEmoji;
315
- if (emojisInCategory && emojisInCategory.length > 0) {
316
- newSelectedEmoji = getEmojiVariation(emojisInCategory[0], {
324
+ const visibleEmojisInCategory = isTeamojiExperimentEnabled ? filterHiddenEmojis(emojisInCategory || []) : emojisInCategory || [];
325
+ if (visibleEmojisInCategory.length > 0) {
326
+ newSelectedEmoji = getEmojiVariation(visibleEmojisInCategory[0], {
317
327
  skinTone: selectedTone
318
328
  });
319
329
  }
320
330
  if (emojiPickerList.current) {
321
- if (FeatureGates.getExperimentValue('platform_teamoji_26_refresh_emoji_picker', 'isEnabled', false)) {
331
+ if (isTeamojiExperimentEnabled) {
322
332
  isProgrammaticScroll.current = true;
323
333
  }
324
334
  emojiPickerList.current.reveal(categoryId);
325
- if (FeatureGates.getExperimentValue('platform_teamoji_26_refresh_emoji_picker', 'isEnabled', false)) {
335
+ if (isTeamojiExperimentEnabled) {
326
336
  // Clear the flag after the scroll animation has settled.
327
337
  setTimeout(() => {
328
338
  isProgrammaticScroll.current = false;
@@ -338,7 +348,7 @@ const EmojiPickerComponent = ({
338
348
  }));
339
349
  }
340
350
  });
341
- }, [disableCategories, emojiPickerList, emojiProvider, fireAnalytics, selectedTone, uploading, emojiToDelete]);
351
+ }, [disableCategories, emojiPickerList, emojiProvider, fireAnalytics, isTeamojiExperimentEnabled, selectedTone, uploading, emojiToDelete]);
342
352
  const recordUsageOnSelection = useMemo(() => createRecordSelectionDefault(emojiProvider, onSelectWrapper, analytic => fireAnalytics(analytic(SearchSourceTypes.PICKER))), [emojiProvider, fireAnalytics, onSelectWrapper]);
343
353
  const formattedErrorMessage = useMemo(() => uploadErrorMessage ? /*#__PURE__*/React.createElement(FormattedMessage, uploadErrorMessage) : null, [uploadErrorMessage]);
344
354
  const onFileChooserClicked = useCallback(() => {
@@ -580,11 +590,13 @@ const EmojiPickerComponent = ({
580
590
  onSearch: onSearch,
581
591
  query: query,
582
592
  selectedTone: selectedTone,
593
+ selectedProductivityColor: isTeamojiExperimentEnabled ? selectedProductivityColor : undefined,
583
594
  loading: loading,
584
595
  ref: emojiPickerList,
585
596
  initialUploadName: query,
586
597
  onToneSelected: onToneSelected,
587
598
  onToneSelectorCancelled: onToneSelectorCancelled,
599
+ onProductivityColorSelected: isTeamojiExperimentEnabled ? onProductivityColorSelected : undefined,
588
600
  toneEmoji: toneEmoji,
589
601
  uploading: uploading,
590
602
  emojiToDelete: emojiToDelete,