@atlaskit/editor-plugin-mentions 16.1.5 → 16.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.
Files changed (27) hide show
  1. package/CHANGELOG.md +11 -0
  2. package/compass.yml +2 -2
  3. package/dist/cjs/entry-points/mention-node-data-provider.js +12 -0
  4. package/dist/cjs/nodeviews/mentionAvatarRenderer.js +75 -0
  5. package/dist/cjs/nodeviews/mentionNodeView.js +79 -10
  6. package/dist/cjs/nodeviews/profileCardRenderer.js +11 -9
  7. package/dist/cjs/pm-plugins/main.js +1 -1
  8. package/dist/cjs/providers/mention-node-data-provider.js +205 -0
  9. package/dist/es2019/entry-points/mention-node-data-provider.js +3 -0
  10. package/dist/es2019/nodeviews/mentionAvatarRenderer.js +71 -0
  11. package/dist/es2019/nodeviews/mentionNodeView.js +75 -10
  12. package/dist/es2019/nodeviews/profileCardRenderer.js +7 -5
  13. package/dist/es2019/pm-plugins/main.js +1 -1
  14. package/dist/es2019/providers/mention-node-data-provider.js +115 -0
  15. package/dist/esm/entry-points/mention-node-data-provider.js +3 -0
  16. package/dist/esm/nodeviews/mentionAvatarRenderer.js +69 -0
  17. package/dist/esm/nodeviews/mentionNodeView.js +79 -10
  18. package/dist/esm/nodeviews/profileCardRenderer.js +11 -9
  19. package/dist/esm/pm-plugins/main.js +1 -1
  20. package/dist/esm/providers/mention-node-data-provider.js +198 -0
  21. package/dist/types/entry-points/mention-node-data-provider.d.ts +2 -0
  22. package/dist/types/nodeviews/mentionAvatarRenderer.d.ts +12 -0
  23. package/dist/types/nodeviews/mentionNodeView.d.ts +6 -0
  24. package/dist/types/providers/mention-node-data-provider.d.ts +39 -0
  25. package/dist/types/types/index.d.ts +6 -0
  26. package/mention-node-data-provider/package.json +10 -0
  27. package/package.json +14 -6
package/CHANGELOG.md CHANGED
@@ -1,5 +1,16 @@
1
1
  # @atlaskit/editor-plugin-mentions
2
2
 
3
+ ## 16.2.0
4
+
5
+ ### Minor Changes
6
+
7
+ - [`13e86ff9f1588`](https://bitbucket.org/atlassian/atlassian-frontend-monorepo/commits/13e86ff9f1588) -
8
+ [ux] Display avatars for mention nodes.
9
+
10
+ ### Patch Changes
11
+
12
+ - Updated dependencies
13
+
3
14
  ## 16.1.5
4
15
 
5
16
  ### Patch Changes
package/compass.yml CHANGED
@@ -1,7 +1,7 @@
1
1
  configVersion: 1
2
2
  id: ari:cloud:compass:a436116f-02ce-4520-8fbb-7301462a1674:component/c5751cc6-3513-4070-9deb-af31e86aed34/7492c730-d44c-453e-af94-85a8b85e8279
3
3
  name: '@atlaskit/editor-plugin-mentions'
4
- ownerId: ari:cloud:identity::team/0250ee69-f755-47fd-a468-bf8a9d10a3c5 # Editor AI
4
+ ownerId: ari:cloud:identity::team/cf6a670b-5252-4c68-a769-9207de366beb # Editor Developers
5
5
  labels:
6
6
  - platform-code
7
7
  - platform-afm
@@ -23,7 +23,7 @@ links:
23
23
  customFields:
24
24
  - name: Department
25
25
  type: text
26
- value: Eng - Editor AI
26
+ value: Editor Developers
27
27
  - name: Trusted Reviewer Teams
28
28
  type: text
29
29
  value: ari:cloud:identity::team/cf6a670b-5252-4c68-a769-9207de366beb
@@ -0,0 +1,12 @@
1
+ "use strict";
2
+
3
+ Object.defineProperty(exports, "__esModule", {
4
+ value: true
5
+ });
6
+ Object.defineProperty(exports, "MentionNodeDataProvider", {
7
+ enumerable: true,
8
+ get: function get() {
9
+ return _mentionNodeDataProvider.MentionNodeDataProvider;
10
+ }
11
+ });
12
+ var _mentionNodeDataProvider = require("../providers/mention-node-data-provider");
@@ -0,0 +1,75 @@
1
+ "use strict";
2
+
3
+ Object.defineProperty(exports, "__esModule", {
4
+ value: true
5
+ });
6
+ exports.mentionAvatarRenderer = void 0;
7
+ var _bindEventListener = require("bind-event-listener");
8
+ var avatarImageClassName = 'editor-mention-avatar-image';
9
+ var agentAvatarClassName = 'editor-mention-avatar-agent';
10
+ var fallbackAvatarClassName = 'editor-mention-avatar-fallback';
11
+ var avatarSize = 16;
12
+ /**
13
+ * Populates the fixed-size avatar slot owned by the vanilla ProseMirror NodeView.
14
+ * No React root or editor portal is created for individual mention nodes.
15
+ */
16
+ var mentionAvatarRenderer = exports.mentionAvatarRenderer = function mentionAvatarRenderer(_ref) {
17
+ var container = _ref.container;
18
+ var image;
19
+ var fallback;
20
+ var unbindImageError;
21
+ var removeImage = function removeImage() {
22
+ var _unbindImageError, _image;
23
+ (_unbindImageError = unbindImageError) === null || _unbindImageError === void 0 || _unbindImageError();
24
+ unbindImageError = undefined;
25
+ (_image = image) === null || _image === void 0 || _image.remove();
26
+ image = undefined;
27
+ };
28
+ var removeFallback = function removeFallback() {
29
+ var _fallback;
30
+ (_fallback = fallback) === null || _fallback === void 0 || _fallback.remove();
31
+ fallback = undefined;
32
+ container.classList.remove(fallbackAvatarClassName);
33
+ };
34
+ var showFallback = function showFallback() {
35
+ removeImage();
36
+ removeFallback();
37
+ fallback = container.ownerDocument.createTextNode('@');
38
+ container.appendChild(fallback);
39
+ container.classList.add(fallbackAvatarClassName);
40
+ };
41
+ var destroy = function destroy() {
42
+ removeImage();
43
+ removeFallback();
44
+ };
45
+ return {
46
+ destroy: destroy,
47
+ render: function render(_ref2) {
48
+ var appType = _ref2.appType,
49
+ avatarUrl = _ref2.avatarUrl,
50
+ isAvatarImagePreShaped = _ref2.isAvatarImagePreShaped;
51
+ container.classList.toggle(agentAvatarClassName, !isAvatarImagePreShaped && appType === 'agent');
52
+ removeFallback();
53
+ if (!avatarUrl) {
54
+ removeImage();
55
+ return;
56
+ }
57
+ if (!image) {
58
+ image = container.ownerDocument.createElement('img');
59
+ image.alt = '';
60
+ image.className = avatarImageClassName;
61
+ image.decoding = 'async';
62
+ image.draggable = false;
63
+ image.height = avatarSize;
64
+ image.loading = 'lazy';
65
+ image.width = avatarSize;
66
+ unbindImageError = (0, _bindEventListener.bind)(image, {
67
+ type: 'error',
68
+ listener: showFallback
69
+ });
70
+ container.appendChild(image);
71
+ }
72
+ image.src = avatarUrl;
73
+ }
74
+ };
75
+ };
@@ -13,16 +13,24 @@ var _defineProperty2 = _interopRequireDefault(require("@babel/runtime/helpers/de
13
13
  var _browser = require("@atlaskit/editor-common/browser");
14
14
  var _whitespace = require("@atlaskit/editor-common/whitespace");
15
15
  var _model = require("@atlaskit/editor-prosemirror/model");
16
+ var _constants = require("@atlaskit/mention/constants");
16
17
  var _resource = require("@atlaskit/mention/resource");
17
18
  var _types = require("@atlaskit/mention/types");
19
+ var _isExperimentEnabled = require("@atlaskit/platform-feature-experiments/is-experiment-enabled");
18
20
  var _platformFeatureFlags = require("@atlaskit/platform-feature-flags");
19
21
  var _expValEquals = require("@atlaskit/tmp-editor-statsig/exp-val-equals");
20
22
  var _expVal = require("@atlaskit/tmp-editor-statsig/expVal");
21
23
  var _disabledTooltipRenderer = require("./disabledTooltipRenderer");
24
+ var _mentionAvatarRenderer = require("./mentionAvatarRenderer");
22
25
  var _profileCardRenderer2 = require("./profileCardRenderer");
23
26
  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; }
24
27
  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; }
25
28
  var primitiveClassName = 'editor-mention-primitive';
29
+ var primitiveWithAvatarClassName = 'editor-mention-primitive-with-avatar';
30
+ var avatarContainerClassName = 'editor-mention-avatar';
31
+ var mentionTextClassName = 'editor-mention-text';
32
+ var genericMentionIds = ['HipChat', 'all', 'here'];
33
+ var unknownMentionText = "@".concat(_constants.UNKNOWN_USER_ID);
26
34
  // eslint-disable-next-line require-unicode-regexp
27
35
  var AT_PREFIX_REGEX = /^@/;
28
36
  var getAccessibilityLabelFromName = function getAccessibilityLabelFromName(name) {
@@ -53,7 +61,7 @@ var isAgentMentionsExperimentEnabled = function isAgentMentionsExperimentEnabled
53
61
  var isAgentAaidText = function isAgentAaidText(node, isAgentMentionsEnabled) {
54
62
  return isAgentMentionsEnabled && (node.attrs.userType === 'APP' || node.attrs.userType === 'AGENT') && !!node.attrs.text && isMentionTextAnAaid(node.attrs.text);
55
63
  };
56
- var toDOM = function toDOM(node) {
64
+ var toDOM = function toDOM(node, hasAvatarSlot) {
57
65
  // packages/elements/mention/src/components/Mention/index.tsx
58
66
  var mentionAttrs = {
59
67
  contenteditable: 'false',
@@ -78,14 +86,25 @@ var toDOM = function toDOM(node) {
78
86
  }
79
87
  var browser = (0, _browser.getBrowserInfo)();
80
88
  var hasAgentAaidText = isAgentAaidText(node, isAgentMentionsEnabled);
89
+ var mentionText = node.attrs.text && !hasAgentAaidText ? node.attrs.text : '@…';
90
+ var visibleMentionText = hasAvatarSlot && mentionText.startsWith('@') ? mentionText.slice(1) : mentionText;
91
+ var mentionContentSpec = hasAvatarSlot ? ['span', {
92
+ spellcheck: 'false',
93
+ class: "".concat(primitiveClassName, " ").concat(primitiveWithAvatarClassName)
94
+ }, ['span', {
95
+ class: avatarContainerClassName,
96
+ 'aria-hidden': 'true'
97
+ }], ['span', {
98
+ class: mentionTextClassName
99
+ }, visibleMentionText]] : ['span', {
100
+ spellcheck: 'false',
101
+ class: primitiveClassName
102
+ }, mentionText];
81
103
  return ['span', mentionAttrs, ['span', {
82
104
  class: 'zeroWidthSpaceContainer'
83
105
  }, ['span', {
84
106
  class: 'inlineNodeViewAddZeroWidthSpace'
85
- }, _whitespace.ZERO_WIDTH_SPACE]], ['span', {
86
- spellcheck: 'false',
87
- class: primitiveClassName
88
- }, node.attrs.text && !hasAgentAaidText ? node.attrs.text : '@…'], browser.android ? ['span', {
107
+ }, _whitespace.ZERO_WIDTH_SPACE]], mentionContentSpec, browser.android ? ['span', {
89
108
  class: 'zeroWidthSpaceContainer',
90
109
  contenteditable: 'false'
91
110
  }, ['span', {
@@ -95,7 +114,7 @@ var toDOM = function toDOM(node) {
95
114
  }, _whitespace.ZERO_WIDTH_SPACE]];
96
115
  };
97
116
  var processName = function processName(name) {
98
- return name.status === _resource.MentionNameStatus.OK ? "@".concat(name.name || '') : "@_|unknown|_";
117
+ return name.status === _resource.MentionNameStatus.OK ? "@".concat(name.name || '') : unknownMentionText;
99
118
  };
100
119
  var handleProviderName = /*#__PURE__*/function () {
101
120
  var _ref = (0, _asyncToGenerator2.default)( /*#__PURE__*/_regenerator.default.mark(function _callee(mentionProvider, node, isAgentMentionsEnabled) {
@@ -143,11 +162,14 @@ var MentionNodeView = exports.MentionNodeView = /*#__PURE__*/function () {
143
162
  _api$mention$sharedSt,
144
163
  _this = this;
145
164
  (0, _classCallCheck2.default)(this, MentionNodeView);
165
+ (0, _defineProperty2.default)(this, "hasAvatarSlot", false);
166
+ (0, _defineProperty2.default)(this, "isDestroyed", false);
146
167
  var options = config.options,
147
168
  api = config.api,
148
169
  portalProviderAPI = config.portalProviderAPI,
149
170
  editorView = config.editorView;
150
- var _DOMSerializer$render = _model.DOMSerializer.renderSpec(document, toDOM(node)),
171
+ this.hasAvatarSlot = Boolean(options === null || options === void 0 ? void 0 : options.mentionNodeDataProvider) && node.attrs.userType !== 'SPECIAL' && !genericMentionIds.includes(node.attrs.id) && (0, _isExperimentEnabled.isExperimentEnabled)('platform_editor_mention_node_avatar');
172
+ var _DOMSerializer$render = _model.DOMSerializer.renderSpec(document, toDOM(node, this.hasAvatarSlot)),
151
173
  dom = _DOMSerializer$render.dom,
152
174
  contentDOM = _DOMSerializer$render.contentDOM;
153
175
  this.dom = dom;
@@ -156,6 +178,18 @@ var MentionNodeView = exports.MentionNodeView = /*#__PURE__*/function () {
156
178
  this.node = node;
157
179
  this.domElement = dom instanceof HTMLElement ? dom : undefined;
158
180
  this.mentionPrimitiveElement = this.domElement ? (_this$domElement$quer = this.domElement.querySelector(".".concat(primitiveClassName))) !== null && _this$domElement$quer !== void 0 ? _this$domElement$quer : undefined : undefined;
181
+ this.mentionTextElement = this.mentionPrimitiveElement;
182
+ if (this.hasAvatarSlot) {
183
+ var _this$domElement$quer2, _this$domElement, _this$domElement2;
184
+ this.mentionTextElement = (_this$domElement$quer2 = (_this$domElement = this.domElement) === null || _this$domElement === void 0 ? void 0 : _this$domElement.querySelector(".".concat(mentionTextClassName))) !== null && _this$domElement$quer2 !== void 0 ? _this$domElement$quer2 : this.mentionPrimitiveElement;
185
+ var avatarContainer = (_this$domElement2 = this.domElement) === null || _this$domElement2 === void 0 ? void 0 : _this$domElement2.querySelector(".".concat(avatarContainerClassName));
186
+ if (avatarContainer) {
187
+ this.mentionAvatar = (0, _mentionAvatarRenderer.mentionAvatarRenderer)({
188
+ container: avatarContainer
189
+ });
190
+ this.resolveMentionAvatar(options === null || options === void 0 ? void 0 : options.mentionNodeDataProvider);
191
+ }
192
+ }
159
193
  var _ref2 = (_api$mention$sharedSt = api === null || api === void 0 ? void 0 : api.mention.sharedState.currentState()) !== null && _api$mention$sharedSt !== void 0 ? _api$mention$sharedSt : {},
160
194
  mentionProvider = _ref2.mentionProvider;
161
195
  this.updateState(mentionProvider);
@@ -287,9 +321,41 @@ var MentionNodeView = exports.MentionNodeView = /*#__PURE__*/function () {
287
321
  value: function setTextContent(name, isAgentMentionsEnabled) {
288
322
  // Also overwrite when text is a raw AAID so the resolved name takes precedence.
289
323
  var textIsAaid = isAgentAaidText(this.node, isAgentMentionsEnabled);
290
- if (name && (!this.node.attrs.text || textIsAaid) && this.mentionPrimitiveElement) {
291
- this.mentionPrimitiveElement.textContent = name;
324
+ if (name && (!this.node.attrs.text || textIsAaid) && this.mentionTextElement) {
325
+ this.setVisibleText(name);
326
+ }
327
+ }
328
+ }, {
329
+ key: "setVisibleText",
330
+ value: function setVisibleText(text) {
331
+ if (!this.mentionTextElement) {
332
+ return;
333
+ }
334
+ this.mentionTextElement.textContent = this.hasAvatarSlot && text.startsWith('@') && text !== unknownMentionText ? text.slice(1) : text;
335
+ }
336
+ }, {
337
+ key: "resolveMentionAvatar",
338
+ value: function resolveMentionAvatar(mentionNodeDataProvider) {
339
+ var _this3 = this;
340
+ if (!this.hasAvatarSlot || !mentionNodeDataProvider || this.node.attrs.userType === 'SPECIAL') {
341
+ return;
292
342
  }
343
+ var mention = {
344
+ id: this.node.attrs.id,
345
+ userType: this.node.attrs.userType
346
+ };
347
+ var applyData = function applyData(data) {
348
+ var _this3$mentionAvatar;
349
+ if (_this3.isDestroyed || !(data !== null && data !== void 0 && data.avatarUrl)) {
350
+ return;
351
+ }
352
+ (_this3$mentionAvatar = _this3.mentionAvatar) === null || _this3$mentionAvatar === void 0 || _this3$mentionAvatar.render(data);
353
+ };
354
+ mentionNodeDataProvider.getMentionData(mention, function (payload) {
355
+ if (payload.data) {
356
+ applyData(payload.data);
357
+ }
358
+ });
293
359
  }
294
360
  }, {
295
361
  key: "shouldHighlightMention",
@@ -386,7 +452,8 @@ var MentionNodeView = exports.MentionNodeView = /*#__PURE__*/function () {
386
452
  }, {
387
453
  key: "destroy",
388
454
  value: function destroy() {
389
- var _this$cleanup, _this$destroyProfileC, _this$disabledTooltip, _this$unsubscribeFrom2;
455
+ var _this$cleanup, _this$destroyProfileC, _this$mentionAvatar, _this$disabledTooltip, _this$unsubscribeFrom2;
456
+ this.isDestroyed = true;
390
457
  // Surface the destruction to the provider before tearing down so the
391
458
  // chat layer can react (e.g. drop the agent id from `selectedAgentIds`).
392
459
  // This is the lowest-level deletion signal — fires for backspace,
@@ -402,6 +469,8 @@ var MentionNodeView = exports.MentionNodeView = /*#__PURE__*/function () {
402
469
  }
403
470
  (_this$cleanup = this.cleanup) === null || _this$cleanup === void 0 || _this$cleanup.call(this);
404
471
  (_this$destroyProfileC = this.destroyProfileCard) === null || _this$destroyProfileC === void 0 || _this$destroyProfileC.call(this);
472
+ (_this$mentionAvatar = this.mentionAvatar) === null || _this$mentionAvatar === void 0 || _this$mentionAvatar.destroy();
473
+ this.mentionAvatar = undefined;
405
474
  (_this$disabledTooltip = this.disabledTooltip) === null || _this$disabledTooltip === void 0 || _this$disabledTooltip.destroy();
406
475
  this.disabledTooltip = undefined;
407
476
  (_this$unsubscribeFrom2 = this.unsubscribeFromDisabledStateChanges) === null || _this$unsubscribeFrom2 === void 0 || _this$unsubscribeFrom2.call(this);
@@ -66,13 +66,15 @@ var profileCardRenderer = exports.profileCardRenderer = function profileCardRend
66
66
  var renderEditorProfileCard = function renderEditorProfileCard() {
67
67
  var isReducedProfileCards = (0, _expVal.expVal)('platform_editor_reduced_agent_profile_cards', 'isEnabled', false);
68
68
  var clickedNode = isReducedProfileCards ? currentNode : node;
69
- var activeMention = isReducedProfileCards ? function (_dom$querySelector, _currentNode, _currentNode2) {
70
- // Read the display name from the DOM element at click time — this is
71
- // always up-to-date even when node.attrs.text is absent
72
- var primitiveText = dom instanceof HTMLElement ? (_dom$querySelector = dom.querySelector('.editor-mention-primitive')) === null || _dom$querySelector === void 0 || (_dom$querySelector = _dom$querySelector.textContent) === null || _dom$querySelector === void 0 ? void 0 : _dom$querySelector.trim() : undefined;
69
+ var activeMention = isReducedProfileCards ? function (_ref3, _currentNode, _currentNode2, _currentNode3) {
70
+ // Avatar mentions keep their resolved display name in the nested text span.
71
+ // Control mentions preserve the legacy attrs-first fallback.
72
+ var mentionTextElement = dom instanceof HTMLElement ? dom.querySelector('.editor-mention-text') : undefined;
73
+ var primitiveText = (_ref3 = mentionTextElement !== null && mentionTextElement !== void 0 ? mentionTextElement : dom instanceof HTMLElement ? dom.querySelector('.editor-mention-primitive') : undefined) === null || _ref3 === void 0 || (_ref3 = _ref3.textContent) === null || _ref3 === void 0 ? void 0 : _ref3.trim();
74
+ var resolvedText = primitiveText && !primitiveText.startsWith('@') ? "@".concat(primitiveText) : primitiveText;
73
75
  return {
74
76
  attrs: _objectSpread(_objectSpread({}, (_currentNode = currentNode) === null || _currentNode === void 0 ? void 0 : _currentNode.attrs), {}, {
75
- text: ((_currentNode2 = currentNode) === null || _currentNode2 === void 0 || (_currentNode2 = _currentNode2.attrs) === null || _currentNode2 === void 0 ? void 0 : _currentNode2.text) || primitiveText || undefined
77
+ text: mentionTextElement ? resolvedText || ((_currentNode2 = currentNode) === null || _currentNode2 === void 0 || (_currentNode2 = _currentNode2.attrs) === null || _currentNode2 === void 0 ? void 0 : _currentNode2.text) || undefined : ((_currentNode3 = currentNode) === null || _currentNode3 === void 0 || (_currentNode3 = _currentNode3.attrs) === null || _currentNode3 === void 0 ? void 0 : _currentNode3.text) || primitiveText || undefined
76
78
  })
77
79
  };
78
80
  }() : {
@@ -108,10 +110,10 @@ var profileCardRenderer = exports.profileCardRenderer = function profileCardRend
108
110
  });
109
111
  });
110
112
  };
111
- var renderUserProfileCard = function renderUserProfileCard(_ref3) {
112
- var userId = _ref3.userId,
113
- cloudId = _ref3.cloudId,
114
- renderUserMentionCard = _ref3.renderUserMentionCard;
113
+ var renderUserProfileCard = function renderUserProfileCard(_ref4) {
114
+ var userId = _ref4.userId,
115
+ cloudId = _ref4.cloudId,
116
+ renderUserMentionCard = _ref4.renderUserMentionCard;
115
117
  if (!renderUserMentionCard) {
116
118
  return false;
117
119
  }
@@ -67,7 +67,7 @@ var AI_STREAMING_TRANSFORMATION_META_KEY = 'isAIStreamingTransformation';
67
67
  var AGENT_MENTION_INACTIVITY_MS = 3000;
68
68
  var MAX_PENDING_TYPED_AGENT_MENTION_FOCUS_DEFERS = 20;
69
69
  var PACKAGE_NAME = "@atlaskit/editor-plugin-mentions";
70
- var PACKAGE_VERSION = "16.1.4";
70
+ var PACKAGE_VERSION = "16.1.5";
71
71
  var setProvider = function setProvider(provider) {
72
72
  return function (state, dispatch) {
73
73
  if (dispatch) {
@@ -0,0 +1,205 @@
1
+ "use strict";
2
+
3
+ var _interopRequireDefault = require("@babel/runtime/helpers/interopRequireDefault");
4
+ Object.defineProperty(exports, "__esModule", {
5
+ value: true
6
+ });
7
+ exports.MentionNodeDataProvider = void 0;
8
+ var _regenerator = _interopRequireDefault(require("@babel/runtime/regenerator"));
9
+ var _asyncToGenerator2 = _interopRequireDefault(require("@babel/runtime/helpers/asyncToGenerator"));
10
+ var _classCallCheck2 = _interopRequireDefault(require("@babel/runtime/helpers/classCallCheck"));
11
+ var _createClass2 = _interopRequireDefault(require("@babel/runtime/helpers/createClass"));
12
+ var _possibleConstructorReturn2 = _interopRequireDefault(require("@babel/runtime/helpers/possibleConstructorReturn"));
13
+ var _getPrototypeOf2 = _interopRequireDefault(require("@babel/runtime/helpers/getPrototypeOf"));
14
+ var _inherits2 = _interopRequireDefault(require("@babel/runtime/helpers/inherits"));
15
+ var _defineProperty2 = _interopRequireDefault(require("@babel/runtime/helpers/defineProperty"));
16
+ var _nodeDataProvider = require("@atlaskit/node-data-provider/node-data-provider");
17
+ function _callSuper(t, o, e) { return o = (0, _getPrototypeOf2.default)(o), (0, _possibleConstructorReturn2.default)(t, _isNativeReflectConstruct() ? Reflect.construct(o, e || [], (0, _getPrototypeOf2.default)(t).constructor) : o.apply(t, e)); }
18
+ function _isNativeReflectConstruct() { try { var t = !Boolean.prototype.valueOf.call(Reflect.construct(Boolean, [], function () {})); } catch (t) {} return (_isNativeReflectConstruct = function _isNativeReflectConstruct() { return !!t; })(); }
19
+ 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; }
20
+ 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; }
21
+ var getAppType = function getAppType(userType) {
22
+ return userType === 'APP' || userType === 'AGENT' ? 'agent' : 'user';
23
+ };
24
+ var enrichMentionNodeData = function enrichMentionNodeData(mention, data) {
25
+ var _data$appType;
26
+ return _objectSpread(_objectSpread({}, data), {}, {
27
+ appType: (_data$appType = data === null || data === void 0 ? void 0 : data.appType) !== null && _data$appType !== void 0 ? _data$appType : getAppType(mention.userType)
28
+ });
29
+ };
30
+ var toMentionNode = function toMentionNode(_ref) {
31
+ var id = _ref.id,
32
+ userType = _ref.userType;
33
+ return {
34
+ attrs: {
35
+ id: id,
36
+ // NodeDataProvider uses an ADF node internally, so normalize the runtime-only value.
37
+ userType: userType === 'AGENT' ? 'APP' : userType
38
+ },
39
+ type: 'mention'
40
+ };
41
+ };
42
+ var isMentionNode = function isMentionNode(node) {
43
+ return node.type === 'mention' && node.attrs !== undefined && 'id' in node.attrs && typeof node.attrs.id === 'string';
44
+ };
45
+
46
+ /**
47
+ * Page-scoped data provider for mention avatars.
48
+ *
49
+ * Products inject their resolution strategy so this package remains independent
50
+ * of Jira and Confluence APIs. Reuse the instance for the lifetime of a renderer
51
+ * or editor rather than creating one for every mention.
52
+ *
53
+ * Deterministic products can supply `resolveMentionNodeData` to return an
54
+ * SSR-safe avatar URL synchronously. It must return the same value on the server
55
+ * and the client's first render to preserve hydration parity.
56
+ *
57
+ * Network-backed products supply `fetchMentionNodeData`. Calls made in the same
58
+ * microtask are combined and account IDs are deduplicated before the fetcher is
59
+ * invoked. A Relay adapter can query `users(accountIds:)`, then map each user's
60
+ * `picture` and app type to a `MentionNodeData` record keyed by account ID. The
61
+ * resolved result is cached by the underlying `NodeDataProvider`.
62
+ */
63
+ var MentionNodeDataProvider = exports.MentionNodeDataProvider = /*#__PURE__*/function (_NodeDataProvider) {
64
+ function MentionNodeDataProvider(fetchMentionNodeData) {
65
+ var _this;
66
+ var resolveMentionNodeData = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : undefined;
67
+ (0, _classCallCheck2.default)(this, MentionNodeDataProvider);
68
+ _this = _callSuper(this, MentionNodeDataProvider);
69
+ (0, _defineProperty2.default)(_this, "name", 'mentionNodeDataProvider');
70
+ (0, _defineProperty2.default)(_this, "queuedFetches", []);
71
+ (0, _defineProperty2.default)(_this, "isFlushScheduled", false);
72
+ _this.fetchMentionNodeData = fetchMentionNodeData;
73
+ _this.resolveMentionNodeData = resolveMentionNodeData;
74
+ return _this;
75
+ }
76
+ (0, _inherits2.default)(MentionNodeDataProvider, _NodeDataProvider);
77
+ return (0, _createClass2.default)(MentionNodeDataProvider, [{
78
+ key: "isNodeSupported",
79
+ value: function isNodeSupported(node) {
80
+ return isMentionNode(node) && node.attrs.userType !== 'SPECIAL';
81
+ }
82
+ }, {
83
+ key: "nodeDataKey",
84
+ value: function nodeDataKey(node) {
85
+ return node.attrs.id;
86
+ }
87
+ }, {
88
+ key: "fetchNodesData",
89
+ value: function () {
90
+ var _fetchNodesData = (0, _asyncToGenerator2.default)( /*#__PURE__*/_regenerator.default.mark(function _callee(nodes) {
91
+ var accountIds, dataByAccountId;
92
+ return _regenerator.default.wrap(function (_context) {
93
+ while (1) switch (_context.prev = _context.next) {
94
+ case 0:
95
+ accountIds = Array.from(new Set(nodes.map(function (_ref2) {
96
+ var attrs = _ref2.attrs;
97
+ return attrs.id;
98
+ })));
99
+ _context.next = 1;
100
+ return this.enqueueFetch(accountIds);
101
+ case 1:
102
+ dataByAccountId = _context.sent;
103
+ return _context.abrupt("return", nodes.map(function (_ref3) {
104
+ var attrs = _ref3.attrs;
105
+ return enrichMentionNodeData(attrs, dataByAccountId[attrs.id]);
106
+ }));
107
+ case 2:
108
+ case "end":
109
+ return _context.stop();
110
+ }
111
+ }, _callee, this);
112
+ }));
113
+ function fetchNodesData(_x) {
114
+ return _fetchNodesData.apply(this, arguments);
115
+ }
116
+ return fetchNodesData;
117
+ }()
118
+ }, {
119
+ key: "getMentionData",
120
+ value: function getMentionData(mention, callback) {
121
+ var _this$resolveMentionN;
122
+ var resolvedData = (_this$resolveMentionN = this.resolveMentionNodeData) === null || _this$resolveMentionN === void 0 ? void 0 : _this$resolveMentionN.call(this, mention);
123
+ if (resolvedData) {
124
+ callback({
125
+ data: enrichMentionNodeData(mention, resolvedData)
126
+ });
127
+ return;
128
+ }
129
+ this.getData(toMentionNode(mention), callback);
130
+ }
131
+ }, {
132
+ key: "getMentionDataFromCache",
133
+ value: function getMentionDataFromCache(mention) {
134
+ var _this$resolveMentionN2, _this$getNodeDataFrom;
135
+ var resolvedData = (_this$resolveMentionN2 = this.resolveMentionNodeData) === null || _this$resolveMentionN2 === void 0 ? void 0 : _this$resolveMentionN2.call(this, mention);
136
+ if (resolvedData) {
137
+ return enrichMentionNodeData(mention, resolvedData);
138
+ }
139
+ var data = (_this$getNodeDataFrom = this.getNodeDataFromCache(toMentionNode(mention))) === null || _this$getNodeDataFrom === void 0 ? void 0 : _this$getNodeDataFrom.data;
140
+ return data ? enrichMentionNodeData(mention, data) : undefined;
141
+ }
142
+ }, {
143
+ key: "enqueueFetch",
144
+ value: function enqueueFetch(accountIds) {
145
+ var _this2 = this;
146
+ var result = new Promise(function (resolve, reject) {
147
+ _this2.queuedFetches.push({
148
+ accountIds: accountIds,
149
+ reject: reject,
150
+ resolve: resolve
151
+ });
152
+ });
153
+ if (!this.isFlushScheduled) {
154
+ this.isFlushScheduled = true;
155
+ void Promise.resolve().then(function () {
156
+ return _this2.flushFetches();
157
+ });
158
+ }
159
+ return result;
160
+ }
161
+ }, {
162
+ key: "flushFetches",
163
+ value: function () {
164
+ var _flushFetches = (0, _asyncToGenerator2.default)( /*#__PURE__*/_regenerator.default.mark(function _callee2() {
165
+ var queuedFetches, accountIds, data, _t;
166
+ return _regenerator.default.wrap(function (_context2) {
167
+ while (1) switch (_context2.prev = _context2.next) {
168
+ case 0:
169
+ this.isFlushScheduled = false;
170
+ queuedFetches = this.queuedFetches;
171
+ this.queuedFetches = [];
172
+ accountIds = Array.from(new Set(queuedFetches.flatMap(function (request) {
173
+ return request.accountIds;
174
+ })));
175
+ _context2.prev = 1;
176
+ _context2.next = 2;
177
+ return this.fetchMentionNodeData(accountIds);
178
+ case 2:
179
+ data = _context2.sent;
180
+ queuedFetches.forEach(function (_ref4) {
181
+ var resolve = _ref4.resolve;
182
+ return resolve(data);
183
+ });
184
+ _context2.next = 4;
185
+ break;
186
+ case 3:
187
+ _context2.prev = 3;
188
+ _t = _context2["catch"](1);
189
+ queuedFetches.forEach(function (_ref5) {
190
+ var reject = _ref5.reject;
191
+ return reject(_t);
192
+ });
193
+ case 4:
194
+ case "end":
195
+ return _context2.stop();
196
+ }
197
+ }, _callee2, this, [[1, 3]]);
198
+ }));
199
+ function flushFetches() {
200
+ return _flushFetches.apply(this, arguments);
201
+ }
202
+ return flushFetches;
203
+ }()
204
+ }]);
205
+ }(_nodeDataProvider.NodeDataProvider);
@@ -0,0 +1,3 @@
1
+ /* eslint-disable @atlaskit/editor/no-re-export */
2
+
3
+ export { MentionNodeDataProvider } from '../providers/mention-node-data-provider';
@@ -0,0 +1,71 @@
1
+ import { bind } from 'bind-event-listener';
2
+ const avatarImageClassName = 'editor-mention-avatar-image';
3
+ const agentAvatarClassName = 'editor-mention-avatar-agent';
4
+ const fallbackAvatarClassName = 'editor-mention-avatar-fallback';
5
+ const avatarSize = 16;
6
+ /**
7
+ * Populates the fixed-size avatar slot owned by the vanilla ProseMirror NodeView.
8
+ * No React root or editor portal is created for individual mention nodes.
9
+ */
10
+ export const mentionAvatarRenderer = ({
11
+ container
12
+ }) => {
13
+ let image;
14
+ let fallback;
15
+ let unbindImageError;
16
+ const removeImage = () => {
17
+ var _unbindImageError, _image;
18
+ (_unbindImageError = unbindImageError) === null || _unbindImageError === void 0 ? void 0 : _unbindImageError();
19
+ unbindImageError = undefined;
20
+ (_image = image) === null || _image === void 0 ? void 0 : _image.remove();
21
+ image = undefined;
22
+ };
23
+ const removeFallback = () => {
24
+ var _fallback;
25
+ (_fallback = fallback) === null || _fallback === void 0 ? void 0 : _fallback.remove();
26
+ fallback = undefined;
27
+ container.classList.remove(fallbackAvatarClassName);
28
+ };
29
+ const showFallback = () => {
30
+ removeImage();
31
+ removeFallback();
32
+ fallback = container.ownerDocument.createTextNode('@');
33
+ container.appendChild(fallback);
34
+ container.classList.add(fallbackAvatarClassName);
35
+ };
36
+ const destroy = () => {
37
+ removeImage();
38
+ removeFallback();
39
+ };
40
+ return {
41
+ destroy,
42
+ render: ({
43
+ appType,
44
+ avatarUrl,
45
+ isAvatarImagePreShaped
46
+ }) => {
47
+ container.classList.toggle(agentAvatarClassName, !isAvatarImagePreShaped && appType === 'agent');
48
+ removeFallback();
49
+ if (!avatarUrl) {
50
+ removeImage();
51
+ return;
52
+ }
53
+ if (!image) {
54
+ image = container.ownerDocument.createElement('img');
55
+ image.alt = '';
56
+ image.className = avatarImageClassName;
57
+ image.decoding = 'async';
58
+ image.draggable = false;
59
+ image.height = avatarSize;
60
+ image.loading = 'lazy';
61
+ image.width = avatarSize;
62
+ unbindImageError = bind(image, {
63
+ type: 'error',
64
+ listener: showFallback
65
+ });
66
+ container.appendChild(image);
67
+ }
68
+ image.src = avatarUrl;
69
+ }
70
+ };
71
+ };