@atlaskit/editor-plugin-avatar-group 0.1.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 +1 -0
- package/LICENSE.md +13 -0
- package/README.md +33 -0
- package/dist/cjs/index.js +12 -0
- package/dist/cjs/messages.js +14 -0
- package/dist/cjs/plugin.js +58 -0
- package/dist/cjs/ui/AvatarGroupPluginWrapper.js +52 -0
- package/dist/cjs/ui/avatars-with-plugin-state.js +42 -0
- package/dist/cjs/ui/avatars.js +73 -0
- package/dist/cjs/ui/colored-avatar-item.js +23 -0
- package/dist/cjs/ui/index.js +16 -0
- package/dist/cjs/ui/invite-to-edit.js +48 -0
- package/dist/cjs/ui/styles.js +17 -0
- package/dist/cjs/ui/to-avatar.js +30 -0
- package/dist/es2019/index.js +1 -0
- package/dist/es2019/messages.js +8 -0
- package/dist/es2019/plugin.js +54 -0
- package/dist/es2019/ui/AvatarGroupPluginWrapper.js +57 -0
- package/dist/es2019/ui/avatars-with-plugin-state.js +38 -0
- package/dist/es2019/ui/avatars.js +66 -0
- package/dist/es2019/ui/colored-avatar-item.js +16 -0
- package/dist/es2019/ui/index.js +3 -0
- package/dist/es2019/ui/invite-to-edit.js +35 -0
- package/dist/es2019/ui/styles.js +46 -0
- package/dist/es2019/ui/to-avatar.js +16 -0
- package/dist/esm/index.js +1 -0
- package/dist/esm/messages.js +8 -0
- package/dist/esm/plugin.js +51 -0
- package/dist/esm/ui/AvatarGroupPluginWrapper.js +46 -0
- package/dist/esm/ui/avatars-with-plugin-state.js +35 -0
- package/dist/esm/ui/avatars.js +66 -0
- package/dist/esm/ui/colored-avatar-item.js +16 -0
- package/dist/esm/ui/index.js +3 -0
- package/dist/esm/ui/invite-to-edit.js +37 -0
- package/dist/esm/ui/styles.js +10 -0
- package/dist/esm/ui/to-avatar.js +23 -0
- package/dist/types/index.d.ts +2 -0
- package/dist/types/messages.d.ts +7 -0
- package/dist/types/plugin.d.ts +27 -0
- package/dist/types/ui/AvatarGroupPluginWrapper.d.ts +18 -0
- package/dist/types/ui/avatars-with-plugin-state.d.ts +80 -0
- package/dist/types/ui/avatars.d.ts +20 -0
- package/dist/types/ui/colored-avatar-item.d.ts +10 -0
- package/dist/types/ui/index.d.ts +3 -0
- package/dist/types/ui/invite-to-edit.d.ts +10 -0
- package/dist/types/ui/styles.d.ts +3 -0
- package/dist/types/ui/to-avatar.d.ts +30 -0
- package/dist/types-ts4.5/index.d.ts +2 -0
- package/dist/types-ts4.5/messages.d.ts +7 -0
- package/dist/types-ts4.5/plugin.d.ts +27 -0
- package/dist/types-ts4.5/ui/AvatarGroupPluginWrapper.d.ts +18 -0
- package/dist/types-ts4.5/ui/avatars-with-plugin-state.d.ts +96 -0
- package/dist/types-ts4.5/ui/avatars.d.ts +22 -0
- package/dist/types-ts4.5/ui/colored-avatar-item.d.ts +12 -0
- package/dist/types-ts4.5/ui/index.d.ts +3 -0
- package/dist/types-ts4.5/ui/invite-to-edit.d.ts +10 -0
- package/dist/types-ts4.5/ui/styles.d.ts +3 -0
- package/dist/types-ts4.5/ui/to-avatar.d.ts +37 -0
- package/package.json +110 -0
|
@@ -0,0 +1,66 @@
|
|
|
1
|
+
/** @jsx jsx */
|
|
2
|
+
|
|
3
|
+
import React from 'react';
|
|
4
|
+
import { jsx } from '@emotion/react';
|
|
5
|
+
import AvatarGroup from '@atlaskit/avatar-group';
|
|
6
|
+
import { ACTION, ACTION_SUBJECT, EVENT_TYPE } from '@atlaskit/editor-common/analytics';
|
|
7
|
+
import { Selection } from '@atlaskit/editor-prosemirror/state';
|
|
8
|
+
import { avatarContainer } from './styles';
|
|
9
|
+
import toAvatar from './to-avatar';
|
|
10
|
+
export const scrollToCollabCursor = (editorView, participants, sessionId, index, editorAnalyticsAPI) => {
|
|
11
|
+
const selectedUser = participants[index];
|
|
12
|
+
if (selectedUser && selectedUser.cursorPos !== undefined && selectedUser.sessionId !== sessionId) {
|
|
13
|
+
const {
|
|
14
|
+
state
|
|
15
|
+
} = editorView;
|
|
16
|
+
let tr = state.tr;
|
|
17
|
+
const analyticsPayload = {
|
|
18
|
+
action: ACTION.MATCHED,
|
|
19
|
+
actionSubject: ACTION_SUBJECT.SELECTION,
|
|
20
|
+
eventType: EVENT_TYPE.TRACK
|
|
21
|
+
};
|
|
22
|
+
tr.setSelection(Selection.near(tr.doc.resolve(selectedUser.cursorPos)));
|
|
23
|
+
editorAnalyticsAPI === null || editorAnalyticsAPI === void 0 ? void 0 : editorAnalyticsAPI.attachAnalyticsEvent(analyticsPayload)(tr);
|
|
24
|
+
tr.scrollIntoView();
|
|
25
|
+
editorView.dispatch(tr);
|
|
26
|
+
if (!editorView.hasFocus()) {
|
|
27
|
+
editorView.focus();
|
|
28
|
+
}
|
|
29
|
+
}
|
|
30
|
+
};
|
|
31
|
+
export const Avatars = /*#__PURE__*/React.memo(props => {
|
|
32
|
+
var _props$participants;
|
|
33
|
+
const {
|
|
34
|
+
sessionId,
|
|
35
|
+
editorView,
|
|
36
|
+
featureFlags,
|
|
37
|
+
editorAPI
|
|
38
|
+
} = props;
|
|
39
|
+
const participants = (_props$participants = props.participants) === null || _props$participants === void 0 ? void 0 : _props$participants.toArray();
|
|
40
|
+
const avatars = participants.sort(p => p.sessionId === sessionId ? -1 : 1).map(participant => toAvatar(participant, editorAPI));
|
|
41
|
+
if (!avatars.length) {
|
|
42
|
+
return null;
|
|
43
|
+
}
|
|
44
|
+
return (
|
|
45
|
+
// eslint-disable-next-line @atlaskit/design-system/consistent-css-prop-usage
|
|
46
|
+
jsx("div", {
|
|
47
|
+
css: avatarContainer
|
|
48
|
+
}, jsx(AvatarGroup, {
|
|
49
|
+
appearance: "stack",
|
|
50
|
+
size: "medium",
|
|
51
|
+
data: avatars,
|
|
52
|
+
maxCount: 3,
|
|
53
|
+
onAvatarClick: (_event, _analytics, index) => {
|
|
54
|
+
if (!editorView) {
|
|
55
|
+
return;
|
|
56
|
+
}
|
|
57
|
+
const allowCollabAvatarScroll = featureFlags === null || featureFlags === void 0 ? void 0 : featureFlags.collabAvatarScroll;
|
|
58
|
+
|
|
59
|
+
// user does not need to scroll to their own position (index 0)
|
|
60
|
+
if (allowCollabAvatarScroll && index > 0) {
|
|
61
|
+
scrollToCollabCursor(editorView, participants, props.sessionId, index, props.editorAnalyticsAPI);
|
|
62
|
+
}
|
|
63
|
+
}
|
|
64
|
+
}), props.children)
|
|
65
|
+
);
|
|
66
|
+
});
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
/** @jsx jsx */
|
|
2
|
+
import { jsx } from '@emotion/react';
|
|
3
|
+
import { R100 } from '@atlaskit/theme/colors';
|
|
4
|
+
import { badge } from './styles';
|
|
5
|
+
export const ColoredAvatarItem = props => {
|
|
6
|
+
var _props$api, _props$api$collabEdit, _props$api$collabEdit2;
|
|
7
|
+
const color = (_props$api = props.api) === null || _props$api === void 0 ? void 0 : (_props$api$collabEdit = _props$api.collabEdit) === null || _props$api$collabEdit === void 0 ? void 0 : (_props$api$collabEdit2 = _props$api$collabEdit.actions) === null || _props$api$collabEdit2 === void 0 ? void 0 : _props$api$collabEdit2.getAvatarColor(props.sessionId).color.solid;
|
|
8
|
+
const avatar = props.name.substr(0, 1).toUpperCase();
|
|
9
|
+
return (
|
|
10
|
+
// eslint-disable-next-line @atlaskit/design-system/consistent-css-prop-usage
|
|
11
|
+
jsx("div", {
|
|
12
|
+
css: badge(color || R100),
|
|
13
|
+
"data-testid": "editor-collab-badge"
|
|
14
|
+
}, avatar)
|
|
15
|
+
);
|
|
16
|
+
};
|
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
/** @jsx jsx */
|
|
2
|
+
import React, { Fragment } from 'react';
|
|
3
|
+
import { jsx } from '@emotion/react';
|
|
4
|
+
import { ToolbarButton } from '@atlaskit/editor-common/ui-menu';
|
|
5
|
+
import InviteTeamIcon from '@atlaskit/icon/glyph/editor/add';
|
|
6
|
+
import { inviteTeamWrapper } from './styles';
|
|
7
|
+
const ID = props => jsx(Fragment, null, props.children);
|
|
8
|
+
export const InviteToEditButton = props => {
|
|
9
|
+
const {
|
|
10
|
+
Component,
|
|
11
|
+
onClick,
|
|
12
|
+
selected,
|
|
13
|
+
title
|
|
14
|
+
} = props;
|
|
15
|
+
const iconBefore = React.useMemo(() => jsx(InviteTeamIcon, {
|
|
16
|
+
label: title
|
|
17
|
+
}), [title]);
|
|
18
|
+
if (!Component && !onClick) {
|
|
19
|
+
return null;
|
|
20
|
+
}
|
|
21
|
+
const Wrapper = Component ? Component : ID;
|
|
22
|
+
return (
|
|
23
|
+
// eslint-disable-next-line @atlaskit/design-system/consistent-css-prop-usage
|
|
24
|
+
jsx("div", {
|
|
25
|
+
css: inviteTeamWrapper
|
|
26
|
+
}, jsx(Wrapper, null, jsx(ToolbarButton, {
|
|
27
|
+
className: "invite-to-edit",
|
|
28
|
+
onClick: onClick,
|
|
29
|
+
selected: selected,
|
|
30
|
+
title: title,
|
|
31
|
+
titlePosition: "bottom",
|
|
32
|
+
iconBefore: iconBefore
|
|
33
|
+
})))
|
|
34
|
+
);
|
|
35
|
+
};
|
|
@@ -0,0 +1,46 @@
|
|
|
1
|
+
import { css } from '@emotion/react';
|
|
2
|
+
import { akEditorSmallZIndex, relativeFontSizeToBase16 } from '@atlaskit/editor-shared-styles';
|
|
3
|
+
import { N20 } from '@atlaskit/theme/colors';
|
|
4
|
+
export const inviteTeamWrapper = css`
|
|
5
|
+
background: ${`var(--ds-background-neutral, ${N20})`};
|
|
6
|
+
border-radius: 50%;
|
|
7
|
+
min-width: ${"var(--ds-space-400, 32px)"};
|
|
8
|
+
margin-left: ${"var(--ds-space-negative-050, -4px)"};
|
|
9
|
+
`;
|
|
10
|
+
export const avatarContainer = css`
|
|
11
|
+
margin-right: ${"var(--ds-space-100, 8px)"};
|
|
12
|
+
display: flex;
|
|
13
|
+
align-items: center;
|
|
14
|
+
|
|
15
|
+
// ED-13102: This is to override list styles that come from the
|
|
16
|
+
// .wiki-content class in Confluence that should not apply within
|
|
17
|
+
// the toolbar. Has to be extra specific to override.
|
|
18
|
+
&& > ul {
|
|
19
|
+
list-style-type: none;
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
div:last-child button.invite-to-edit {
|
|
23
|
+
border-radius: 50%;
|
|
24
|
+
height: 32px;
|
|
25
|
+
width: 32px;
|
|
26
|
+
padding: ${"var(--ds-space-025, 2px)"};
|
|
27
|
+
}
|
|
28
|
+
`;
|
|
29
|
+
export const badge = color => css`
|
|
30
|
+
display: block;
|
|
31
|
+
position: absolute;
|
|
32
|
+
right: 1px;
|
|
33
|
+
bottom: 1px;
|
|
34
|
+
width: 13px;
|
|
35
|
+
height: 13px;
|
|
36
|
+
z-index: ${akEditorSmallZIndex};
|
|
37
|
+
border-radius: 3px;
|
|
38
|
+
background: ${color};
|
|
39
|
+
color: ${"var(--ds-text-inverse, #fff)"};
|
|
40
|
+
font-size: ${relativeFontSizeToBase16(9)};
|
|
41
|
+
line-height: 0;
|
|
42
|
+
padding-top: 7px;
|
|
43
|
+
text-align: center;
|
|
44
|
+
box-shadow: 0 0 1px ${"var(--ds-border-inverse, #fff)"};
|
|
45
|
+
box-sizing: border-box;
|
|
46
|
+
`;
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
import React from 'react';
|
|
2
|
+
import memoizeOne from 'memoize-one';
|
|
3
|
+
import { ColoredAvatarItem } from './colored-avatar-item';
|
|
4
|
+
const toAvatar = (participant, api) => ({
|
|
5
|
+
name: participant.name,
|
|
6
|
+
src: participant.avatar,
|
|
7
|
+
size: 'medium',
|
|
8
|
+
presence: /*#__PURE__*/React.createElement(ColoredAvatarItem, {
|
|
9
|
+
api: api,
|
|
10
|
+
name: participant.name,
|
|
11
|
+
sessionId: participant.sessionId
|
|
12
|
+
})
|
|
13
|
+
});
|
|
14
|
+
export default memoizeOne(toAvatar, function participantEquals([a], [b]) {
|
|
15
|
+
return a.name === b.name && a.avatar === b.avatar && a.sessionId === b.sessionId;
|
|
16
|
+
});
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export { avatarGroupPlugin } from './plugin';
|
|
@@ -0,0 +1,51 @@
|
|
|
1
|
+
import React from 'react';
|
|
2
|
+
import AvatarGroupPluginWrapper from './ui/AvatarGroupPluginWrapper';
|
|
3
|
+
import AvatarsWithPluginState from './ui/avatars-with-plugin-state';
|
|
4
|
+
export var avatarGroupPlugin = function avatarGroupPlugin(_ref) {
|
|
5
|
+
var _api$featureFlags;
|
|
6
|
+
var props = _ref.config,
|
|
7
|
+
api = _ref.api;
|
|
8
|
+
var featureFlags = (api === null || api === void 0 || (_api$featureFlags = api.featureFlags) === null || _api$featureFlags === void 0 ? void 0 : _api$featureFlags.sharedState.currentState()) || {};
|
|
9
|
+
return {
|
|
10
|
+
name: 'avatarGroup',
|
|
11
|
+
primaryToolbarComponent: props.showAvatarGroup ? function (_ref2) {
|
|
12
|
+
var _api$analytics;
|
|
13
|
+
var editorView = _ref2.editorView,
|
|
14
|
+
popupsMountPoint = _ref2.popupsMountPoint,
|
|
15
|
+
popupsBoundariesElement = _ref2.popupsBoundariesElement,
|
|
16
|
+
popupsScrollableElement = _ref2.popupsScrollableElement,
|
|
17
|
+
disabled = _ref2.disabled,
|
|
18
|
+
isToolbarReducedSpacing = _ref2.isToolbarReducedSpacing,
|
|
19
|
+
eventDispatcher = _ref2.eventDispatcher,
|
|
20
|
+
dispatchAnalyticsEvent = _ref2.dispatchAnalyticsEvent;
|
|
21
|
+
return /*#__PURE__*/React.createElement(AvatarGroupPluginWrapper, {
|
|
22
|
+
dispatchAnalyticsEvent: dispatchAnalyticsEvent,
|
|
23
|
+
editorView: editorView,
|
|
24
|
+
eventDispatcher: eventDispatcher,
|
|
25
|
+
collabEdit: props === null || props === void 0 ? void 0 : props.collabEdit,
|
|
26
|
+
takeFullWidth: props === null || props === void 0 ? void 0 : props.takeFullWidth,
|
|
27
|
+
featureFlags: featureFlags,
|
|
28
|
+
editorAnalyticsAPI: api === null || api === void 0 || (_api$analytics = api.analytics) === null || _api$analytics === void 0 ? void 0 : _api$analytics.actions,
|
|
29
|
+
editorAPI: api
|
|
30
|
+
});
|
|
31
|
+
} : undefined,
|
|
32
|
+
actions: {
|
|
33
|
+
getToolbarItem: function getToolbarItem(_ref3) {
|
|
34
|
+
var _api$featureFlags$sha, _api$featureFlags2, _api$analytics2;
|
|
35
|
+
var editorView = _ref3.editorView,
|
|
36
|
+
inviteToEditHandler = _ref3.inviteToEditHandler,
|
|
37
|
+
isInviteToEditButtonSelected = _ref3.isInviteToEditButtonSelected,
|
|
38
|
+
inviteToEditComponent = _ref3.inviteToEditComponent;
|
|
39
|
+
return /*#__PURE__*/React.createElement(AvatarsWithPluginState, {
|
|
40
|
+
editorView: editorView,
|
|
41
|
+
featureFlags: (_api$featureFlags$sha = api === null || api === void 0 || (_api$featureFlags2 = api.featureFlags) === null || _api$featureFlags2 === void 0 ? void 0 : _api$featureFlags2.sharedState.currentState()) !== null && _api$featureFlags$sha !== void 0 ? _api$featureFlags$sha : {},
|
|
42
|
+
editorAnalyticsAPI: api === null || api === void 0 || (_api$analytics2 = api.analytics) === null || _api$analytics2 === void 0 ? void 0 : _api$analytics2.actions,
|
|
43
|
+
editorAPI: api,
|
|
44
|
+
inviteToEditHandler: inviteToEditHandler,
|
|
45
|
+
isInviteToEditButtonSelected: isInviteToEditButtonSelected,
|
|
46
|
+
inviteToEditComponent: inviteToEditComponent
|
|
47
|
+
});
|
|
48
|
+
}
|
|
49
|
+
}
|
|
50
|
+
};
|
|
51
|
+
};
|
|
@@ -0,0 +1,46 @@
|
|
|
1
|
+
import _taggedTemplateLiteral from "@babel/runtime/helpers/taggedTemplateLiteral";
|
|
2
|
+
var _templateObject, _templateObject2;
|
|
3
|
+
/** @jsx jsx */
|
|
4
|
+
import { useEffect } from 'react';
|
|
5
|
+
import { css, jsx } from '@emotion/react';
|
|
6
|
+
import { useIntl } from 'react-intl-next';
|
|
7
|
+
import { ACTION, ACTION_SUBJECT, ACTION_SUBJECT_ID, EVENT_TYPE } from '@atlaskit/editor-common/analytics';
|
|
8
|
+
import { avatarGroupMessages } from '../messages';
|
|
9
|
+
import AvatarsWithPluginState from './avatars-with-plugin-state';
|
|
10
|
+
|
|
11
|
+
// eslint-disable-next-line @atlaskit/design-system/consistent-css-prop-usage
|
|
12
|
+
var toolbarButtonWrapper = css(_templateObject || (_templateObject = _taggedTemplateLiteral(["\n display: flex;\n justify-content: flex-end;\n flex-grow: 0;\n align-items: center;\n & > div {\n margin-right: 0;\n }\n"])));
|
|
13
|
+
|
|
14
|
+
// eslint-disable-next-line @atlaskit/design-system/consistent-css-prop-usage
|
|
15
|
+
var toolbarButtonWrapperFullWidth = css(_templateObject2 || (_templateObject2 = _taggedTemplateLiteral(["\n ", "\n flex-grow: 1;\n"])), toolbarButtonWrapper);
|
|
16
|
+
var AvatarGroupPluginWrapper = function AvatarGroupPluginWrapper(props) {
|
|
17
|
+
var dispatchAnalyticsEvent = props.dispatchAnalyticsEvent,
|
|
18
|
+
featureFlags = props.featureFlags;
|
|
19
|
+
var intl = useIntl();
|
|
20
|
+
useEffect(function () {
|
|
21
|
+
if (!dispatchAnalyticsEvent) {
|
|
22
|
+
return;
|
|
23
|
+
}
|
|
24
|
+
dispatchAnalyticsEvent({
|
|
25
|
+
action: ACTION.VIEWED,
|
|
26
|
+
actionSubject: ACTION_SUBJECT.BUTTON,
|
|
27
|
+
actionSubjectId: ACTION_SUBJECT_ID.AVATAR_GROUP_PLUGIN,
|
|
28
|
+
eventType: EVENT_TYPE.UI
|
|
29
|
+
});
|
|
30
|
+
}, [dispatchAnalyticsEvent]);
|
|
31
|
+
return jsx("div", {
|
|
32
|
+
"aria-label": intl.formatMessage(avatarGroupMessages.editors),
|
|
33
|
+
"data-testid": 'avatar-group-in-plugin',
|
|
34
|
+
css: props.takeFullWidth ? toolbarButtonWrapperFullWidth : toolbarButtonWrapper
|
|
35
|
+
}, jsx(AvatarsWithPluginState, {
|
|
36
|
+
editorView: props.editorView,
|
|
37
|
+
eventDispatcher: props.eventDispatcher,
|
|
38
|
+
inviteToEditComponent: props.collabEdit && props.collabEdit.inviteToEditComponent,
|
|
39
|
+
inviteToEditHandler: props.collabEdit && props.collabEdit.inviteToEditHandler,
|
|
40
|
+
isInviteToEditButtonSelected: props.collabEdit && props.collabEdit.isInviteToEditButtonSelected,
|
|
41
|
+
featureFlags: featureFlags,
|
|
42
|
+
editorAnalyticsAPI: props.editorAnalyticsAPI,
|
|
43
|
+
editorAPI: props.editorAPI
|
|
44
|
+
}));
|
|
45
|
+
};
|
|
46
|
+
export default AvatarGroupPluginWrapper;
|
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
import React from 'react';
|
|
2
|
+
import { injectIntl } from 'react-intl-next';
|
|
3
|
+
import { useSharedPluginState } from '@atlaskit/editor-common/hooks';
|
|
4
|
+
import messages from '@atlaskit/editor-common/messages';
|
|
5
|
+
import { Avatars } from './avatars';
|
|
6
|
+
import { InviteToEditButton } from './invite-to-edit';
|
|
7
|
+
var AvatarsWithPluginState = function AvatarsWithPluginState(props) {
|
|
8
|
+
var title = props.intl.formatMessage(messages.inviteToEditButtonTitle);
|
|
9
|
+
var selected = props.isInviteToEditButtonSelected,
|
|
10
|
+
onClick = props.inviteToEditHandler,
|
|
11
|
+
Component = props.inviteToEditComponent,
|
|
12
|
+
editorView = props.editorView,
|
|
13
|
+
featureFlags = props.featureFlags,
|
|
14
|
+
editorAnalyticsAPI = props.editorAnalyticsAPI,
|
|
15
|
+
editorAPI = props.editorAPI;
|
|
16
|
+
var _useSharedPluginState = useSharedPluginState(editorAPI, ['collabEdit']),
|
|
17
|
+
collabEditState = _useSharedPluginState.collabEditState;
|
|
18
|
+
if (!collabEditState) {
|
|
19
|
+
return null;
|
|
20
|
+
}
|
|
21
|
+
return /*#__PURE__*/React.createElement(Avatars, {
|
|
22
|
+
sessionId: collabEditState.sessionId,
|
|
23
|
+
participants: collabEditState.activeParticipants,
|
|
24
|
+
editorView: editorView,
|
|
25
|
+
featureFlags: featureFlags,
|
|
26
|
+
editorAnalyticsAPI: editorAnalyticsAPI,
|
|
27
|
+
editorAPI: editorAPI
|
|
28
|
+
}, /*#__PURE__*/React.createElement(InviteToEditButton, {
|
|
29
|
+
title: title,
|
|
30
|
+
selected: selected,
|
|
31
|
+
onClick: onClick,
|
|
32
|
+
Component: Component
|
|
33
|
+
}));
|
|
34
|
+
};
|
|
35
|
+
export default injectIntl(AvatarsWithPluginState);
|
|
@@ -0,0 +1,66 @@
|
|
|
1
|
+
/** @jsx jsx */
|
|
2
|
+
|
|
3
|
+
import React from 'react';
|
|
4
|
+
import { jsx } from '@emotion/react';
|
|
5
|
+
import AvatarGroup from '@atlaskit/avatar-group';
|
|
6
|
+
import { ACTION, ACTION_SUBJECT, EVENT_TYPE } from '@atlaskit/editor-common/analytics';
|
|
7
|
+
import { Selection } from '@atlaskit/editor-prosemirror/state';
|
|
8
|
+
import { avatarContainer } from './styles';
|
|
9
|
+
import toAvatar from './to-avatar';
|
|
10
|
+
export var scrollToCollabCursor = function scrollToCollabCursor(editorView, participants, sessionId, index, editorAnalyticsAPI) {
|
|
11
|
+
var selectedUser = participants[index];
|
|
12
|
+
if (selectedUser && selectedUser.cursorPos !== undefined && selectedUser.sessionId !== sessionId) {
|
|
13
|
+
var state = editorView.state;
|
|
14
|
+
var tr = state.tr;
|
|
15
|
+
var analyticsPayload = {
|
|
16
|
+
action: ACTION.MATCHED,
|
|
17
|
+
actionSubject: ACTION_SUBJECT.SELECTION,
|
|
18
|
+
eventType: EVENT_TYPE.TRACK
|
|
19
|
+
};
|
|
20
|
+
tr.setSelection(Selection.near(tr.doc.resolve(selectedUser.cursorPos)));
|
|
21
|
+
editorAnalyticsAPI === null || editorAnalyticsAPI === void 0 || editorAnalyticsAPI.attachAnalyticsEvent(analyticsPayload)(tr);
|
|
22
|
+
tr.scrollIntoView();
|
|
23
|
+
editorView.dispatch(tr);
|
|
24
|
+
if (!editorView.hasFocus()) {
|
|
25
|
+
editorView.focus();
|
|
26
|
+
}
|
|
27
|
+
}
|
|
28
|
+
};
|
|
29
|
+
export var Avatars = /*#__PURE__*/React.memo(function (props) {
|
|
30
|
+
var _props$participants;
|
|
31
|
+
var sessionId = props.sessionId,
|
|
32
|
+
editorView = props.editorView,
|
|
33
|
+
featureFlags = props.featureFlags,
|
|
34
|
+
editorAPI = props.editorAPI;
|
|
35
|
+
var participants = (_props$participants = props.participants) === null || _props$participants === void 0 ? void 0 : _props$participants.toArray();
|
|
36
|
+
var avatars = participants.sort(function (p) {
|
|
37
|
+
return p.sessionId === sessionId ? -1 : 1;
|
|
38
|
+
}).map(function (participant) {
|
|
39
|
+
return toAvatar(participant, editorAPI);
|
|
40
|
+
});
|
|
41
|
+
if (!avatars.length) {
|
|
42
|
+
return null;
|
|
43
|
+
}
|
|
44
|
+
return (
|
|
45
|
+
// eslint-disable-next-line @atlaskit/design-system/consistent-css-prop-usage
|
|
46
|
+
jsx("div", {
|
|
47
|
+
css: avatarContainer
|
|
48
|
+
}, jsx(AvatarGroup, {
|
|
49
|
+
appearance: "stack",
|
|
50
|
+
size: "medium",
|
|
51
|
+
data: avatars,
|
|
52
|
+
maxCount: 3,
|
|
53
|
+
onAvatarClick: function onAvatarClick(_event, _analytics, index) {
|
|
54
|
+
if (!editorView) {
|
|
55
|
+
return;
|
|
56
|
+
}
|
|
57
|
+
var allowCollabAvatarScroll = featureFlags === null || featureFlags === void 0 ? void 0 : featureFlags.collabAvatarScroll;
|
|
58
|
+
|
|
59
|
+
// user does not need to scroll to their own position (index 0)
|
|
60
|
+
if (allowCollabAvatarScroll && index > 0) {
|
|
61
|
+
scrollToCollabCursor(editorView, participants, props.sessionId, index, props.editorAnalyticsAPI);
|
|
62
|
+
}
|
|
63
|
+
}
|
|
64
|
+
}), props.children)
|
|
65
|
+
);
|
|
66
|
+
});
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
/** @jsx jsx */
|
|
2
|
+
import { jsx } from '@emotion/react';
|
|
3
|
+
import { R100 } from '@atlaskit/theme/colors';
|
|
4
|
+
import { badge } from './styles';
|
|
5
|
+
export var ColoredAvatarItem = function ColoredAvatarItem(props) {
|
|
6
|
+
var _props$api;
|
|
7
|
+
var color = (_props$api = props.api) === null || _props$api === void 0 || (_props$api = _props$api.collabEdit) === null || _props$api === void 0 || (_props$api = _props$api.actions) === null || _props$api === void 0 ? void 0 : _props$api.getAvatarColor(props.sessionId).color.solid;
|
|
8
|
+
var avatar = props.name.substr(0, 1).toUpperCase();
|
|
9
|
+
return (
|
|
10
|
+
// eslint-disable-next-line @atlaskit/design-system/consistent-css-prop-usage
|
|
11
|
+
jsx("div", {
|
|
12
|
+
css: badge(color || R100),
|
|
13
|
+
"data-testid": "editor-collab-badge"
|
|
14
|
+
}, avatar)
|
|
15
|
+
);
|
|
16
|
+
};
|
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
/** @jsx jsx */
|
|
2
|
+
import React, { Fragment } from 'react';
|
|
3
|
+
import { jsx } from '@emotion/react';
|
|
4
|
+
import { ToolbarButton } from '@atlaskit/editor-common/ui-menu';
|
|
5
|
+
import InviteTeamIcon from '@atlaskit/icon/glyph/editor/add';
|
|
6
|
+
import { inviteTeamWrapper } from './styles';
|
|
7
|
+
var ID = function ID(props) {
|
|
8
|
+
return jsx(Fragment, null, props.children);
|
|
9
|
+
};
|
|
10
|
+
export var InviteToEditButton = function InviteToEditButton(props) {
|
|
11
|
+
var Component = props.Component,
|
|
12
|
+
onClick = props.onClick,
|
|
13
|
+
selected = props.selected,
|
|
14
|
+
title = props.title;
|
|
15
|
+
var iconBefore = React.useMemo(function () {
|
|
16
|
+
return jsx(InviteTeamIcon, {
|
|
17
|
+
label: title
|
|
18
|
+
});
|
|
19
|
+
}, [title]);
|
|
20
|
+
if (!Component && !onClick) {
|
|
21
|
+
return null;
|
|
22
|
+
}
|
|
23
|
+
var Wrapper = Component ? Component : ID;
|
|
24
|
+
return (
|
|
25
|
+
// eslint-disable-next-line @atlaskit/design-system/consistent-css-prop-usage
|
|
26
|
+
jsx("div", {
|
|
27
|
+
css: inviteTeamWrapper
|
|
28
|
+
}, jsx(Wrapper, null, jsx(ToolbarButton, {
|
|
29
|
+
className: "invite-to-edit",
|
|
30
|
+
onClick: onClick,
|
|
31
|
+
selected: selected,
|
|
32
|
+
title: title,
|
|
33
|
+
titlePosition: "bottom",
|
|
34
|
+
iconBefore: iconBefore
|
|
35
|
+
})))
|
|
36
|
+
);
|
|
37
|
+
};
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
import _taggedTemplateLiteral from "@babel/runtime/helpers/taggedTemplateLiteral";
|
|
2
|
+
var _templateObject, _templateObject2, _templateObject3;
|
|
3
|
+
import { css } from '@emotion/react';
|
|
4
|
+
import { akEditorSmallZIndex, relativeFontSizeToBase16 } from '@atlaskit/editor-shared-styles';
|
|
5
|
+
import { N20 } from '@atlaskit/theme/colors';
|
|
6
|
+
export var inviteTeamWrapper = css(_templateObject || (_templateObject = _taggedTemplateLiteral(["\n background: ", ";\n border-radius: 50%;\n min-width: ", ";\n margin-left: ", ";\n"])), "var(--ds-background-neutral, ".concat(N20, ")"), "var(--ds-space-400, 32px)", "var(--ds-space-negative-050, -4px)");
|
|
7
|
+
export var avatarContainer = css(_templateObject2 || (_templateObject2 = _taggedTemplateLiteral(["\n margin-right: ", ";\n display: flex;\n align-items: center;\n\n // ED-13102: This is to override list styles that come from the\n // .wiki-content class in Confluence that should not apply within\n // the toolbar. Has to be extra specific to override.\n && > ul {\n list-style-type: none;\n }\n\n div:last-child button.invite-to-edit {\n border-radius: 50%;\n height: 32px;\n width: 32px;\n padding: ", ";\n }\n"])), "var(--ds-space-100, 8px)", "var(--ds-space-025, 2px)");
|
|
8
|
+
export var badge = function badge(color) {
|
|
9
|
+
return css(_templateObject3 || (_templateObject3 = _taggedTemplateLiteral(["\n display: block;\n position: absolute;\n right: 1px;\n bottom: 1px;\n width: 13px;\n height: 13px;\n z-index: ", ";\n border-radius: 3px;\n background: ", ";\n color: ", ";\n font-size: ", ";\n line-height: 0;\n padding-top: 7px;\n text-align: center;\n box-shadow: 0 0 1px ", ";\n box-sizing: border-box;\n"])), akEditorSmallZIndex, color, "var(--ds-text-inverse, #fff)", relativeFontSizeToBase16(9), "var(--ds-border-inverse, #fff)");
|
|
10
|
+
};
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
import _slicedToArray from "@babel/runtime/helpers/slicedToArray";
|
|
2
|
+
import React from 'react';
|
|
3
|
+
import memoizeOne from 'memoize-one';
|
|
4
|
+
import { ColoredAvatarItem } from './colored-avatar-item';
|
|
5
|
+
var toAvatar = function toAvatar(participant, api) {
|
|
6
|
+
return {
|
|
7
|
+
name: participant.name,
|
|
8
|
+
src: participant.avatar,
|
|
9
|
+
size: 'medium',
|
|
10
|
+
presence: /*#__PURE__*/React.createElement(ColoredAvatarItem, {
|
|
11
|
+
api: api,
|
|
12
|
+
name: participant.name,
|
|
13
|
+
sessionId: participant.sessionId
|
|
14
|
+
})
|
|
15
|
+
};
|
|
16
|
+
};
|
|
17
|
+
export default memoizeOne(toAvatar, function participantEquals(_ref, _ref2) {
|
|
18
|
+
var _ref3 = _slicedToArray(_ref, 1),
|
|
19
|
+
a = _ref3[0];
|
|
20
|
+
var _ref4 = _slicedToArray(_ref2, 1),
|
|
21
|
+
b = _ref4[0];
|
|
22
|
+
return a.name === b.name && a.avatar === b.avatar && a.sessionId === b.sessionId;
|
|
23
|
+
});
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
/// <reference types="react" />
|
|
2
|
+
import type { CollabEditOptions, CollabInviteToEditProps } from '@atlaskit/editor-common/collab';
|
|
3
|
+
import type { NextEditorPlugin, OptionalPlugin } from '@atlaskit/editor-common/types';
|
|
4
|
+
import type { AnalyticsPlugin } from '@atlaskit/editor-plugin-analytics';
|
|
5
|
+
import type { CollabEditPlugin } from '@atlaskit/editor-plugin-collab-edit';
|
|
6
|
+
import type { FeatureFlagsPlugin } from '@atlaskit/editor-plugin-feature-flags';
|
|
7
|
+
import type { EditorView } from '@atlaskit/editor-prosemirror/view';
|
|
8
|
+
type Config = {
|
|
9
|
+
collabEdit?: CollabEditOptions;
|
|
10
|
+
takeFullWidth: boolean;
|
|
11
|
+
showAvatarGroup?: boolean;
|
|
12
|
+
};
|
|
13
|
+
export type AvatarGroupPlugin = NextEditorPlugin<'avatarGroup', {
|
|
14
|
+
pluginConfiguration: Config;
|
|
15
|
+
dependencies: [
|
|
16
|
+
OptionalPlugin<FeatureFlagsPlugin>,
|
|
17
|
+
OptionalPlugin<AnalyticsPlugin>,
|
|
18
|
+
OptionalPlugin<CollabEditPlugin>
|
|
19
|
+
];
|
|
20
|
+
actions: {
|
|
21
|
+
getToolbarItem: ({ editorView, inviteToEditHandler, isInviteToEditButtonSelected, inviteToEditComponent, }: {
|
|
22
|
+
editorView: EditorView;
|
|
23
|
+
} & CollabInviteToEditProps) => JSX.Element | null;
|
|
24
|
+
};
|
|
25
|
+
}>;
|
|
26
|
+
export declare const avatarGroupPlugin: AvatarGroupPlugin;
|
|
27
|
+
export {};
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
import { jsx } from '@emotion/react';
|
|
2
|
+
import type { DispatchAnalyticsEvent, EditorAnalyticsAPI } from '@atlaskit/editor-common/analytics';
|
|
3
|
+
import type { CollabEditOptions } from '@atlaskit/editor-common/collab';
|
|
4
|
+
import type { EventDispatcher } from '@atlaskit/editor-common/event-dispatcher';
|
|
5
|
+
import type { ExtractInjectionAPI, FeatureFlags } from '@atlaskit/editor-common/types';
|
|
6
|
+
import type { EditorView } from '@atlaskit/editor-prosemirror/view';
|
|
7
|
+
import type { AvatarGroupPlugin } from '../index';
|
|
8
|
+
declare const AvatarGroupPluginWrapper: (props: {
|
|
9
|
+
collabEdit?: CollabEditOptions | undefined;
|
|
10
|
+
editorView: EditorView;
|
|
11
|
+
eventDispatcher: EventDispatcher<any>;
|
|
12
|
+
dispatchAnalyticsEvent?: DispatchAnalyticsEvent | undefined;
|
|
13
|
+
takeFullWidth: boolean;
|
|
14
|
+
featureFlags: FeatureFlags;
|
|
15
|
+
editorAnalyticsAPI: EditorAnalyticsAPI | undefined;
|
|
16
|
+
editorAPI: ExtractInjectionAPI<AvatarGroupPlugin> | undefined;
|
|
17
|
+
}) => jsx.JSX.Element;
|
|
18
|
+
export default AvatarGroupPluginWrapper;
|
|
@@ -0,0 +1,80 @@
|
|
|
1
|
+
import React from 'react';
|
|
2
|
+
import type { WrappedComponentProps } from 'react-intl-next';
|
|
3
|
+
import type { EditorAnalyticsAPI } from '@atlaskit/editor-common/analytics';
|
|
4
|
+
import type { EventDispatcher } from '@atlaskit/editor-common/event-dispatcher';
|
|
5
|
+
import type { FeatureFlags, OptionalPlugin, PublicPluginAPI } from '@atlaskit/editor-common/types';
|
|
6
|
+
import type { CollabEditPlugin, CollabInviteToEditProps } from '@atlaskit/editor-plugin-collab-edit';
|
|
7
|
+
import type { EditorView } from '@atlaskit/editor-prosemirror/view';
|
|
8
|
+
export type AvatarsWithPluginStateProps = {
|
|
9
|
+
editorView?: EditorView;
|
|
10
|
+
eventDispatcher?: EventDispatcher;
|
|
11
|
+
featureFlags: FeatureFlags;
|
|
12
|
+
editorAnalyticsAPI: EditorAnalyticsAPI | undefined;
|
|
13
|
+
editorAPI: PublicPluginAPI<[OptionalPlugin<CollabEditPlugin>]> | undefined;
|
|
14
|
+
} & CollabInviteToEditProps;
|
|
15
|
+
declare const _default: React.FC<import("react-intl-next").WithIntlProps<{
|
|
16
|
+
editorView?: EditorView | undefined;
|
|
17
|
+
eventDispatcher?: EventDispatcher<any> | undefined;
|
|
18
|
+
featureFlags: FeatureFlags;
|
|
19
|
+
editorAnalyticsAPI: EditorAnalyticsAPI | undefined;
|
|
20
|
+
editorAPI: PublicPluginAPI<[OptionalPlugin<import("@atlaskit/editor-common/types").NextEditorPluginFunctionOptionalConfigDefinition<"collabEdit", {
|
|
21
|
+
pluginConfiguration: import("@atlaskit/editor-plugin-collab-edit").PrivateCollabEditOptions;
|
|
22
|
+
dependencies: [OptionalPlugin<import("@atlaskit/editor-common/types").NextEditorPluginFunctionOptionalConfigDefinition<"featureFlags", {
|
|
23
|
+
pluginConfiguration: FeatureFlags;
|
|
24
|
+
sharedState: FeatureFlags;
|
|
25
|
+
}, FeatureFlags>>, OptionalPlugin<import("@atlaskit/editor-common/types").NextEditorPluginFunctionOptionalConfigDefinition<"analytics", {
|
|
26
|
+
pluginConfiguration: import("@atlaskit/editor-plugin-analytics").AnalyticsPluginOptions;
|
|
27
|
+
sharedState: {
|
|
28
|
+
createAnalyticsEvent: import("@atlaskit/analytics-next").CreateUIAnalyticsEvent | null;
|
|
29
|
+
attachAnalyticsEvent: import("@atlaskit/editor-plugin-analytics").CreateAttachPayloadIntoTransaction | null;
|
|
30
|
+
performanceTracking: import("@atlaskit/editor-common/types").PerformanceTracking | undefined;
|
|
31
|
+
};
|
|
32
|
+
dependencies: [OptionalPlugin<import("@atlaskit/editor-common/types").NextEditorPluginFunctionOptionalConfigDefinition<"featureFlags", {
|
|
33
|
+
pluginConfiguration: FeatureFlags;
|
|
34
|
+
sharedState: FeatureFlags;
|
|
35
|
+
}, FeatureFlags>>];
|
|
36
|
+
actions: EditorAnalyticsAPI;
|
|
37
|
+
}, import("@atlaskit/editor-plugin-analytics").AnalyticsPluginOptions>>];
|
|
38
|
+
sharedState: import("@atlaskit/editor-plugin-collab-edit").CollabEditPluginSharedState;
|
|
39
|
+
actions: {
|
|
40
|
+
getAvatarColor: (str: string) => {
|
|
41
|
+
index: number;
|
|
42
|
+
color: import("@atlaskit/editor-common/collab").Color;
|
|
43
|
+
};
|
|
44
|
+
};
|
|
45
|
+
}, import("@atlaskit/editor-plugin-collab-edit").PrivateCollabEditOptions>>]> | undefined;
|
|
46
|
+
} & CollabInviteToEditProps & WrappedComponentProps<"intl">>> & {
|
|
47
|
+
WrappedComponent: React.ComponentType<{
|
|
48
|
+
editorView?: EditorView | undefined;
|
|
49
|
+
eventDispatcher?: EventDispatcher<any> | undefined;
|
|
50
|
+
featureFlags: FeatureFlags;
|
|
51
|
+
editorAnalyticsAPI: EditorAnalyticsAPI | undefined;
|
|
52
|
+
editorAPI: PublicPluginAPI<[OptionalPlugin<import("@atlaskit/editor-common/types").NextEditorPluginFunctionOptionalConfigDefinition<"collabEdit", {
|
|
53
|
+
pluginConfiguration: import("@atlaskit/editor-plugin-collab-edit").PrivateCollabEditOptions;
|
|
54
|
+
dependencies: [OptionalPlugin<import("@atlaskit/editor-common/types").NextEditorPluginFunctionOptionalConfigDefinition<"featureFlags", {
|
|
55
|
+
pluginConfiguration: FeatureFlags;
|
|
56
|
+
sharedState: FeatureFlags;
|
|
57
|
+
}, FeatureFlags>>, OptionalPlugin<import("@atlaskit/editor-common/types").NextEditorPluginFunctionOptionalConfigDefinition<"analytics", {
|
|
58
|
+
pluginConfiguration: import("@atlaskit/editor-plugin-analytics").AnalyticsPluginOptions;
|
|
59
|
+
sharedState: {
|
|
60
|
+
createAnalyticsEvent: import("@atlaskit/analytics-next").CreateUIAnalyticsEvent | null;
|
|
61
|
+
attachAnalyticsEvent: import("@atlaskit/editor-plugin-analytics").CreateAttachPayloadIntoTransaction | null;
|
|
62
|
+
performanceTracking: import("@atlaskit/editor-common/types").PerformanceTracking | undefined;
|
|
63
|
+
};
|
|
64
|
+
dependencies: [OptionalPlugin<import("@atlaskit/editor-common/types").NextEditorPluginFunctionOptionalConfigDefinition<"featureFlags", {
|
|
65
|
+
pluginConfiguration: FeatureFlags;
|
|
66
|
+
sharedState: FeatureFlags;
|
|
67
|
+
}, FeatureFlags>>];
|
|
68
|
+
actions: EditorAnalyticsAPI;
|
|
69
|
+
}, import("@atlaskit/editor-plugin-analytics").AnalyticsPluginOptions>>];
|
|
70
|
+
sharedState: import("@atlaskit/editor-plugin-collab-edit").CollabEditPluginSharedState;
|
|
71
|
+
actions: {
|
|
72
|
+
getAvatarColor: (str: string) => {
|
|
73
|
+
index: number;
|
|
74
|
+
color: import("@atlaskit/editor-common/collab").Color;
|
|
75
|
+
};
|
|
76
|
+
};
|
|
77
|
+
}, import("@atlaskit/editor-plugin-collab-edit").PrivateCollabEditOptions>>]> | undefined;
|
|
78
|
+
} & CollabInviteToEditProps & WrappedComponentProps<"intl">>;
|
|
79
|
+
};
|
|
80
|
+
export default _default;
|