@atlaskit/mention 27.6.0 → 27.7.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/CHANGELOG.md CHANGED
@@ -1,5 +1,19 @@
1
1
  # @atlaskit/mention
2
2
 
3
+ ## 27.7.0
4
+
5
+ ### Minor Changes
6
+
7
+ - [`d6596dc895420`](https://bitbucket.org/atlassian/atlassian-frontend-monorepo/commits/d6596dc895420) -
8
+ Show a loading shimmer in the mention typeahead Agents section while the (slower) agent source
9
+ resolves. The Rovo chat mention provider now emits a non-selectable loading placeholder in the
10
+ agents slot until agents arrive (gated by rovo_chat_agent_selection); @atlaskit/mention renders it
11
+ as a skeleton row, and the editor mention plugin guards it from selection/analytics.
12
+
13
+ ### Patch Changes
14
+
15
+ - Updated dependencies
16
+
3
17
  ## 27.6.0
4
18
 
5
19
  ### Minor Changes
@@ -52,6 +52,9 @@
52
52
  {
53
53
  "path": "../../../react-compiler/react-compiler-gating/afm-cc/tsconfig.json"
54
54
  },
55
+ {
56
+ "path": "../../../design-system/skeleton/afm-cc/tsconfig.json"
57
+ },
55
58
  {
56
59
  "path": "../../../design-system/tag/afm-cc/tsconfig.json"
57
60
  },
@@ -52,6 +52,9 @@
52
52
  {
53
53
  "path": "../../../react-compiler/react-compiler-gating/afm-products/tsconfig.json"
54
54
  },
55
+ {
56
+ "path": "../../../design-system/skeleton/afm-products/tsconfig.json"
57
+ },
55
58
  {
56
59
  "path": "../../../design-system/tag/afm-products/tsconfig.json"
57
60
  },
@@ -469,6 +469,10 @@ var MentionResource = exports.MentionResource = /*#__PURE__*/function (_Abstract
469
469
  key: "transformServiceResponse",
470
470
  value: function transformServiceResponse(result, query) {
471
471
  var mentions = result.mentions.map(function (mention) {
472
+ // Loading placeholders carry none of these fields and pass through untouched.
473
+ if (mention.isPlaceholder) {
474
+ return mention;
475
+ }
472
476
  var lozenge;
473
477
  if ((0, _types.isAppMention)(mention)) {
474
478
  lozenge = mention.userType;
@@ -0,0 +1,50 @@
1
+ "use strict";
2
+
3
+ var _interopRequireDefault = require("@babel/runtime/helpers/interopRequireDefault");
4
+ Object.defineProperty(exports, "__esModule", {
5
+ value: true
6
+ });
7
+ exports.default = MentionItemPlaceholder;
8
+ var _react = _interopRequireDefault(require("react"));
9
+ var _reactIntl = require("react-intl");
10
+ var _skeleton = _interopRequireDefault(require("@atlaskit/skeleton"));
11
+ var _i18n = require("../i18n");
12
+ var _styles = require("./styles");
13
+ /**
14
+ * Non-interactive skeleton row rendered for a placeholder mention
15
+ * (`mention.isPlaceholder`). Mirrors the avatar + name layout of a real
16
+ * row so the list doesn't jump when the real items swap in, and exposes
17
+ * an accessible loading label. Deliberately wires no selection/hover
18
+ * handlers — it must not be clickable.
19
+ *
20
+ * Lives in its own module (lazy-loaded by `MentionItem`) so the
21
+ * `@atlaskit/skeleton` dependency only enters the bundle when a
22
+ * placeholder is actually rendered, not for every `@atlaskit/mention`
23
+ * consumer.
24
+ */
25
+ function MentionItemPlaceholder(_ref) {
26
+ var height = _ref.height,
27
+ forwardedRef = _ref.forwardedRef,
28
+ id = _ref.id;
29
+ var _useIntl = (0, _reactIntl.useIntl)(),
30
+ formatMessage = _useIntl.formatMessage;
31
+ var label = formatMessage(_i18n.messages.loadingPlaceholder);
32
+ return /*#__PURE__*/_react.default.createElement(_styles.MentionItemStyle, {
33
+ height: height,
34
+ "data-mention-item": true,
35
+ "data-testid": "mention-item-".concat(id),
36
+ "data-mention-id": id,
37
+ ref: forwardedRef,
38
+ role: "status",
39
+ "aria-label": label
40
+ }, /*#__PURE__*/_react.default.createElement(_styles.RowStyle, null, /*#__PURE__*/_react.default.createElement(_styles.AvatarStyle, null, /*#__PURE__*/_react.default.createElement(_styles.AvatarSkeletonWrapper, null, /*#__PURE__*/_react.default.createElement(_skeleton.default, {
41
+ width: 32,
42
+ height: 32,
43
+ borderRadius: "var(--ds-radius-full, 9999px)",
44
+ isShimmering: true
45
+ }))), /*#__PURE__*/_react.default.createElement(_styles.NameSectionStyle, null, /*#__PURE__*/_react.default.createElement(_skeleton.default, {
46
+ width: 140,
47
+ height: 12,
48
+ isShimmering: true
49
+ }))));
50
+ }
@@ -42,6 +42,15 @@ var _MessagesIntlProvider = _interopRequireDefault(require("../MessagesIntlProvi
42
42
  var _MentionAvatar = require("../MentionAvatar");
43
43
  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)); }
44
44
  function _isNativeReflectConstruct() { try { var t = !Boolean.prototype.valueOf.call(Reflect.construct(Boolean, [], function () {})); } catch (t) {} return (_isNativeReflectConstruct = function _isNativeReflectConstruct() { return !!t; })(); }
45
+ 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" != (0, _typeof2.default)(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); }
46
+ // Lazy-loaded so `@atlaskit/skeleton` (only needed for the loading
47
+ // placeholder) doesn't enter the bundle for every `@atlaskit/mention`
48
+ // consumer — only when an `isPlaceholder` mention is actually rendered.
49
+ var MentionItemPlaceholder = /*#__PURE__*/_react.default.lazy(function () {
50
+ return Promise.resolve().then(function () {
51
+ return _interopRequireWildcard(require( /* webpackChunkName: "@atlaskit-internal_mention-item-placeholder" */'./MentionItemPlaceholder'));
52
+ });
53
+ });
45
54
  var lozengeAppearanceToTagColor = {
46
55
  default: 'standard',
47
56
  success: 'lime',
@@ -135,6 +144,18 @@ var MentionItem = exports.default = /*#__PURE__*/function (_React$PureComponent)
135
144
  lozenge = mention.lozenge,
136
145
  accessLevel = mention.accessLevel,
137
146
  isXProductUser = mention.isXProductUser;
147
+ if (mention.isPlaceholder) {
148
+ return /*#__PURE__*/_react.default.createElement(_MessagesIntlProvider.default, null, /*#__PURE__*/_react.default.createElement(_react.default.Suspense, {
149
+ fallback: /*#__PURE__*/_react.default.createElement(_styles.MentionItemStyle, {
150
+ height: height,
151
+ "aria-hidden": true
152
+ })
153
+ }, /*#__PURE__*/_react.default.createElement(MentionItemPlaceholder, {
154
+ height: height,
155
+ forwardedRef: forwardedRef,
156
+ id: id
157
+ })));
158
+ }
138
159
  var _ref = presence || {},
139
160
  time = _ref.time;
140
161
  var restricted = (0, _types.isRestricted)(accessLevel);
@@ -4,7 +4,7 @@ var _interopRequireDefault = require("@babel/runtime/helpers/interopRequireDefau
4
4
  Object.defineProperty(exports, "__esModule", {
5
5
  value: true
6
6
  });
7
- exports.TimeStyle = exports.RowStyle = exports.NameSectionStyle = exports.MentionItemStyle = exports.MENTION_ITEM_HEIGHT_REFRESHED = exports.MENTION_ITEM_HEIGHT = exports.InfoSectionStyle = exports.FullNameStyle = exports.AvatarStyle = exports.AccessSectionStyle = void 0;
7
+ exports.TimeStyle = exports.RowStyle = exports.NameSectionStyle = exports.MentionItemStyle = exports.MENTION_ITEM_HEIGHT_REFRESHED = exports.MENTION_ITEM_HEIGHT = exports.InfoSectionStyle = exports.FullNameStyle = exports.AvatarStyle = exports.AvatarSkeletonWrapper = exports.AccessSectionStyle = void 0;
8
8
  var _styled = _interopRequireDefault(require("@emotion/styled"));
9
9
  var _platformFeatureFlags = require("@atlaskit/platform-feature-flags");
10
10
  // eslint-disable-next-line @atlaskit/ui-styling-standard/use-compiled -- Ignored via go/DSP-18766
@@ -33,6 +33,21 @@ var AvatarStyle = exports.AvatarStyle = _styled.default.span(function (props) {
33
33
  };
34
34
  });
35
35
 
36
+ /**
37
+ * Footprint of the loading placeholder avatar. Matches the real
38
+ * `@atlaskit/avatar` `size="medium"` layout: a 32px circle (the image)
39
+ * centered inside a 36px wrapper, so the loading row and the resolved row
40
+ * line up identically and the row doesn't shift on swap.
41
+ */
42
+ // eslint-disable-next-line @atlaskit/ui-styling-standard/no-styled, @atlaskit/ui-styling-standard/no-exported-styles -- Ignored via go/DSP-18766
43
+ var AvatarSkeletonWrapper = exports.AvatarSkeletonWrapper = _styled.default.div({
44
+ display: 'flex',
45
+ alignItems: 'center',
46
+ justifyContent: 'center',
47
+ width: '36px',
48
+ height: '36px'
49
+ });
50
+
36
51
  // eslint-disable-next-line @atlaskit/ui-styling-standard/no-styled, @atlaskit/ui-styling-standard/no-exported-styles, @atlaskit/ui-styling-standard/no-dynamic-styles -- Ignored via go/DSP-18766
37
52
  var NameSectionStyle = exports.NameSectionStyle = _styled.default.div(function (props) {
38
53
  return {
@@ -65,5 +65,10 @@ var messages = exports.messages = (0, _reactIntl.defineMessages)({
65
65
  id: 'fabric.elements.mentions.xproduct.mention.description',
66
66
  defaultMessage: 'Needs access to Confluence',
67
67
  description: 'Description for a x-product mention item in the mention list in Confluence'
68
+ },
69
+ loadingPlaceholder: {
70
+ id: 'fabric.elements.mentions.loading.placeholder',
71
+ defaultMessage: 'Loading',
72
+ description: 'Accessible label for a loading placeholder row shown in the mention list while a slower mention source (such as agents) is still loading.'
68
73
  }
69
74
  });
package/dist/cjs/types.js CHANGED
@@ -26,6 +26,23 @@ exports.isTeamMention = isTeamMention;
26
26
  * type so the config callback and the provider method share the same input
27
27
  * surface, and so callers do not have to fabricate fields they do not have.
28
28
  */
29
+ /**
30
+ * Real-mention fields forbidden on a placeholder. Declaring them as `never`
31
+ * (rather than omitting them) keeps `mention.name` etc. readable on the
32
+ * {@link MentionDescription} union — so the hundreds of consumers that never
33
+ * encounter a placeholder are unaffected — while still making illegal
34
+ * combinations like `{ isPlaceholder: true, name: 'Real User' }` a compile
35
+ * error.
36
+ */
37
+ /**
38
+ * Non-selectable loading placeholder surfaced in the mention list while a
39
+ * slower mention source (e.g. agents) resolves. Its own member of the
40
+ * {@link MentionDescription} discriminated union (discriminated on
41
+ * `isPlaceholder`).
42
+ *
43
+ * `id` must be unique per placeholder — the typeahead keys rows by id — so
44
+ * multiple placeholders can be rendered at once.
45
+ */
29
46
  // data is returned from team search service
30
47
  var MentionType = exports.MentionType = /*#__PURE__*/function (MentionType) {
31
48
  MentionType[MentionType["SELF"] = 0] = "SELF";
@@ -12,7 +12,7 @@ var _types = require("../types");
12
12
  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; }
13
13
  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; }
14
14
  var packageName = "@atlaskit/mention";
15
- var packageVersion = "27.5.2";
15
+ var packageVersion = "27.6.0";
16
16
  var SLI_EVENT_TYPE = exports.SLI_EVENT_TYPE = 'sli';
17
17
  var SMART_EVENT_TYPE = exports.SMART_EVENT_TYPE = 'smart';
18
18
  var fireAnalyticsMentionTypeaheadEvent = exports.fireAnalyticsMentionTypeaheadEvent = function fireAnalyticsMentionTypeaheadEvent(props) {
@@ -319,6 +319,10 @@ export class MentionResource extends AbstractMentionResource {
319
319
  }
320
320
  transformServiceResponse(result, query) {
321
321
  const mentions = result.mentions.map(mention => {
322
+ // Loading placeholders carry none of these fields and pass through untouched.
323
+ if (mention.isPlaceholder) {
324
+ return mention;
325
+ }
322
326
  let lozenge;
323
327
  if (isAppMention(mention)) {
324
328
  lozenge = mention.userType;
@@ -0,0 +1,45 @@
1
+ import React from 'react';
2
+ import { useIntl } from 'react-intl';
3
+ import Skeleton from '@atlaskit/skeleton';
4
+ import { messages } from '../i18n';
5
+ import { AvatarSkeletonWrapper, AvatarStyle, MentionItemStyle, NameSectionStyle, RowStyle } from './styles';
6
+ /**
7
+ * Non-interactive skeleton row rendered for a placeholder mention
8
+ * (`mention.isPlaceholder`). Mirrors the avatar + name layout of a real
9
+ * row so the list doesn't jump when the real items swap in, and exposes
10
+ * an accessible loading label. Deliberately wires no selection/hover
11
+ * handlers — it must not be clickable.
12
+ *
13
+ * Lives in its own module (lazy-loaded by `MentionItem`) so the
14
+ * `@atlaskit/skeleton` dependency only enters the bundle when a
15
+ * placeholder is actually rendered, not for every `@atlaskit/mention`
16
+ * consumer.
17
+ */
18
+ export default function MentionItemPlaceholder({
19
+ height,
20
+ forwardedRef,
21
+ id
22
+ }) {
23
+ const {
24
+ formatMessage
25
+ } = useIntl();
26
+ const label = formatMessage(messages.loadingPlaceholder);
27
+ return /*#__PURE__*/React.createElement(MentionItemStyle, {
28
+ height: height,
29
+ "data-mention-item": true,
30
+ "data-testid": `mention-item-${id}`,
31
+ "data-mention-id": id,
32
+ ref: forwardedRef,
33
+ role: "status",
34
+ "aria-label": label
35
+ }, /*#__PURE__*/React.createElement(RowStyle, null, /*#__PURE__*/React.createElement(AvatarStyle, null, /*#__PURE__*/React.createElement(AvatarSkeletonWrapper, null, /*#__PURE__*/React.createElement(Skeleton, {
36
+ width: 32,
37
+ height: 32,
38
+ borderRadius: "var(--ds-radius-full, 9999px)",
39
+ isShimmering: true
40
+ }))), /*#__PURE__*/React.createElement(NameSectionStyle, null, /*#__PURE__*/React.createElement(Skeleton, {
41
+ width: 140,
42
+ height: 12,
43
+ isShimmering: true
44
+ }))));
45
+ }
@@ -15,6 +15,11 @@ import { renderHighlight } from './MentionHighlightHelpers';
15
15
  import MentionDescriptionByline from '../MentionDescriptionByline';
16
16
  import MessagesIntlProvider from '../MessagesIntlProvider';
17
17
  import { MentionAvatar } from '../MentionAvatar';
18
+
19
+ // Lazy-loaded so `@atlaskit/skeleton` (only needed for the loading
20
+ // placeholder) doesn't enter the bundle for every `@atlaskit/mention`
21
+ // consumer — only when an `isPlaceholder` mention is actually rendered.
22
+ const MentionItemPlaceholder = /*#__PURE__*/React.lazy(() => import( /* webpackChunkName: "@atlaskit-internal_mention-item-placeholder" */'./MentionItemPlaceholder'));
18
23
  export { MENTION_ITEM_HEIGHT, MENTION_ITEM_HEIGHT_REFRESHED } from './styles';
19
24
  const lozengeAppearanceToTagColor = {
20
25
  default: 'standard',
@@ -107,6 +112,18 @@ export default class MentionItem extends React.PureComponent {
107
112
  accessLevel,
108
113
  isXProductUser
109
114
  } = mention;
115
+ if (mention.isPlaceholder) {
116
+ return /*#__PURE__*/React.createElement(MessagesIntlProvider, null, /*#__PURE__*/React.createElement(React.Suspense, {
117
+ fallback: /*#__PURE__*/React.createElement(MentionItemStyle, {
118
+ height: height,
119
+ "aria-hidden": true
120
+ })
121
+ }, /*#__PURE__*/React.createElement(MentionItemPlaceholder, {
122
+ height: height,
123
+ forwardedRef: forwardedRef,
124
+ id: id
125
+ })));
126
+ }
110
127
  const {
111
128
  time
112
129
  } = presence || {};
@@ -23,6 +23,21 @@ export const AvatarStyle = styled.span(props => ({
23
23
  opacity: props.restricted ? '0.5' : 'inherit'
24
24
  }));
25
25
 
26
+ /**
27
+ * Footprint of the loading placeholder avatar. Matches the real
28
+ * `@atlaskit/avatar` `size="medium"` layout: a 32px circle (the image)
29
+ * centered inside a 36px wrapper, so the loading row and the resolved row
30
+ * line up identically and the row doesn't shift on swap.
31
+ */
32
+ // eslint-disable-next-line @atlaskit/ui-styling-standard/no-styled, @atlaskit/ui-styling-standard/no-exported-styles -- Ignored via go/DSP-18766
33
+ export const AvatarSkeletonWrapper = styled.div({
34
+ display: 'flex',
35
+ alignItems: 'center',
36
+ justifyContent: 'center',
37
+ width: '36px',
38
+ height: '36px'
39
+ });
40
+
26
41
  // eslint-disable-next-line @atlaskit/ui-styling-standard/no-styled, @atlaskit/ui-styling-standard/no-exported-styles, @atlaskit/ui-styling-standard/no-dynamic-styles -- Ignored via go/DSP-18766
27
42
  export const NameSectionStyle = styled.div(props => ({
28
43
  flex: 1,
@@ -59,5 +59,10 @@ export const messages = defineMessages({
59
59
  id: 'fabric.elements.mentions.xproduct.mention.description',
60
60
  defaultMessage: 'Needs access to Confluence',
61
61
  description: 'Description for a x-product mention item in the mention list in Confluence'
62
+ },
63
+ loadingPlaceholder: {
64
+ id: 'fabric.elements.mentions.loading.placeholder',
65
+ defaultMessage: 'Loading',
66
+ description: 'Accessible label for a loading placeholder row shown in the mention list while a slower mention source (such as agents) is still loading.'
62
67
  }
63
68
  });
@@ -17,6 +17,25 @@
17
17
  * surface, and so callers do not have to fabricate fields they do not have.
18
18
  */
19
19
 
20
+ /**
21
+ * Real-mention fields forbidden on a placeholder. Declaring them as `never`
22
+ * (rather than omitting them) keeps `mention.name` etc. readable on the
23
+ * {@link MentionDescription} union — so the hundreds of consumers that never
24
+ * encounter a placeholder are unaffected — while still making illegal
25
+ * combinations like `{ isPlaceholder: true, name: 'Real User' }` a compile
26
+ * error.
27
+ */
28
+
29
+ /**
30
+ * Non-selectable loading placeholder surfaced in the mention list while a
31
+ * slower mention source (e.g. agents) resolves. Its own member of the
32
+ * {@link MentionDescription} discriminated union (discriminated on
33
+ * `isPlaceholder`).
34
+ *
35
+ * `id` must be unique per placeholder — the typeahead keys rows by id — so
36
+ * multiple placeholders can be rendered at once.
37
+ */
38
+
20
39
  // data is returned from team search service
21
40
 
22
41
  export let MentionType = /*#__PURE__*/function (MentionType) {
@@ -2,7 +2,7 @@ import { OPERATIONAL_EVENT_TYPE, UI_EVENT_TYPE } from '@atlaskit/analytics-gas-t
2
2
  import { ELEMENTS_CHANNEL } from '../_constants';
3
3
  import { ComponentNames, isSpecialMentionText } from '../types';
4
4
  const packageName = "@atlaskit/mention";
5
- const packageVersion = "27.5.2";
5
+ const packageVersion = "27.6.0";
6
6
  export const SLI_EVENT_TYPE = 'sli';
7
7
  export const SMART_EVENT_TYPE = 'smart';
8
8
  export const fireAnalyticsMentionTypeaheadEvent = props => (action, duration, userIds = [], query) => {
@@ -462,6 +462,10 @@ export var MentionResource = /*#__PURE__*/function (_AbstractMentionResou) {
462
462
  key: "transformServiceResponse",
463
463
  value: function transformServiceResponse(result, query) {
464
464
  var mentions = result.mentions.map(function (mention) {
465
+ // Loading placeholders carry none of these fields and pass through untouched.
466
+ if (mention.isPlaceholder) {
467
+ return mention;
468
+ }
465
469
  var lozenge;
466
470
  if (isAppMention(mention)) {
467
471
  lozenge = mention.userType;
@@ -0,0 +1,43 @@
1
+ import React from 'react';
2
+ import { useIntl } from 'react-intl';
3
+ import Skeleton from '@atlaskit/skeleton';
4
+ import { messages } from '../i18n';
5
+ import { AvatarSkeletonWrapper, AvatarStyle, MentionItemStyle, NameSectionStyle, RowStyle } from './styles';
6
+ /**
7
+ * Non-interactive skeleton row rendered for a placeholder mention
8
+ * (`mention.isPlaceholder`). Mirrors the avatar + name layout of a real
9
+ * row so the list doesn't jump when the real items swap in, and exposes
10
+ * an accessible loading label. Deliberately wires no selection/hover
11
+ * handlers — it must not be clickable.
12
+ *
13
+ * Lives in its own module (lazy-loaded by `MentionItem`) so the
14
+ * `@atlaskit/skeleton` dependency only enters the bundle when a
15
+ * placeholder is actually rendered, not for every `@atlaskit/mention`
16
+ * consumer.
17
+ */
18
+ export default function MentionItemPlaceholder(_ref) {
19
+ var height = _ref.height,
20
+ forwardedRef = _ref.forwardedRef,
21
+ id = _ref.id;
22
+ var _useIntl = useIntl(),
23
+ formatMessage = _useIntl.formatMessage;
24
+ var label = formatMessage(messages.loadingPlaceholder);
25
+ return /*#__PURE__*/React.createElement(MentionItemStyle, {
26
+ height: height,
27
+ "data-mention-item": true,
28
+ "data-testid": "mention-item-".concat(id),
29
+ "data-mention-id": id,
30
+ ref: forwardedRef,
31
+ role: "status",
32
+ "aria-label": label
33
+ }, /*#__PURE__*/React.createElement(RowStyle, null, /*#__PURE__*/React.createElement(AvatarStyle, null, /*#__PURE__*/React.createElement(AvatarSkeletonWrapper, null, /*#__PURE__*/React.createElement(Skeleton, {
34
+ width: 32,
35
+ height: 32,
36
+ borderRadius: "var(--ds-radius-full, 9999px)",
37
+ isShimmering: true
38
+ }))), /*#__PURE__*/React.createElement(NameSectionStyle, null, /*#__PURE__*/React.createElement(Skeleton, {
39
+ width: 140,
40
+ height: 12,
41
+ isShimmering: true
42
+ }))));
43
+ }
@@ -23,6 +23,13 @@ import { renderHighlight } from './MentionHighlightHelpers';
23
23
  import MentionDescriptionByline from '../MentionDescriptionByline';
24
24
  import MessagesIntlProvider from '../MessagesIntlProvider';
25
25
  import { MentionAvatar } from '../MentionAvatar';
26
+
27
+ // Lazy-loaded so `@atlaskit/skeleton` (only needed for the loading
28
+ // placeholder) doesn't enter the bundle for every `@atlaskit/mention`
29
+ // consumer — only when an `isPlaceholder` mention is actually rendered.
30
+ var MentionItemPlaceholder = /*#__PURE__*/React.lazy(function () {
31
+ return import( /* webpackChunkName: "@atlaskit-internal_mention-item-placeholder" */'./MentionItemPlaceholder');
32
+ });
26
33
  export { MENTION_ITEM_HEIGHT, MENTION_ITEM_HEIGHT_REFRESHED } from './styles';
27
34
  var lozengeAppearanceToTagColor = {
28
35
  default: 'standard',
@@ -117,6 +124,18 @@ var MentionItem = /*#__PURE__*/function (_React$PureComponent) {
117
124
  lozenge = mention.lozenge,
118
125
  accessLevel = mention.accessLevel,
119
126
  isXProductUser = mention.isXProductUser;
127
+ if (mention.isPlaceholder) {
128
+ return /*#__PURE__*/React.createElement(MessagesIntlProvider, null, /*#__PURE__*/React.createElement(React.Suspense, {
129
+ fallback: /*#__PURE__*/React.createElement(MentionItemStyle, {
130
+ height: height,
131
+ "aria-hidden": true
132
+ })
133
+ }, /*#__PURE__*/React.createElement(MentionItemPlaceholder, {
134
+ height: height,
135
+ forwardedRef: forwardedRef,
136
+ id: id
137
+ })));
138
+ }
120
139
  var _ref = presence || {},
121
140
  time = _ref.time;
122
141
  var restricted = isRestricted(accessLevel);
@@ -25,6 +25,21 @@ export var AvatarStyle = styled.span(function (props) {
25
25
  };
26
26
  });
27
27
 
28
+ /**
29
+ * Footprint of the loading placeholder avatar. Matches the real
30
+ * `@atlaskit/avatar` `size="medium"` layout: a 32px circle (the image)
31
+ * centered inside a 36px wrapper, so the loading row and the resolved row
32
+ * line up identically and the row doesn't shift on swap.
33
+ */
34
+ // eslint-disable-next-line @atlaskit/ui-styling-standard/no-styled, @atlaskit/ui-styling-standard/no-exported-styles -- Ignored via go/DSP-18766
35
+ export var AvatarSkeletonWrapper = styled.div({
36
+ display: 'flex',
37
+ alignItems: 'center',
38
+ justifyContent: 'center',
39
+ width: '36px',
40
+ height: '36px'
41
+ });
42
+
28
43
  // eslint-disable-next-line @atlaskit/ui-styling-standard/no-styled, @atlaskit/ui-styling-standard/no-exported-styles, @atlaskit/ui-styling-standard/no-dynamic-styles -- Ignored via go/DSP-18766
29
44
  export var NameSectionStyle = styled.div(function (props) {
30
45
  return {
@@ -59,5 +59,10 @@ export var messages = defineMessages({
59
59
  id: 'fabric.elements.mentions.xproduct.mention.description',
60
60
  defaultMessage: 'Needs access to Confluence',
61
61
  description: 'Description for a x-product mention item in the mention list in Confluence'
62
+ },
63
+ loadingPlaceholder: {
64
+ id: 'fabric.elements.mentions.loading.placeholder',
65
+ defaultMessage: 'Loading',
66
+ description: 'Accessible label for a loading placeholder row shown in the mention list while a slower mention source (such as agents) is still loading.'
62
67
  }
63
68
  });
package/dist/esm/types.js CHANGED
@@ -17,6 +17,25 @@
17
17
  * surface, and so callers do not have to fabricate fields they do not have.
18
18
  */
19
19
 
20
+ /**
21
+ * Real-mention fields forbidden on a placeholder. Declaring them as `never`
22
+ * (rather than omitting them) keeps `mention.name` etc. readable on the
23
+ * {@link MentionDescription} union — so the hundreds of consumers that never
24
+ * encounter a placeholder are unaffected — while still making illegal
25
+ * combinations like `{ isPlaceholder: true, name: 'Real User' }` a compile
26
+ * error.
27
+ */
28
+
29
+ /**
30
+ * Non-selectable loading placeholder surfaced in the mention list while a
31
+ * slower mention source (e.g. agents) resolves. Its own member of the
32
+ * {@link MentionDescription} discriminated union (discriminated on
33
+ * `isPlaceholder`).
34
+ *
35
+ * `id` must be unique per placeholder — the typeahead keys rows by id — so
36
+ * multiple placeholders can be rendered at once.
37
+ */
38
+
20
39
  // data is returned from team search service
21
40
 
22
41
  export var MentionType = /*#__PURE__*/function (MentionType) {
@@ -5,7 +5,7 @@ import { OPERATIONAL_EVENT_TYPE, UI_EVENT_TYPE } from '@atlaskit/analytics-gas-t
5
5
  import { ELEMENTS_CHANNEL } from '../_constants';
6
6
  import { ComponentNames, isSpecialMentionText } from '../types';
7
7
  var packageName = "@atlaskit/mention";
8
- var packageVersion = "27.5.2";
8
+ var packageVersion = "27.6.0";
9
9
  export var SLI_EVENT_TYPE = 'sli';
10
10
  export var SMART_EVENT_TYPE = 'smart';
11
11
  export var fireAnalyticsMentionTypeaheadEvent = function fireAnalyticsMentionTypeaheadEvent(props) {
@@ -0,0 +1,20 @@
1
+ import React from 'react';
2
+ type MentionItemPlaceholderProps = {
3
+ forwardedRef?: React.Ref<HTMLDivElement>;
4
+ height?: number;
5
+ id: string;
6
+ };
7
+ /**
8
+ * Non-interactive skeleton row rendered for a placeholder mention
9
+ * (`mention.isPlaceholder`). Mirrors the avatar + name layout of a real
10
+ * row so the list doesn't jump when the real items swap in, and exposes
11
+ * an accessible loading label. Deliberately wires no selection/hover
12
+ * handlers — it must not be clickable.
13
+ *
14
+ * Lives in its own module (lazy-loaded by `MentionItem`) so the
15
+ * `@atlaskit/skeleton` dependency only enters the bundle when a
16
+ * placeholder is actually rendered, not for every `@atlaskit/mention`
17
+ * consumer.
18
+ */
19
+ export default function MentionItemPlaceholder({ height, forwardedRef, id, }: MentionItemPlaceholderProps): React.JSX.Element;
20
+ export {};
@@ -22,6 +22,16 @@ export declare const AvatarStyle: StyledComponent<{
22
22
  as?: React.ElementType;
23
23
  theme?: Theme;
24
24
  } & AvatarSectionStyleProps, DetailedHTMLProps<HTMLAttributes<HTMLSpanElement>, HTMLSpanElement>, {}>;
25
+ /**
26
+ * Footprint of the loading placeholder avatar. Matches the real
27
+ * `@atlaskit/avatar` `size="medium"` layout: a 32px circle (the image)
28
+ * centered inside a 36px wrapper, so the loading row and the resolved row
29
+ * line up identically and the row doesn't shift on swap.
30
+ */
31
+ export declare const AvatarSkeletonWrapper: StyledComponent<{
32
+ as?: React.ElementType;
33
+ theme?: Theme;
34
+ }, DetailedHTMLProps<HTMLAttributes<HTMLDivElement>, HTMLDivElement>, {}>;
25
35
  export declare const NameSectionStyle: StyledComponent<{
26
36
  as?: React.ElementType;
27
37
  theme?: Theme;
@@ -1,62 +1,67 @@
1
1
  export declare const messages: {
2
- unknownUserError: {
3
- id: string;
2
+ defaultAdvisedAction: {
4
3
  defaultMessage: string;
5
4
  description: string;
6
- };
7
- noAccessWarning: {
8
5
  id: string;
9
- defaultMessage: string;
10
- description: string;
11
6
  };
12
- noAccessLabel: {
13
- id: string;
7
+ defaultHeadline: {
14
8
  defaultMessage: string;
15
9
  description: string;
16
- };
17
- defaultHeadline: {
18
10
  id: string;
11
+ };
12
+ differentText: {
19
13
  defaultMessage: string;
20
14
  description: string;
21
- };
22
- defaultAdvisedAction: {
23
15
  id: string;
16
+ };
17
+ loadingPlaceholder: {
24
18
  defaultMessage: string;
25
19
  description: string;
20
+ id: string;
26
21
  };
27
22
  loginAgain: {
28
- id: string;
29
23
  defaultMessage: string;
30
24
  description: string;
31
- };
32
- differentText: {
33
25
  id: string;
34
- defaultMessage: string;
35
- description: string;
36
26
  };
37
27
  memberCountWithoutYou: {
38
- id: string;
39
28
  defaultMessage: string;
40
29
  description: string;
30
+ id: string;
41
31
  };
42
32
  memberCountWithYou: {
33
+ defaultMessage: string;
34
+ description: string;
43
35
  id: string;
36
+ };
37
+ noAccessLabel: {
44
38
  defaultMessage: string;
45
39
  description: string;
40
+ id: string;
46
41
  };
47
- plus50MembersWithoutYou: {
42
+ noAccessWarning: {
43
+ defaultMessage: string;
44
+ description: string;
48
45
  id: string;
46
+ };
47
+ plus50MembersWithoutYou: {
49
48
  defaultMessage: string;
50
49
  description: string;
50
+ id: string;
51
51
  };
52
52
  plus50MembersWithYou: {
53
+ defaultMessage: string;
54
+ description: string;
53
55
  id: string;
56
+ };
57
+ unknownUserError: {
54
58
  defaultMessage: string;
55
59
  description: string;
60
+ id: string;
56
61
  };
57
62
  xProductMentionDescription: {
58
- id: string;
59
63
  defaultMessage: string;
60
64
  description: string;
65
+ id: string;
61
66
  };
62
67
  };
@@ -207,7 +207,7 @@ export interface LozengeProps {
207
207
  appearance?: LozengeColor;
208
208
  text: React.ReactNode;
209
209
  }
210
- export interface MentionDescription {
210
+ export interface RealMentionDescription {
211
211
  accessLevel?: string;
212
212
  appType?: string | null;
213
213
  avatarUrl?: string;
@@ -215,6 +215,8 @@ export interface MentionDescription {
215
215
  highlight?: Highlight;
216
216
  id: string;
217
217
  inContext?: boolean;
218
+ /** Discriminant: real mentions are never placeholders. */
219
+ isPlaceholder?: false;
218
220
  isXProductUser?: boolean;
219
221
  lozenge?: string | LozengeProps;
220
222
  mentionName?: string;
@@ -224,6 +226,33 @@ export interface MentionDescription {
224
226
  source?: string;
225
227
  userType?: string;
226
228
  }
229
+ /**
230
+ * Real-mention fields forbidden on a placeholder. Declaring them as `never`
231
+ * (rather than omitting them) keeps `mention.name` etc. readable on the
232
+ * {@link MentionDescription} union — so the hundreds of consumers that never
233
+ * encounter a placeholder are unaffected — while still making illegal
234
+ * combinations like `{ isPlaceholder: true, name: 'Real User' }` a compile
235
+ * error.
236
+ */
237
+ type RealMentionFieldsForbidden = {
238
+ [Field in Exclude<keyof RealMentionDescription, 'id' | 'isPlaceholder' | 'userType' | 'appType'>]?: never;
239
+ };
240
+ /**
241
+ * Non-selectable loading placeholder surfaced in the mention list while a
242
+ * slower mention source (e.g. agents) resolves. Its own member of the
243
+ * {@link MentionDescription} discriminated union (discriminated on
244
+ * `isPlaceholder`).
245
+ *
246
+ * `id` must be unique per placeholder — the typeahead keys rows by id — so
247
+ * multiple placeholders can be rendered at once.
248
+ */
249
+ export type MentionPlaceholder = RealMentionFieldsForbidden & {
250
+ appType?: 'agent';
251
+ id: string;
252
+ isPlaceholder: true;
253
+ userType?: 'APP';
254
+ };
255
+ export type MentionDescription = RealMentionDescription | MentionPlaceholder;
227
256
  export interface MentionDescContext {
228
257
  includesYou: boolean;
229
258
  memberCount: number;
@@ -319,3 +348,4 @@ export interface InviteFromMentionProvider {
319
348
  export interface XProductInviteMentionProvider {
320
349
  inviteXProductUser?: (userId: string, mentionName: string) => Promise<void>;
321
350
  }
351
+ export {};
package/package.json CHANGED
@@ -37,6 +37,7 @@
37
37
  "@atlaskit/platform-feature-flags": "^2.0.0",
38
38
  "@atlaskit/primitives": "^21.0.0",
39
39
  "@atlaskit/react-compiler-gating": "^0.2.0",
40
+ "@atlaskit/skeleton": "^4.2.0",
40
41
  "@atlaskit/tag": "^15.3.0",
41
42
  "@atlaskit/teams-avatar": "^3.1.0",
42
43
  "@atlaskit/tokens": "^15.8.0",
@@ -117,5 +118,5 @@
117
118
  }
118
119
  },
119
120
  "types": "dist/types/index.d.ts",
120
- "version": "27.6.0"
121
+ "version": "27.7.0"
121
122
  }