@atlaskit/reactions 37.0.1 → 37.1.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.
- package/CHANGELOG.md +22 -0
- package/dist/cjs/analytics/index.js +1 -1
- package/dist/cjs/components/Reactions.js +115 -2
- package/dist/es2019/analytics/index.js +1 -1
- package/dist/es2019/components/Reactions.js +87 -2
- package/dist/esm/analytics/index.js +1 -1
- package/dist/esm/components/Reactions.js +115 -2
- package/package.json +7 -7
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,27 @@
|
|
|
1
1
|
# @atlaskit/reactions
|
|
2
2
|
|
|
3
|
+
## 37.1.1
|
|
4
|
+
|
|
5
|
+
### Patch Changes
|
|
6
|
+
|
|
7
|
+
- Updated dependencies
|
|
8
|
+
|
|
9
|
+
## 37.1.0
|
|
10
|
+
|
|
11
|
+
### Minor Changes
|
|
12
|
+
|
|
13
|
+
- [`5157e2c52cfcd`](https://bitbucket.org/atlassian/atlassian-frontend-monorepo/commits/5157e2c52cfcd) -
|
|
14
|
+
Update i18n NPM package versions for editor,editor-extensions,activity-platform,media,elements
|
|
15
|
+
(Group 3)
|
|
16
|
+
|
|
17
|
+
### Patch Changes
|
|
18
|
+
|
|
19
|
+
- [`87589cc4647ba`](https://bitbucket.org/atlassian/atlassian-frontend-monorepo/commits/87589cc4647ba) -
|
|
20
|
+
Keep keyboard focus when the focused reaction is removed or re-rendered, including with quick
|
|
21
|
+
reactions and in the summary view, instead of losing it to the document body. Behind feature gate
|
|
22
|
+
platform_a11y_reactions_removal_focus.
|
|
23
|
+
- Updated dependencies
|
|
24
|
+
|
|
3
25
|
## 37.0.1
|
|
4
26
|
|
|
5
27
|
### Patch Changes
|
|
@@ -11,7 +11,7 @@ var _createAndFireEvents = _interopRequireDefault(require("@atlaskit/analytics-n
|
|
|
11
11
|
function ownKeys(e, r) { var t = Object.keys(e); if (Object.getOwnPropertySymbols) { var o = Object.getOwnPropertySymbols(e); r && (o = o.filter(function (r) { return Object.getOwnPropertyDescriptor(e, r).enumerable; })), t.push.apply(t, o); } return t; }
|
|
12
12
|
function _objectSpread(e) { for (var r = 1; r < arguments.length; r++) { var t = null != arguments[r] ? arguments[r] : {}; r % 2 ? ownKeys(Object(t), !0).forEach(function (r) { (0, _defineProperty2.default)(e, r, t[r]); }) : Object.getOwnPropertyDescriptors ? Object.defineProperties(e, Object.getOwnPropertyDescriptors(t)) : ownKeys(Object(t)).forEach(function (r) { Object.defineProperty(e, r, Object.getOwnPropertyDescriptor(t, r)); }); } return e; } // eslint-disable-next-line @typescript-eslint/consistent-type-imports
|
|
13
13
|
var packageName = "@atlaskit/reactions";
|
|
14
|
-
var packageVersion = "37.
|
|
14
|
+
var packageVersion = "37.1.0";
|
|
15
15
|
/**
|
|
16
16
|
* TODO: move to utility package?
|
|
17
17
|
* A random sampling function
|
|
@@ -28,7 +28,11 @@ var _Reaction = require("./Reaction");
|
|
|
28
28
|
var _ReactionPicker = require("./ReactionPicker");
|
|
29
29
|
var _ReactionsDialog = require("./ReactionsDialog");
|
|
30
30
|
var _ReactionSummaryView = require("./ReactionSummaryView");
|
|
31
|
+
var _Trigger = require("./Trigger");
|
|
31
32
|
function _interopRequireWildcard(e, t) { if ("function" == typeof WeakMap) var r = new WeakMap(), n = new WeakMap(); return (_interopRequireWildcard = function _interopRequireWildcard(e, t) { if (!t && e && e.__esModule) return e; var o, i, f = { __proto__: null, default: e }; if (null === e || "object" != _typeof(e) && "function" != typeof e) return f; if (o = t ? n : r) { if (o.has(e)) return o.get(e); o.set(e, f); } for (var _t in e) "default" !== _t && {}.hasOwnProperty.call(e, _t) && ((i = (o = Object.defineProperty) && Object.getOwnPropertyDescriptor(e, _t)) && (i.get || i.set) ? o(f, _t, i) : f[_t] = e[_t]); return f; })(e, t); }
|
|
33
|
+
function _createForOfIteratorHelper(r, e) { var t = "undefined" != typeof Symbol && r[Symbol.iterator] || r["@@iterator"]; if (!t) { if (Array.isArray(r) || (t = _unsupportedIterableToArray(r)) || e && r && "number" == typeof r.length) { t && (r = t); var _n = 0, F = function F() {}; return { s: F, n: function n() { return _n >= r.length ? { done: !0 } : { done: !1, value: r[_n++] }; }, e: function e(r) { throw r; }, f: F }; } throw new TypeError("Invalid attempt to iterate non-iterable instance.\nIn order to be iterable, non-array objects must have a [Symbol.iterator]() method."); } var o, a = !0, u = !1; return { s: function s() { t = t.call(r); }, n: function n() { var r = t.next(); return a = r.done, r; }, e: function e(r) { u = !0, o = r; }, f: function f() { try { a || null == t.return || t.return(); } finally { if (u) throw o; } } }; }
|
|
34
|
+
function _unsupportedIterableToArray(r, a) { if (r) { if ("string" == typeof r) return _arrayLikeToArray(r, a); var t = {}.toString.call(r).slice(8, -1); return "Object" === t && r.constructor && (t = r.constructor.name), "Map" === t || "Set" === t ? Array.from(r) : "Arguments" === t || /^(?:Ui|I)nt(?:8|16|32)(?:Clamped)?Array$/.test(t) ? _arrayLikeToArray(r, a) : void 0; } }
|
|
35
|
+
function _arrayLikeToArray(r, a) { (null == a || a > r.length) && (a = r.length); for (var e = 0, n = Array(a); e < a; e++) n[e] = r[e]; return n; }
|
|
32
36
|
var wrapperStyle = null;
|
|
33
37
|
var noFlexWrapStyles = null;
|
|
34
38
|
var noContainerPositionStyles = null;
|
|
@@ -313,6 +317,114 @@ var Reactions = exports.Reactions = /*#__PURE__*/_react.default.memo(function (_
|
|
|
313
317
|
return (b === null || b === void 0 ? void 0 : b.count) - (a === null || a === void 0 ? void 0 : a.count);
|
|
314
318
|
});
|
|
315
319
|
}, [memorizedReactions]);
|
|
320
|
+
var wrapperRef = (0, _react.useRef)(null);
|
|
321
|
+
/**
|
|
322
|
+
* The reaction button the user activated while it had focus, with the order of the reactions shown alongside it
|
|
323
|
+
*/
|
|
324
|
+
var activatedReactionRef = (0, _react.useRef)(null);
|
|
325
|
+
var trackActivatedReaction = (0, _react.useCallback)(function (emojiId, event, shownReactions) {
|
|
326
|
+
var button = event.currentTarget;
|
|
327
|
+
// Only keyboard and screen reader users, or mouse clicks that focus the button, can lose focus with it
|
|
328
|
+
if (button.ownerDocument.activeElement !== button) {
|
|
329
|
+
activatedReactionRef.current = null;
|
|
330
|
+
return;
|
|
331
|
+
}
|
|
332
|
+
activatedReactionRef.current = {
|
|
333
|
+
button: button,
|
|
334
|
+
emojiId: emojiId,
|
|
335
|
+
// Read now, as a removed button no longer has ancestors
|
|
336
|
+
list: button.closest('ul'),
|
|
337
|
+
shownEmojiIds: shownReactions.map(function (reaction) {
|
|
338
|
+
return reaction.emojiId;
|
|
339
|
+
})
|
|
340
|
+
};
|
|
341
|
+
// Focus moved away by the user while the button is still shown was not lost with it.
|
|
342
|
+
// Chrome fires focusout before detaching a removed button, so check once the removal has finished.
|
|
343
|
+
button.addEventListener('focusout', function () {
|
|
344
|
+
return queueMicrotask(function () {
|
|
345
|
+
var _activatedReactionRef;
|
|
346
|
+
if (button.isConnected && ((_activatedReactionRef = activatedReactionRef.current) === null || _activatedReactionRef === void 0 ? void 0 : _activatedReactionRef.button) === button) {
|
|
347
|
+
activatedReactionRef.current = null;
|
|
348
|
+
}
|
|
349
|
+
});
|
|
350
|
+
}, {
|
|
351
|
+
once: true
|
|
352
|
+
});
|
|
353
|
+
}, []);
|
|
354
|
+
var handleTrackedReactionClick = (0, _react.useCallback)(function (emojiId, event) {
|
|
355
|
+
trackActivatedReaction(emojiId, event, memorizedReactions);
|
|
356
|
+
onReactionClick(emojiId, event);
|
|
357
|
+
}, [memorizedReactions, onReactionClick, trackActivatedReaction]);
|
|
358
|
+
var handleTrackedSummaryViewReactionClick = (0, _react.useCallback)(function (emojiId, event) {
|
|
359
|
+
trackActivatedReaction(emojiId, event, sortedReactions);
|
|
360
|
+
handleSummaryViewReactionClick(emojiId, event);
|
|
361
|
+
}, [handleSummaryViewReactionClick, sortedReactions, trackActivatedReaction]);
|
|
362
|
+
|
|
363
|
+
/**
|
|
364
|
+
* Restore focus when the activated reaction button leaves the DOM, either because the reaction was removed or
|
|
365
|
+
* because the reactions re-rendered in a different layout, rather than losing it to the document body
|
|
366
|
+
*/
|
|
367
|
+
(0, _react.useEffect)(function () {
|
|
368
|
+
if (!(0, _fg.fg)('platform_a11y_reactions_removal_focus')) {
|
|
369
|
+
return;
|
|
370
|
+
}
|
|
371
|
+
var activatedReaction = activatedReactionRef.current;
|
|
372
|
+
// Only the first update after an activation can be its result
|
|
373
|
+
activatedReactionRef.current = null;
|
|
374
|
+
var wrapper = wrapperRef.current;
|
|
375
|
+
if (!activatedReaction || activatedReaction.button.isConnected || !wrapper) {
|
|
376
|
+
return;
|
|
377
|
+
}
|
|
378
|
+
var activeElement = wrapper.ownerDocument.activeElement;
|
|
379
|
+
// Never take focus from where the user has since moved it
|
|
380
|
+
if (activeElement && activeElement !== wrapper.ownerDocument.body) {
|
|
381
|
+
return;
|
|
382
|
+
}
|
|
383
|
+
|
|
384
|
+
// The summary view tray can be portalled outside the wrapper, so search the activated button's list first
|
|
385
|
+
var list = activatedReaction.list;
|
|
386
|
+
var findReactionButton = function findReactionButton(emojiId) {
|
|
387
|
+
return [list !== null && list !== void 0 && list.isConnected ? list : null, wrapper].flatMap(function (root) {
|
|
388
|
+
return root ? Array.from(root.querySelectorAll('button[data-emoji-id]')) : [];
|
|
389
|
+
}).find(function (button) {
|
|
390
|
+
return button.dataset.emojiId === emojiId;
|
|
391
|
+
});
|
|
392
|
+
};
|
|
393
|
+
var emojiId = activatedReaction.emojiId,
|
|
394
|
+
shownEmojiIds = activatedReaction.shownEmojiIds;
|
|
395
|
+
var index = shownEmojiIds.indexOf(emojiId);
|
|
396
|
+
var focusCandidates = [
|
|
397
|
+
// The same reaction re-rendered, e.g. a quick reaction going back to a zero count
|
|
398
|
+
function () {
|
|
399
|
+
return findReactionButton(emojiId);
|
|
400
|
+
}].concat((0, _toConsumableArray2.default)(shownEmojiIds.slice(index + 1).map(function (id) {
|
|
401
|
+
return function () {
|
|
402
|
+
return findReactionButton(id);
|
|
403
|
+
};
|
|
404
|
+
})), [function () {
|
|
405
|
+
return wrapper.querySelector("[data-testid=\"".concat(_Trigger.RENDER_TRIGGER_BUTTON_TESTID, "\"]"));
|
|
406
|
+
}], (0, _toConsumableArray2.default)(shownEmojiIds.slice(0, index).reverse().map(function (id) {
|
|
407
|
+
return function () {
|
|
408
|
+
return findReactionButton(id);
|
|
409
|
+
};
|
|
410
|
+
})));
|
|
411
|
+
var _iterator = _createForOfIteratorHelper(focusCandidates),
|
|
412
|
+
_step;
|
|
413
|
+
try {
|
|
414
|
+
for (_iterator.s(); !(_step = _iterator.n()).done;) {
|
|
415
|
+
var findCandidate = _step.value;
|
|
416
|
+
var candidate = findCandidate();
|
|
417
|
+
if (candidate !== null && candidate !== void 0 && candidate.isConnected) {
|
|
418
|
+
candidate.focus();
|
|
419
|
+
return;
|
|
420
|
+
}
|
|
421
|
+
}
|
|
422
|
+
} catch (err) {
|
|
423
|
+
_iterator.e(err);
|
|
424
|
+
} finally {
|
|
425
|
+
_iterator.f();
|
|
426
|
+
}
|
|
427
|
+
}, [memorizedReactions]);
|
|
316
428
|
|
|
317
429
|
/**
|
|
318
430
|
* event handler to open dialog with selected reaction
|
|
@@ -346,7 +458,7 @@ var Reactions = exports.Reactions = /*#__PURE__*/_react.default.memo(function (_
|
|
|
346
458
|
rootElement: rootElement,
|
|
347
459
|
reaction: reaction,
|
|
348
460
|
emojiProvider: emojiProvider,
|
|
349
|
-
onClick: onReactionClick,
|
|
461
|
+
onClick: (0, _fg.fg)('platform_a11y_reactions_removal_focus') ? handleTrackedReactionClick : onReactionClick,
|
|
350
462
|
onMouseEnter: handleReactionMouseEnter,
|
|
351
463
|
onFocused: handleReactionFocused,
|
|
352
464
|
flash: flash[reaction.emojiId],
|
|
@@ -376,6 +488,7 @@ var Reactions = exports.Reactions = /*#__PURE__*/_react.default.memo(function (_
|
|
|
376
488
|
return /*#__PURE__*/_react.default.createElement(_ufoSegment.default, {
|
|
377
489
|
name: "reactions"
|
|
378
490
|
}, /*#__PURE__*/_react.default.createElement("div", {
|
|
491
|
+
ref: wrapperRef,
|
|
379
492
|
"data-testid": RENDER_REACTIONS_TESTID,
|
|
380
493
|
className: (0, _runtime.ax)(["_1e0c1txw _1n261g80 _kqswh2mm _4cvr1h6o _1pfhr5cr _1fohidpf", noWrap && "_1n261q9c", noRelativeContainer && "_kqswpfqs"])
|
|
381
494
|
}, !onlyRenderPicker && (shouldShowSummaryView ? /*#__PURE__*/_react.default.createElement("div", {
|
|
@@ -386,7 +499,7 @@ var Reactions = exports.Reactions = /*#__PURE__*/_react.default.memo(function (_
|
|
|
386
499
|
flash: flash,
|
|
387
500
|
particleEffectByEmoji: particleEffectByEmoji,
|
|
388
501
|
onSelection: handleOnSelection,
|
|
389
|
-
onReactionClick: handleSummaryViewReactionClick,
|
|
502
|
+
onReactionClick: (0, _fg.fg)('platform_a11y_reactions_removal_focus') ? handleTrackedSummaryViewReactionClick : handleSummaryViewReactionClick,
|
|
390
503
|
onReactionFocused: handleReactionFocused,
|
|
391
504
|
onReactionMouseEnter: handleReactionMouseEnter,
|
|
392
505
|
placement: summaryViewPlacement,
|
|
@@ -2,7 +2,7 @@ import { UI_EVENT_TYPE, OPERATIONAL_EVENT_TYPE } from '@atlaskit/analytics-gas-t
|
|
|
2
2
|
// eslint-disable-next-line @typescript-eslint/consistent-type-imports
|
|
3
3
|
import createAndFireEvent from '@atlaskit/analytics-next/createAndFireEvents';
|
|
4
4
|
const packageName = "@atlaskit/reactions";
|
|
5
|
-
const packageVersion = "37.
|
|
5
|
+
const packageVersion = "37.1.0";
|
|
6
6
|
/**
|
|
7
7
|
* TODO: move to utility package?
|
|
8
8
|
* A random sampling function
|
|
@@ -16,6 +16,7 @@ import { Reaction } from './Reaction';
|
|
|
16
16
|
import { ReactionPicker } from './ReactionPicker';
|
|
17
17
|
import { ReactionsDialog } from './ReactionsDialog';
|
|
18
18
|
import { ReactionSummaryView } from './ReactionSummaryView';
|
|
19
|
+
import { RENDER_TRIGGER_BUTTON_TESTID } from './Trigger';
|
|
19
20
|
const wrapperStyle = null;
|
|
20
21
|
const noFlexWrapStyles = null;
|
|
21
22
|
const noContainerPositionStyles = null;
|
|
@@ -261,6 +262,89 @@ export const Reactions = /*#__PURE__*/React.memo(({
|
|
|
261
262
|
const sortedReactions = useMemo(() => {
|
|
262
263
|
return [...memorizedReactions].sort((a, b) => (b === null || b === void 0 ? void 0 : b.count) - (a === null || a === void 0 ? void 0 : a.count));
|
|
263
264
|
}, [memorizedReactions]);
|
|
265
|
+
const wrapperRef = useRef(null);
|
|
266
|
+
/**
|
|
267
|
+
* The reaction button the user activated while it had focus, with the order of the reactions shown alongside it
|
|
268
|
+
*/
|
|
269
|
+
const activatedReactionRef = useRef(null);
|
|
270
|
+
const trackActivatedReaction = useCallback((emojiId, event, shownReactions) => {
|
|
271
|
+
const button = event.currentTarget;
|
|
272
|
+
// Only keyboard and screen reader users, or mouse clicks that focus the button, can lose focus with it
|
|
273
|
+
if (button.ownerDocument.activeElement !== button) {
|
|
274
|
+
activatedReactionRef.current = null;
|
|
275
|
+
return;
|
|
276
|
+
}
|
|
277
|
+
activatedReactionRef.current = {
|
|
278
|
+
button,
|
|
279
|
+
emojiId,
|
|
280
|
+
// Read now, as a removed button no longer has ancestors
|
|
281
|
+
list: button.closest('ul'),
|
|
282
|
+
shownEmojiIds: shownReactions.map(reaction => reaction.emojiId)
|
|
283
|
+
};
|
|
284
|
+
// Focus moved away by the user while the button is still shown was not lost with it.
|
|
285
|
+
// Chrome fires focusout before detaching a removed button, so check once the removal has finished.
|
|
286
|
+
button.addEventListener('focusout', () => queueMicrotask(() => {
|
|
287
|
+
var _activatedReactionRef;
|
|
288
|
+
if (button.isConnected && ((_activatedReactionRef = activatedReactionRef.current) === null || _activatedReactionRef === void 0 ? void 0 : _activatedReactionRef.button) === button) {
|
|
289
|
+
activatedReactionRef.current = null;
|
|
290
|
+
}
|
|
291
|
+
}), {
|
|
292
|
+
once: true
|
|
293
|
+
});
|
|
294
|
+
}, []);
|
|
295
|
+
const handleTrackedReactionClick = useCallback((emojiId, event) => {
|
|
296
|
+
trackActivatedReaction(emojiId, event, memorizedReactions);
|
|
297
|
+
onReactionClick(emojiId, event);
|
|
298
|
+
}, [memorizedReactions, onReactionClick, trackActivatedReaction]);
|
|
299
|
+
const handleTrackedSummaryViewReactionClick = useCallback((emojiId, event) => {
|
|
300
|
+
trackActivatedReaction(emojiId, event, sortedReactions);
|
|
301
|
+
handleSummaryViewReactionClick(emojiId, event);
|
|
302
|
+
}, [handleSummaryViewReactionClick, sortedReactions, trackActivatedReaction]);
|
|
303
|
+
|
|
304
|
+
/**
|
|
305
|
+
* Restore focus when the activated reaction button leaves the DOM, either because the reaction was removed or
|
|
306
|
+
* because the reactions re-rendered in a different layout, rather than losing it to the document body
|
|
307
|
+
*/
|
|
308
|
+
useEffect(() => {
|
|
309
|
+
if (!fg('platform_a11y_reactions_removal_focus')) {
|
|
310
|
+
return;
|
|
311
|
+
}
|
|
312
|
+
const activatedReaction = activatedReactionRef.current;
|
|
313
|
+
// Only the first update after an activation can be its result
|
|
314
|
+
activatedReactionRef.current = null;
|
|
315
|
+
const wrapper = wrapperRef.current;
|
|
316
|
+
if (!activatedReaction || activatedReaction.button.isConnected || !wrapper) {
|
|
317
|
+
return;
|
|
318
|
+
}
|
|
319
|
+
const {
|
|
320
|
+
activeElement
|
|
321
|
+
} = wrapper.ownerDocument;
|
|
322
|
+
// Never take focus from where the user has since moved it
|
|
323
|
+
if (activeElement && activeElement !== wrapper.ownerDocument.body) {
|
|
324
|
+
return;
|
|
325
|
+
}
|
|
326
|
+
|
|
327
|
+
// The summary view tray can be portalled outside the wrapper, so search the activated button's list first
|
|
328
|
+
const {
|
|
329
|
+
list
|
|
330
|
+
} = activatedReaction;
|
|
331
|
+
const findReactionButton = emojiId => [list !== null && list !== void 0 && list.isConnected ? list : null, wrapper].flatMap(root => root ? Array.from(root.querySelectorAll('button[data-emoji-id]')) : []).find(button => button.dataset.emojiId === emojiId);
|
|
332
|
+
const {
|
|
333
|
+
emojiId,
|
|
334
|
+
shownEmojiIds
|
|
335
|
+
} = activatedReaction;
|
|
336
|
+
const index = shownEmojiIds.indexOf(emojiId);
|
|
337
|
+
const focusCandidates = [
|
|
338
|
+
// The same reaction re-rendered, e.g. a quick reaction going back to a zero count
|
|
339
|
+
() => findReactionButton(emojiId), ...shownEmojiIds.slice(index + 1).map(id => () => findReactionButton(id)), () => wrapper.querySelector(`[data-testid="${RENDER_TRIGGER_BUTTON_TESTID}"]`), ...shownEmojiIds.slice(0, index).reverse().map(id => () => findReactionButton(id))];
|
|
340
|
+
for (const findCandidate of focusCandidates) {
|
|
341
|
+
const candidate = findCandidate();
|
|
342
|
+
if (candidate !== null && candidate !== void 0 && candidate.isConnected) {
|
|
343
|
+
candidate.focus();
|
|
344
|
+
return;
|
|
345
|
+
}
|
|
346
|
+
}
|
|
347
|
+
}, [memorizedReactions]);
|
|
264
348
|
|
|
265
349
|
/**
|
|
266
350
|
* event handler to open dialog with selected reaction
|
|
@@ -291,7 +375,7 @@ export const Reactions = /*#__PURE__*/React.memo(({
|
|
|
291
375
|
rootElement: rootElement,
|
|
292
376
|
reaction: reaction,
|
|
293
377
|
emojiProvider: emojiProvider,
|
|
294
|
-
onClick: onReactionClick,
|
|
378
|
+
onClick: fg('platform_a11y_reactions_removal_focus') ? handleTrackedReactionClick : onReactionClick,
|
|
295
379
|
onMouseEnter: handleReactionMouseEnter,
|
|
296
380
|
onFocused: handleReactionFocused,
|
|
297
381
|
flash: flash[reaction.emojiId],
|
|
@@ -316,6 +400,7 @@ export const Reactions = /*#__PURE__*/React.memo(({
|
|
|
316
400
|
return /*#__PURE__*/React.createElement(UFOSegment, {
|
|
317
401
|
name: "reactions"
|
|
318
402
|
}, /*#__PURE__*/React.createElement("div", {
|
|
403
|
+
ref: wrapperRef,
|
|
319
404
|
"data-testid": RENDER_REACTIONS_TESTID,
|
|
320
405
|
className: ax(["_1e0c1txw _1n261g80 _kqswh2mm _4cvr1h6o _1pfhr5cr _1fohidpf", noWrap && "_1n261q9c", noRelativeContainer && "_kqswpfqs"])
|
|
321
406
|
}, !onlyRenderPicker && (shouldShowSummaryView ? /*#__PURE__*/React.createElement("div", {
|
|
@@ -326,7 +411,7 @@ export const Reactions = /*#__PURE__*/React.memo(({
|
|
|
326
411
|
flash: flash,
|
|
327
412
|
particleEffectByEmoji: particleEffectByEmoji,
|
|
328
413
|
onSelection: handleOnSelection,
|
|
329
|
-
onReactionClick: handleSummaryViewReactionClick,
|
|
414
|
+
onReactionClick: fg('platform_a11y_reactions_removal_focus') ? handleTrackedSummaryViewReactionClick : handleSummaryViewReactionClick,
|
|
330
415
|
onReactionFocused: handleReactionFocused,
|
|
331
416
|
onReactionMouseEnter: handleReactionMouseEnter,
|
|
332
417
|
placement: summaryViewPlacement,
|
|
@@ -5,7 +5,7 @@ import { UI_EVENT_TYPE, OPERATIONAL_EVENT_TYPE } from '@atlaskit/analytics-gas-t
|
|
|
5
5
|
// eslint-disable-next-line @typescript-eslint/consistent-type-imports
|
|
6
6
|
import createAndFireEvent from '@atlaskit/analytics-next/createAndFireEvents';
|
|
7
7
|
var packageName = "@atlaskit/reactions";
|
|
8
|
-
var packageVersion = "37.
|
|
8
|
+
var packageVersion = "37.1.0";
|
|
9
9
|
/**
|
|
10
10
|
* TODO: move to utility package?
|
|
11
11
|
* A random sampling function
|
|
@@ -3,6 +3,9 @@ import _toConsumableArray from "@babel/runtime/helpers/toConsumableArray";
|
|
|
3
3
|
import _slicedToArray from "@babel/runtime/helpers/slicedToArray";
|
|
4
4
|
import "./Reactions.compiled.css";
|
|
5
5
|
import { ax, ix } from "@compiled/react/runtime";
|
|
6
|
+
function _createForOfIteratorHelper(r, e) { var t = "undefined" != typeof Symbol && r[Symbol.iterator] || r["@@iterator"]; if (!t) { if (Array.isArray(r) || (t = _unsupportedIterableToArray(r)) || e && r && "number" == typeof r.length) { t && (r = t); var _n = 0, F = function F() {}; return { s: F, n: function n() { return _n >= r.length ? { done: !0 } : { done: !1, value: r[_n++] }; }, e: function e(r) { throw r; }, f: F }; } throw new TypeError("Invalid attempt to iterate non-iterable instance.\nIn order to be iterable, non-array objects must have a [Symbol.iterator]() method."); } var o, a = !0, u = !1; return { s: function s() { t = t.call(r); }, n: function n() { var r = t.next(); return a = r.done, r; }, e: function e(r) { u = !0, o = r; }, f: function f() { try { a || null == t.return || t.return(); } finally { if (u) throw o; } } }; }
|
|
7
|
+
function _unsupportedIterableToArray(r, a) { if (r) { if ("string" == typeof r) return _arrayLikeToArray(r, a); var t = {}.toString.call(r).slice(8, -1); return "Object" === t && r.constructor && (t = r.constructor.name), "Map" === t || "Set" === t ? Array.from(r) : "Arguments" === t || /^(?:Ui|I)nt(?:8|16|32)(?:Clamped)?Array$/.test(t) ? _arrayLikeToArray(r, a) : void 0; } }
|
|
8
|
+
function _arrayLikeToArray(r, a) { (null == a || a > r.length) && (a = r.length); for (var e = 0, n = Array(a); e < a; e++) n[e] = r[e]; return n; }
|
|
6
9
|
import React, { useCallback, useEffect, useMemo, useRef, useState } from 'react';
|
|
7
10
|
import { FormattedMessage, useIntl } from 'react-intl';
|
|
8
11
|
import { useAnalyticsEvents } from '@atlaskit/analytics-next/useAnalyticsEvents';
|
|
@@ -18,6 +21,7 @@ import { Reaction } from './Reaction';
|
|
|
18
21
|
import { ReactionPicker } from './ReactionPicker';
|
|
19
22
|
import { ReactionsDialog } from './ReactionsDialog';
|
|
20
23
|
import { ReactionSummaryView } from './ReactionSummaryView';
|
|
24
|
+
import { RENDER_TRIGGER_BUTTON_TESTID } from './Trigger';
|
|
21
25
|
var wrapperStyle = null;
|
|
22
26
|
var noFlexWrapStyles = null;
|
|
23
27
|
var noContainerPositionStyles = null;
|
|
@@ -302,6 +306,114 @@ export var Reactions = /*#__PURE__*/React.memo(function (_ref) {
|
|
|
302
306
|
return (b === null || b === void 0 ? void 0 : b.count) - (a === null || a === void 0 ? void 0 : a.count);
|
|
303
307
|
});
|
|
304
308
|
}, [memorizedReactions]);
|
|
309
|
+
var wrapperRef = useRef(null);
|
|
310
|
+
/**
|
|
311
|
+
* The reaction button the user activated while it had focus, with the order of the reactions shown alongside it
|
|
312
|
+
*/
|
|
313
|
+
var activatedReactionRef = useRef(null);
|
|
314
|
+
var trackActivatedReaction = useCallback(function (emojiId, event, shownReactions) {
|
|
315
|
+
var button = event.currentTarget;
|
|
316
|
+
// Only keyboard and screen reader users, or mouse clicks that focus the button, can lose focus with it
|
|
317
|
+
if (button.ownerDocument.activeElement !== button) {
|
|
318
|
+
activatedReactionRef.current = null;
|
|
319
|
+
return;
|
|
320
|
+
}
|
|
321
|
+
activatedReactionRef.current = {
|
|
322
|
+
button: button,
|
|
323
|
+
emojiId: emojiId,
|
|
324
|
+
// Read now, as a removed button no longer has ancestors
|
|
325
|
+
list: button.closest('ul'),
|
|
326
|
+
shownEmojiIds: shownReactions.map(function (reaction) {
|
|
327
|
+
return reaction.emojiId;
|
|
328
|
+
})
|
|
329
|
+
};
|
|
330
|
+
// Focus moved away by the user while the button is still shown was not lost with it.
|
|
331
|
+
// Chrome fires focusout before detaching a removed button, so check once the removal has finished.
|
|
332
|
+
button.addEventListener('focusout', function () {
|
|
333
|
+
return queueMicrotask(function () {
|
|
334
|
+
var _activatedReactionRef;
|
|
335
|
+
if (button.isConnected && ((_activatedReactionRef = activatedReactionRef.current) === null || _activatedReactionRef === void 0 ? void 0 : _activatedReactionRef.button) === button) {
|
|
336
|
+
activatedReactionRef.current = null;
|
|
337
|
+
}
|
|
338
|
+
});
|
|
339
|
+
}, {
|
|
340
|
+
once: true
|
|
341
|
+
});
|
|
342
|
+
}, []);
|
|
343
|
+
var handleTrackedReactionClick = useCallback(function (emojiId, event) {
|
|
344
|
+
trackActivatedReaction(emojiId, event, memorizedReactions);
|
|
345
|
+
onReactionClick(emojiId, event);
|
|
346
|
+
}, [memorizedReactions, onReactionClick, trackActivatedReaction]);
|
|
347
|
+
var handleTrackedSummaryViewReactionClick = useCallback(function (emojiId, event) {
|
|
348
|
+
trackActivatedReaction(emojiId, event, sortedReactions);
|
|
349
|
+
handleSummaryViewReactionClick(emojiId, event);
|
|
350
|
+
}, [handleSummaryViewReactionClick, sortedReactions, trackActivatedReaction]);
|
|
351
|
+
|
|
352
|
+
/**
|
|
353
|
+
* Restore focus when the activated reaction button leaves the DOM, either because the reaction was removed or
|
|
354
|
+
* because the reactions re-rendered in a different layout, rather than losing it to the document body
|
|
355
|
+
*/
|
|
356
|
+
useEffect(function () {
|
|
357
|
+
if (!fg('platform_a11y_reactions_removal_focus')) {
|
|
358
|
+
return;
|
|
359
|
+
}
|
|
360
|
+
var activatedReaction = activatedReactionRef.current;
|
|
361
|
+
// Only the first update after an activation can be its result
|
|
362
|
+
activatedReactionRef.current = null;
|
|
363
|
+
var wrapper = wrapperRef.current;
|
|
364
|
+
if (!activatedReaction || activatedReaction.button.isConnected || !wrapper) {
|
|
365
|
+
return;
|
|
366
|
+
}
|
|
367
|
+
var activeElement = wrapper.ownerDocument.activeElement;
|
|
368
|
+
// Never take focus from where the user has since moved it
|
|
369
|
+
if (activeElement && activeElement !== wrapper.ownerDocument.body) {
|
|
370
|
+
return;
|
|
371
|
+
}
|
|
372
|
+
|
|
373
|
+
// The summary view tray can be portalled outside the wrapper, so search the activated button's list first
|
|
374
|
+
var list = activatedReaction.list;
|
|
375
|
+
var findReactionButton = function findReactionButton(emojiId) {
|
|
376
|
+
return [list !== null && list !== void 0 && list.isConnected ? list : null, wrapper].flatMap(function (root) {
|
|
377
|
+
return root ? Array.from(root.querySelectorAll('button[data-emoji-id]')) : [];
|
|
378
|
+
}).find(function (button) {
|
|
379
|
+
return button.dataset.emojiId === emojiId;
|
|
380
|
+
});
|
|
381
|
+
};
|
|
382
|
+
var emojiId = activatedReaction.emojiId,
|
|
383
|
+
shownEmojiIds = activatedReaction.shownEmojiIds;
|
|
384
|
+
var index = shownEmojiIds.indexOf(emojiId);
|
|
385
|
+
var focusCandidates = [
|
|
386
|
+
// The same reaction re-rendered, e.g. a quick reaction going back to a zero count
|
|
387
|
+
function () {
|
|
388
|
+
return findReactionButton(emojiId);
|
|
389
|
+
}].concat(_toConsumableArray(shownEmojiIds.slice(index + 1).map(function (id) {
|
|
390
|
+
return function () {
|
|
391
|
+
return findReactionButton(id);
|
|
392
|
+
};
|
|
393
|
+
})), [function () {
|
|
394
|
+
return wrapper.querySelector("[data-testid=\"".concat(RENDER_TRIGGER_BUTTON_TESTID, "\"]"));
|
|
395
|
+
}], _toConsumableArray(shownEmojiIds.slice(0, index).reverse().map(function (id) {
|
|
396
|
+
return function () {
|
|
397
|
+
return findReactionButton(id);
|
|
398
|
+
};
|
|
399
|
+
})));
|
|
400
|
+
var _iterator = _createForOfIteratorHelper(focusCandidates),
|
|
401
|
+
_step;
|
|
402
|
+
try {
|
|
403
|
+
for (_iterator.s(); !(_step = _iterator.n()).done;) {
|
|
404
|
+
var findCandidate = _step.value;
|
|
405
|
+
var candidate = findCandidate();
|
|
406
|
+
if (candidate !== null && candidate !== void 0 && candidate.isConnected) {
|
|
407
|
+
candidate.focus();
|
|
408
|
+
return;
|
|
409
|
+
}
|
|
410
|
+
}
|
|
411
|
+
} catch (err) {
|
|
412
|
+
_iterator.e(err);
|
|
413
|
+
} finally {
|
|
414
|
+
_iterator.f();
|
|
415
|
+
}
|
|
416
|
+
}, [memorizedReactions]);
|
|
305
417
|
|
|
306
418
|
/**
|
|
307
419
|
* event handler to open dialog with selected reaction
|
|
@@ -335,7 +447,7 @@ export var Reactions = /*#__PURE__*/React.memo(function (_ref) {
|
|
|
335
447
|
rootElement: rootElement,
|
|
336
448
|
reaction: reaction,
|
|
337
449
|
emojiProvider: emojiProvider,
|
|
338
|
-
onClick: onReactionClick,
|
|
450
|
+
onClick: fg('platform_a11y_reactions_removal_focus') ? handleTrackedReactionClick : onReactionClick,
|
|
339
451
|
onMouseEnter: handleReactionMouseEnter,
|
|
340
452
|
onFocused: handleReactionFocused,
|
|
341
453
|
flash: flash[reaction.emojiId],
|
|
@@ -365,6 +477,7 @@ export var Reactions = /*#__PURE__*/React.memo(function (_ref) {
|
|
|
365
477
|
return /*#__PURE__*/React.createElement(UFOSegment, {
|
|
366
478
|
name: "reactions"
|
|
367
479
|
}, /*#__PURE__*/React.createElement("div", {
|
|
480
|
+
ref: wrapperRef,
|
|
368
481
|
"data-testid": RENDER_REACTIONS_TESTID,
|
|
369
482
|
className: ax(["_1e0c1txw _1n261g80 _kqswh2mm _4cvr1h6o _1pfhr5cr _1fohidpf", noWrap && "_1n261q9c", noRelativeContainer && "_kqswpfqs"])
|
|
370
483
|
}, !onlyRenderPicker && (shouldShowSummaryView ? /*#__PURE__*/React.createElement("div", {
|
|
@@ -375,7 +488,7 @@ export var Reactions = /*#__PURE__*/React.memo(function (_ref) {
|
|
|
375
488
|
flash: flash,
|
|
376
489
|
particleEffectByEmoji: particleEffectByEmoji,
|
|
377
490
|
onSelection: handleOnSelection,
|
|
378
|
-
onReactionClick: handleSummaryViewReactionClick,
|
|
491
|
+
onReactionClick: fg('platform_a11y_reactions_removal_focus') ? handleTrackedSummaryViewReactionClick : handleSummaryViewReactionClick,
|
|
379
492
|
onReactionFocused: handleReactionFocused,
|
|
380
493
|
onReactionMouseEnter: handleReactionMouseEnter,
|
|
381
494
|
placement: summaryViewPlacement,
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@atlaskit/reactions",
|
|
3
|
-
"version": "37.
|
|
3
|
+
"version": "37.1.1",
|
|
4
4
|
"description": "Reactions component",
|
|
5
5
|
"publishConfig": {
|
|
6
6
|
"registry": "https://registry.npmjs.org/"
|
|
@@ -33,14 +33,14 @@
|
|
|
33
33
|
"access": "public"
|
|
34
34
|
},
|
|
35
35
|
"dependencies": {
|
|
36
|
-
"@atlaskit/afm-i18n-platform-elements-reactions": "2.
|
|
36
|
+
"@atlaskit/afm-i18n-platform-elements-reactions": "2.287.0",
|
|
37
37
|
"@atlaskit/analytics-gas-types": "^6.2.0",
|
|
38
38
|
"@atlaskit/analytics-namespaced-context": "^8.2.0",
|
|
39
39
|
"@atlaskit/analytics-next": "^12.6.0",
|
|
40
40
|
"@atlaskit/avatar": "^30.0.0",
|
|
41
|
-
"@atlaskit/button": "^25.
|
|
41
|
+
"@atlaskit/button": "^25.6.0",
|
|
42
42
|
"@atlaskit/css": "^1.1.0",
|
|
43
|
-
"@atlaskit/emoji": "^73.
|
|
43
|
+
"@atlaskit/emoji": "^73.1.0",
|
|
44
44
|
"@atlaskit/feature-gate-js-client": "^7.0.0",
|
|
45
45
|
"@atlaskit/heading": "^8.0.0",
|
|
46
46
|
"@atlaskit/icon": "^38.0.0",
|
|
@@ -51,15 +51,15 @@
|
|
|
51
51
|
"@atlaskit/platform-feature-flags": "^2.2.0",
|
|
52
52
|
"@atlaskit/popper": "^9.4.0",
|
|
53
53
|
"@atlaskit/popup": "^10.0.0",
|
|
54
|
-
"@atlaskit/portal": "^7.
|
|
54
|
+
"@atlaskit/portal": "^7.1.0",
|
|
55
55
|
"@atlaskit/primitives": "^22.6.0",
|
|
56
56
|
"@atlaskit/react-compiler-gating": "^0.2.0",
|
|
57
57
|
"@atlaskit/react-ufo": "^8.1.0",
|
|
58
58
|
"@atlaskit/spinner": "^20.4.0",
|
|
59
59
|
"@atlaskit/tabs": "^21.3.0",
|
|
60
60
|
"@atlaskit/theme": "^28.2.0",
|
|
61
|
-
"@atlaskit/tmp-editor-statsig": "^
|
|
62
|
-
"@atlaskit/tokens": "^20.
|
|
61
|
+
"@atlaskit/tmp-editor-statsig": "^246.0.0",
|
|
62
|
+
"@atlaskit/tokens": "^20.7.0",
|
|
63
63
|
"@atlaskit/tooltip": "^24.4.0",
|
|
64
64
|
"@atlaskit/ufo": "^2.0.0",
|
|
65
65
|
"@atlaskit/util-service-support": "^7.4.0",
|