@jetbrains/ring-ui 5.0.97 → 5.0.99

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.
@@ -0,0 +1,2 @@
1
+ export declare function copyTextToClipboard(str: string): void;
2
+ export declare function copyHTMLToClipboard(str: string): void;
@@ -0,0 +1,44 @@
1
+ export function copyTextToClipboard(str) {
2
+ const el = document.createElement('textarea');
3
+ el.value = str;
4
+ el.setAttribute('readonly', '');
5
+ el.style.position = 'absolute';
6
+ el.style.left = '-9999px';
7
+ document.body.appendChild(el);
8
+ const selection = document.getSelection();
9
+ // Should restore previous selection
10
+ const selected = (selection && selection.rangeCount > 0)
11
+ ? selection.getRangeAt(0)
12
+ : false;
13
+ el.select();
14
+ document.execCommand('copy');
15
+ document.body.removeChild(el);
16
+ if (selected && selection) {
17
+ selection.removeAllRanges();
18
+ selection.addRange(selected);
19
+ }
20
+ }
21
+ export function copyHTMLToClipboard(str) {
22
+ const el = document.createElement('div');
23
+ el.innerHTML = str;
24
+ el.setAttribute('readonly', '');
25
+ el.style.position = 'absolute';
26
+ el.style.left = '-9999px';
27
+ document.body.appendChild(el);
28
+ const selection = document.getSelection();
29
+ // Should restore previous selection
30
+ const selected = (selection && selection.rangeCount > 0)
31
+ ? selection.getRangeAt(0)
32
+ : false;
33
+ selection?.removeAllRanges();
34
+ const range = document.createRange();
35
+ range.selectNode(el);
36
+ selection?.addRange(range);
37
+ document.execCommand('copy');
38
+ selection?.removeAllRanges();
39
+ document.execCommand('copy');
40
+ document.body.removeChild(el);
41
+ if (selected && selection) {
42
+ selection.addRange(selected);
43
+ }
44
+ }
@@ -0,0 +1,5 @@
1
+ declare const clipboard: {
2
+ copyText: (text: string, successMessage?: string | undefined, errorMessage?: string | undefined, delay?: number) => Promise<void>;
3
+ copyHTML: (html: string, successMessage?: string | undefined, errorMessage?: string | undefined, delay?: number) => Promise<void>;
4
+ };
5
+ export default clipboard;
@@ -0,0 +1,41 @@
1
+ import alertService from '../alert-service/alert-service';
2
+ import { copyHTMLToClipboard, copyTextToClipboard } from './clipboard-fallback';
3
+ const ALERT_DELAY = 1000;
4
+ function getClipboardImplementation() {
5
+ if (navigator.clipboard && !window.isSecureContext) {
6
+ return {
7
+ copy: (text) => navigator.clipboard.writeText(text),
8
+ copyHTML: (html) => navigator.clipboard.write([
9
+ new ClipboardItem({
10
+ ['text/html']: new Blob([html], { type: 'text/html' })
11
+ })
12
+ ])
13
+ };
14
+ }
15
+ return {
16
+ copy: (str) => Promise.resolve(copyTextToClipboard(str)),
17
+ copyHTML: (html) => Promise.resolve(copyHTMLToClipboard(html))
18
+ };
19
+ }
20
+ async function copy(text, successMessage, errorMessage, delay = ALERT_DELAY, isHtml = false) {
21
+ try {
22
+ const clipboardImpl = getClipboardImplementation();
23
+ const copyMethod = isHtml ? clipboardImpl.copyHTML : clipboardImpl.copy;
24
+ await copyMethod(text);
25
+ if (successMessage) {
26
+ alertService.successMessage(successMessage, delay);
27
+ }
28
+ }
29
+ catch (e) {
30
+ if (errorMessage) {
31
+ alertService.error(errorMessage, delay);
32
+ }
33
+ // eslint-disable-next-line no-console
34
+ console.error(e);
35
+ }
36
+ }
37
+ const clipboard = {
38
+ copyText: async (text, successMessage, errorMessage, delay = ALERT_DELAY) => await copy(text, successMessage, errorMessage, delay),
39
+ copyHTML: async (html, successMessage, errorMessage, delay = ALERT_DELAY) => await copy(html, successMessage, errorMessage, delay, true)
40
+ };
41
+ export default clipboard;
@@ -9,16 +9,22 @@ export interface UserCardUser {
9
9
  online?: boolean | null | undefined;
10
10
  banned?: boolean | null | undefined;
11
11
  banReason?: string | undefined;
12
+ unverifiedEmail?: boolean | null | undefined;
12
13
  }
13
14
  export interface UserCardWording {
14
15
  banned: string;
15
16
  online: string;
16
17
  offline: string;
18
+ copyToClipboard: string;
19
+ copiedToClipboard: string;
20
+ copingToClipboardError: string;
21
+ unverified: string;
17
22
  }
18
23
  export interface UserCardProps extends HTMLAttributes<HTMLDivElement> {
19
24
  user: UserCardUser;
20
25
  wording: UserCardWording;
21
26
  info?: ReactElement | readonly ReactElement[] | string;
27
+ avatarInfo?: ReactElement | readonly ReactElement[] | string;
22
28
  'data-test'?: string | null | undefined;
23
29
  }
24
30
  export default class UserCard extends PureComponent<UserCardProps> {
@@ -35,11 +41,16 @@ export default class UserCard extends PureComponent<UserCardProps> {
35
41
  online: PropTypes.Requireable<boolean>;
36
42
  banned: PropTypes.Requireable<boolean>;
37
43
  banReason: PropTypes.Requireable<string>;
44
+ unverifiedEmail: PropTypes.Requireable<boolean>;
38
45
  }>>>;
39
46
  wording: PropTypes.Requireable<PropTypes.InferProps<{
40
47
  banned: PropTypes.Validator<string>;
41
48
  online: PropTypes.Validator<string>;
42
49
  offline: PropTypes.Validator<string>;
50
+ copyToClipboard: PropTypes.Validator<string>;
51
+ copiedToClipboard: PropTypes.Validator<string>;
52
+ copingToClipboardError: PropTypes.Validator<string>;
53
+ unverified: PropTypes.Requireable<string>;
43
54
  }>>;
44
55
  };
45
56
  static defaultProps: {
@@ -47,8 +58,13 @@ export default class UserCard extends PureComponent<UserCardProps> {
47
58
  banned: string;
48
59
  online: string;
49
60
  offline: string;
61
+ copyToClipboard: string;
62
+ copiedToClipboard: string;
63
+ copingToClipboardError: string;
64
+ unverified: string;
50
65
  };
51
66
  };
67
+ copyEmail: () => void;
52
68
  render(): JSX.Element;
53
69
  }
54
70
  export type UserCardAttrs = JSX.LibraryManagedAttributes<typeof UserCard, UserCardProps>;
@@ -1,9 +1,12 @@
1
1
  import React, { PureComponent } from 'react';
2
2
  import PropTypes from 'prop-types';
3
3
  import classNames from 'classnames';
4
- import Avatar, { Size } from '../avatar/avatar';
4
+ import copyIcon from '@jetbrains/icons/copy';
5
+ import Avatar, { Size as AvatarSize } from '../avatar/avatar';
5
6
  import Link from '../link/link';
7
+ import clipboard from '../clipboard/clipboard';
6
8
  import badgeStyles from '../badge/badge.css';
9
+ import Icon, { Size as IconSize } from '../icon/icon';
7
10
  import styles from './user-card.css';
8
11
  export default class UserCard extends PureComponent {
9
12
  static propTypes = {
@@ -18,47 +21,67 @@ export default class UserCard extends PureComponent {
18
21
  href: PropTypes.string,
19
22
  online: PropTypes.bool,
20
23
  banned: PropTypes.bool,
21
- banReason: PropTypes.string
24
+ banReason: PropTypes.string,
25
+ unverifiedEmail: PropTypes.bool
22
26
  }).isRequired,
23
27
  wording: PropTypes.shape({
24
28
  banned: PropTypes.string.isRequired,
25
29
  online: PropTypes.string.isRequired,
26
- offline: PropTypes.string.isRequired
30
+ offline: PropTypes.string.isRequired,
31
+ copyToClipboard: PropTypes.string.isRequired,
32
+ copiedToClipboard: PropTypes.string.isRequired,
33
+ copingToClipboardError: PropTypes.string.isRequired,
34
+ unverified: PropTypes.string
27
35
  })
28
36
  };
29
37
  static defaultProps = {
30
38
  wording: {
31
39
  banned: 'banned',
32
40
  online: 'online',
33
- offline: 'offline'
41
+ offline: 'offline',
42
+ copyToClipboard: 'Copy to clipboard',
43
+ copiedToClipboard: 'Email was copied to clipboard',
44
+ copingToClipboardError: 'Failed to copy to clipboard',
45
+ unverified: 'Unverified'
34
46
  }
35
47
  };
48
+ copyEmail = () => {
49
+ const { user, wording } = this.props;
50
+ clipboard.copyText(user.email || '', wording.copiedToClipboard, wording.copingToClipboardError);
51
+ };
36
52
  render() {
37
- const { children, info, className, user, wording, ...restProps } = this.props;
53
+ const { children, info, className, user, wording, avatarInfo, ...restProps } = this.props;
38
54
  const classes = classNames(className, {});
39
55
  const userActiveStatusClasses = classNames(styles.userActiveStatus, user.online ? styles.online : '');
40
56
  return (<div className={classes} {...restProps}>
41
57
  <div className={styles.userInformationContainer}>
42
- <Avatar size={Size.Size56} url={user.avatarUrl}/>
58
+ <div className={styles.userAvatar}>
59
+ <Avatar size={AvatarSize.Size56} url={user.avatarUrl}/>
60
+ {!!avatarInfo && avatarInfo}
61
+ </div>
43
62
  <div className={styles.userInformation}>
44
- <div>
63
+ <div className={styles.userNameLine}>
45
64
  {user.href && (<Link href={user.href} className={styles.userName}>
46
65
  {user.name}
47
66
  </Link>)}
48
67
  {!user.href && <span className={styles.userName}>{user.name}</span>}
68
+ {typeof user.online === 'boolean' &&
69
+ (<span className={userActiveStatusClasses} title={user.online ? wording.online : wording.offline}/>)}
49
70
  {!!info && <span className={styles.userNameInfo}>{info}</span>}
50
71
  {user.banned &&
51
72
  (<span className={classNames(badgeStyles.badge, badgeStyles.invalid)} title={user.banReason}>{wording.banned}</span>)}
52
73
  </div>
53
- <div>
54
- {typeof user.online === 'boolean' &&
55
- (<span className={userActiveStatusClasses} title={user.online ? wording.online : wording.offline}/>)}
56
- {user.login}
57
- </div>
58
- {user.email && <div>{user.email}</div>}
74
+ <div className={styles.userLogin}>{user.login}</div>
75
+ {user.email && (<span className={styles.userEmailWrapper}>
76
+ <Link pseudo onClick={this.copyEmail} className={styles.userEmail}>
77
+ {user.email}
78
+ </Link>
79
+ {user.unverifiedEmail && (<span className={styles.unverifiedLabel}>{wording.unverified}</span>)}
80
+ <Icon title={wording.copyToClipboard} className={styles.userCopyIcon} onClick={this.copyEmail} glyph={copyIcon} size={IconSize.Size14} suppressSizeWarning/>
81
+ </span>)}
82
+ {children}
59
83
  </div>
60
84
  </div>
61
- {children}
62
85
  </div>);
63
86
  }
64
87
  }
@@ -6,7 +6,7 @@ export interface UserCardTooltipProps extends Omit<UserCardAttrs, 'user'> {
6
6
  user?: UserCardUser | null | undefined;
7
7
  children: ReactElement | readonly ReactElement[] | string;
8
8
  dropdownProps: Partial<DropdownAttrs>;
9
- renderUserCard: (props: UserCardTooltipProps) => ReactNode;
9
+ renderUserCard: (props: UserCardAttrs) => ReactNode;
10
10
  renderNoUser: () => ReactNode;
11
11
  }
12
12
  export default class UserCardTooltip extends Component<UserCardTooltipProps> {
@@ -19,7 +19,7 @@ export default class UserCardTooltip extends Component<UserCardTooltipProps> {
19
19
  renderNoUser: PropTypes.Requireable<(...args: any[]) => any>;
20
20
  };
21
21
  static defaultProps: {
22
- renderUserCard: (props: UserCardTooltipProps) => JSX.Element | null | undefined;
22
+ renderUserCard: (props: UserCardAttrs) => JSX.Element;
23
23
  renderNoUser: () => string;
24
24
  dropdownProps: {
25
25
  hoverShowTimeOut: number;
@@ -17,8 +17,8 @@ export default class UserCardTooltip extends Component {
17
17
  };
18
18
  static defaultProps = {
19
19
  renderUserCard: (props) => {
20
- const { className, children, renderUserCard, renderNoUser, dropdownProps, user, ...restProps } = props;
21
- return user && (<UserCard user={user} {...restProps} className={classNames(styles.userCardSpaced, className)}/>);
20
+ const { user, ...restProps } = props;
21
+ return user && (<UserCard user={user} {...restProps}/>);
22
22
  },
23
23
  renderNoUser: () => '',
24
24
  dropdownProps: {
@@ -27,10 +27,16 @@ export default class UserCardTooltip extends Component {
27
27
  }
28
28
  };
29
29
  render() {
30
- const { children, user, renderUserCard, renderNoUser, dropdownProps } = this.props;
30
+ const { children, renderUserCard, renderNoUser, dropdownProps, user, ...restProps } = this.props;
31
31
  return (<Dropdown anchor={children} hoverMode clickMode={false} {...dropdownProps}>
32
32
  <Popup attached={false}>
33
- {user ? renderUserCard(this.props) : renderNoUser()}
33
+ {user
34
+ ? renderUserCard({
35
+ ...restProps,
36
+ user,
37
+ className: classNames(styles.userCardSpaced, this.props.className)
38
+ })
39
+ : renderNoUser()}
34
40
  </Popup>
35
41
  </Dropdown>);
36
42
  }
@@ -8,7 +8,13 @@
8
8
 
9
9
  .userInformationContainer {
10
10
  display: flex;
11
- align-items: center;
11
+ align-items: flex-start;
12
+ }
13
+
14
+ .userAvatar {
15
+ position: relative;
16
+
17
+ display: flex;
12
18
  }
13
19
 
14
20
  .userInformation {
@@ -22,20 +28,70 @@
22
28
  line-height: 18px;
23
29
  }
24
30
 
31
+ .userNameLine {
32
+ height: var(--ring-line-height-lowest);
33
+
34
+ white-space: nowrap;
35
+
36
+ line-height: var(--ring-line-height-lowest);
37
+ }
38
+
25
39
  .userName {
26
40
  display: inline-block;
27
41
 
28
42
  margin-right: 4px;
29
- margin-bottom: 3px;
30
43
 
31
44
  font-size: 16px;
32
45
  font-weight: 600;
33
46
  }
34
47
 
48
+ .userLogin {
49
+ margin-bottom: 7px;
50
+
51
+ color: var(--ring-secondary-color);
52
+
53
+ font-size: var(--ring-font-size-smaller);
54
+ }
55
+
56
+ .userEmail {
57
+ margin-right: 4px;
58
+
59
+ font-size: var(--ring-font-size);
60
+ }
61
+
62
+ .userCopyIcon {
63
+ cursor: pointer;
64
+
65
+ opacity: 0;
66
+ }
67
+
68
+ .userCopyIcon svg {
69
+ margin-left: 4px;
70
+
71
+ color: var(--ring-link-hover-color);
72
+ }
73
+
74
+ .userEmailWrapper:hover .userCopyIcon {
75
+ transition: opacity 300ms ease-out;
76
+
77
+ opacity: 1;
78
+ }
79
+
80
+ .userEmailWrapper:hover .userEmail {
81
+ color: var(--ring-link-hover-color);
82
+ }
83
+
84
+ .unverifiedLabel {
85
+ margin: 0 4px;
86
+
87
+ color: var(--ring-secondary-color);
88
+
89
+ font-size: var(--ring-font-size-smaller);
90
+ }
91
+
35
92
  .userNameInfo {
36
93
  display: inline-block;
37
94
 
38
- margin-right: 4px;
39
95
  margin-bottom: 3px;
40
96
  }
41
97
 
@@ -44,8 +100,8 @@
44
100
 
45
101
  width: unit;
46
102
  height: unit;
47
-
48
- margin-right: 4px;
103
+ margin-right: var(--ring-unit);
104
+ margin-left: 6px;
49
105
 
50
106
  border-radius: 50%;
51
107
  background-color: var(--ring-icon-secondary-color);
@@ -2,13 +2,27 @@ import { _ as _defineProperty, a as _extends } from './_rollupPluginBabelHelpers
2
2
  import React, { PureComponent } from 'react';
3
3
  import PropTypes from 'prop-types';
4
4
  import classNames from 'classnames';
5
+ import copyIcon from '@jetbrains/icons/copy';
5
6
  import Avatar, { Size } from '../avatar/avatar.js';
6
7
  import Link from '../link/link.js';
8
+ import clipboard from '../clipboard/clipboard.js';
7
9
  import { m as modules_6c9187df } from './badge.js';
10
+ import Icon from '../icon/icon.js';
11
+ import { Size as Size$1 } from '../icon/icon__constants.js';
8
12
 
9
- var modules_a4196c17 = {"unit":"8px","light":"light_rui_6e59","userCardSpaced":"userCardSpaced_rui_6e59","userInformationContainer":"userInformationContainer_rui_6e59","userInformation":"userInformation_rui_6e59","userName":"userName_rui_6e59","userNameInfo":"userNameInfo_rui_6e59","userActiveStatus":"userActiveStatus_rui_6e59","online":"online_rui_6e59"};
13
+ var modules_a4196c17 = {"unit":"8px","light":"light_rui_6e59","userCardSpaced":"userCardSpaced_rui_6e59","userInformationContainer":"userInformationContainer_rui_6e59","userAvatar":"userAvatar_rui_6e59","userInformation":"userInformation_rui_6e59","userNameLine":"userNameLine_rui_6e59","userName":"userName_rui_6e59","userLogin":"userLogin_rui_6e59","userEmail":"userEmail_rui_6e59","userCopyIcon":"userCopyIcon_rui_6e59","userEmailWrapper":"userEmailWrapper_rui_6e59","unverifiedLabel":"unverifiedLabel_rui_6e59","userNameInfo":"userNameInfo_rui_6e59","userActiveStatus":"userActiveStatus_rui_6e59","online":"online_rui_6e59"};
10
14
 
11
15
  class UserCard extends PureComponent {
16
+ constructor() {
17
+ super(...arguments);
18
+ _defineProperty(this, "copyEmail", () => {
19
+ const {
20
+ user,
21
+ wording
22
+ } = this.props;
23
+ clipboard.copyText(user.email || '', wording.copiedToClipboard, wording.copingToClipboardError);
24
+ });
25
+ }
12
26
  render() {
13
27
  const {
14
28
  children,
@@ -16,6 +30,7 @@ class UserCard extends PureComponent {
16
30
  className,
17
31
  user,
18
32
  wording,
33
+ avatarInfo,
19
34
  ...restProps
20
35
  } = this.props;
21
36
  const classes = classNames(className, {});
@@ -24,25 +39,46 @@ class UserCard extends PureComponent {
24
39
  className: classes
25
40
  }, restProps), /*#__PURE__*/React.createElement("div", {
26
41
  className: modules_a4196c17.userInformationContainer
42
+ }, /*#__PURE__*/React.createElement("div", {
43
+ className: modules_a4196c17.userAvatar
27
44
  }, /*#__PURE__*/React.createElement(Avatar, {
28
45
  size: Size.Size56,
29
46
  url: user.avatarUrl
30
- }), /*#__PURE__*/React.createElement("div", {
47
+ }), !!avatarInfo && avatarInfo), /*#__PURE__*/React.createElement("div", {
31
48
  className: modules_a4196c17.userInformation
32
- }, /*#__PURE__*/React.createElement("div", null, user.href && /*#__PURE__*/React.createElement(Link, {
49
+ }, /*#__PURE__*/React.createElement("div", {
50
+ className: modules_a4196c17.userNameLine
51
+ }, user.href && /*#__PURE__*/React.createElement(Link, {
33
52
  href: user.href,
34
53
  className: modules_a4196c17.userName
35
54
  }, user.name), !user.href && /*#__PURE__*/React.createElement("span", {
36
55
  className: modules_a4196c17.userName
37
- }, user.name), !!info && /*#__PURE__*/React.createElement("span", {
56
+ }, user.name), typeof user.online === 'boolean' && /*#__PURE__*/React.createElement("span", {
57
+ className: userActiveStatusClasses,
58
+ title: user.online ? wording.online : wording.offline
59
+ }), !!info && /*#__PURE__*/React.createElement("span", {
38
60
  className: modules_a4196c17.userNameInfo
39
61
  }, info), user.banned && /*#__PURE__*/React.createElement("span", {
40
62
  className: classNames(modules_6c9187df.badge, modules_6c9187df.invalid),
41
63
  title: user.banReason
42
- }, wording.banned)), /*#__PURE__*/React.createElement("div", null, typeof user.online === 'boolean' && /*#__PURE__*/React.createElement("span", {
43
- className: userActiveStatusClasses,
44
- title: user.online ? wording.online : wording.offline
45
- }), user.login), user.email && /*#__PURE__*/React.createElement("div", null, user.email))), children);
64
+ }, wording.banned)), /*#__PURE__*/React.createElement("div", {
65
+ className: modules_a4196c17.userLogin
66
+ }, user.login), user.email && /*#__PURE__*/React.createElement("span", {
67
+ className: modules_a4196c17.userEmailWrapper
68
+ }, /*#__PURE__*/React.createElement(Link, {
69
+ pseudo: true,
70
+ onClick: this.copyEmail,
71
+ className: modules_a4196c17.userEmail
72
+ }, user.email), user.unverifiedEmail && /*#__PURE__*/React.createElement("span", {
73
+ className: modules_a4196c17.unverifiedLabel
74
+ }, wording.unverified), /*#__PURE__*/React.createElement(Icon, {
75
+ title: wording.copyToClipboard,
76
+ className: modules_a4196c17.userCopyIcon,
77
+ onClick: this.copyEmail,
78
+ glyph: copyIcon,
79
+ size: Size$1.Size14,
80
+ suppressSizeWarning: true
81
+ })), children)));
46
82
  }
47
83
  }
48
84
  _defineProperty(UserCard, "propTypes", {
@@ -57,19 +93,28 @@ _defineProperty(UserCard, "propTypes", {
57
93
  href: PropTypes.string,
58
94
  online: PropTypes.bool,
59
95
  banned: PropTypes.bool,
60
- banReason: PropTypes.string
96
+ banReason: PropTypes.string,
97
+ unverifiedEmail: PropTypes.bool
61
98
  }).isRequired,
62
99
  wording: PropTypes.shape({
63
100
  banned: PropTypes.string.isRequired,
64
101
  online: PropTypes.string.isRequired,
65
- offline: PropTypes.string.isRequired
102
+ offline: PropTypes.string.isRequired,
103
+ copyToClipboard: PropTypes.string.isRequired,
104
+ copiedToClipboard: PropTypes.string.isRequired,
105
+ copingToClipboardError: PropTypes.string.isRequired,
106
+ unverified: PropTypes.string
66
107
  })
67
108
  });
68
109
  _defineProperty(UserCard, "defaultProps", {
69
110
  wording: {
70
111
  banned: 'banned',
71
112
  online: 'online',
72
- offline: 'offline'
113
+ offline: 'offline',
114
+ copyToClipboard: 'Copy to clipboard',
115
+ copiedToClipboard: 'Email was copied to clipboard',
116
+ copingToClipboardError: 'Failed to copy to clipboard',
117
+ unverified: 'Unverified'
73
118
  }
74
119
  });
75
120
 
@@ -0,0 +1,2 @@
1
+ export declare function copyTextToClipboard(str: string): void;
2
+ export declare function copyHTMLToClipboard(str: string): void;
@@ -0,0 +1,42 @@
1
+ function copyTextToClipboard(str) {
2
+ const el = document.createElement('textarea');
3
+ el.value = str;
4
+ el.setAttribute('readonly', '');
5
+ el.style.position = 'absolute';
6
+ el.style.left = '-9999px';
7
+ document.body.appendChild(el);
8
+ const selection = document.getSelection();
9
+ // Should restore previous selection
10
+ const selected = selection && selection.rangeCount > 0 ? selection.getRangeAt(0) : false;
11
+ el.select();
12
+ document.execCommand('copy');
13
+ document.body.removeChild(el);
14
+ if (selected && selection) {
15
+ selection.removeAllRanges();
16
+ selection.addRange(selected);
17
+ }
18
+ }
19
+ function copyHTMLToClipboard(str) {
20
+ const el = document.createElement('div');
21
+ el.innerHTML = str;
22
+ el.setAttribute('readonly', '');
23
+ el.style.position = 'absolute';
24
+ el.style.left = '-9999px';
25
+ document.body.appendChild(el);
26
+ const selection = document.getSelection();
27
+ // Should restore previous selection
28
+ const selected = selection && selection.rangeCount > 0 ? selection.getRangeAt(0) : false;
29
+ selection?.removeAllRanges();
30
+ const range = document.createRange();
31
+ range.selectNode(el);
32
+ selection?.addRange(range);
33
+ document.execCommand('copy');
34
+ selection?.removeAllRanges();
35
+ document.execCommand('copy');
36
+ document.body.removeChild(el);
37
+ if (selected && selection) {
38
+ selection.addRange(selected);
39
+ }
40
+ }
41
+
42
+ export { copyHTMLToClipboard, copyTextToClipboard };
@@ -0,0 +1,5 @@
1
+ declare const clipboard: {
2
+ copyText: (text: string, successMessage?: string | undefined, errorMessage?: string | undefined, delay?: number) => Promise<void>;
3
+ copyHTML: (html: string, successMessage?: string | undefined, errorMessage?: string | undefined, delay?: number) => Promise<void>;
4
+ };
5
+ export default clipboard;
@@ -0,0 +1,91 @@
1
+ import alertService from '../alert-service/alert-service.js';
2
+ import { copyTextToClipboard, copyHTMLToClipboard } from './clipboard-fallback.js';
3
+ import '../_helpers/_rollupPluginBabelHelpers.js';
4
+ import 'react';
5
+ import '../global/react-render-adapter.js';
6
+ import 'react-dom';
7
+ import '../global/get-uid.js';
8
+ import '../alert/alert.js';
9
+ import 'classnames';
10
+ import 'prop-types';
11
+ import '@jetbrains/icons/exception';
12
+ import '@jetbrains/icons/checkmark';
13
+ import '@jetbrains/icons/warning';
14
+ import '@jetbrains/icons/close';
15
+ import '../icon/icon.js';
16
+ import 'util-deprecate';
17
+ import '../icon/icon__constants.js';
18
+ import '../_helpers/icon.js';
19
+ import '../icon/icon__svg.js';
20
+ import '../global/memoize.js';
21
+ import '../loader-inline/loader-inline.js';
22
+ import '../global/data-tests.js';
23
+ import '../_helpers/loader-inline.js';
24
+ import '../global/dom.js';
25
+ import '../button/button.js';
26
+ import 'focus-visible';
27
+ import '@jetbrains/icons/chevron-10px';
28
+ import '../link/clickableLink.js';
29
+ import '../global/controls-height.js';
30
+ import '../_helpers/button__classes.js';
31
+ import '../_helpers/theme.js';
32
+ import '../popup/popup.target.js';
33
+ import '../popup/popup.js';
34
+ import '../global/schedule-raf.js';
35
+ import '../shortcuts/shortcuts.js';
36
+ import '../shortcuts/core.js';
37
+ import 'combokeys';
38
+ import '../global/sniffer.js';
39
+ import 'sniffr';
40
+ import '../tab-trap/tab-trap.js';
41
+ import '../popup/position.js';
42
+ import '../popup/popup.consts.js';
43
+ import '../alert/container.js';
44
+
45
+ const ALERT_DELAY = 1000;
46
+ function getClipboardImplementation() {
47
+ if (navigator.clipboard && !window.isSecureContext) {
48
+ return {
49
+ copy: text => navigator.clipboard.writeText(text),
50
+ copyHTML: html => navigator.clipboard.write([new ClipboardItem({
51
+ ['text/html']: new Blob([html], {
52
+ type: 'text/html'
53
+ })
54
+ })])
55
+ };
56
+ }
57
+ return {
58
+ copy: str => Promise.resolve(copyTextToClipboard(str)),
59
+ copyHTML: html => Promise.resolve(copyHTMLToClipboard(html))
60
+ };
61
+ }
62
+ async function copy(text, successMessage, errorMessage) {
63
+ let delay = arguments.length > 3 && arguments[3] !== undefined ? arguments[3] : ALERT_DELAY;
64
+ let isHtml = arguments.length > 4 && arguments[4] !== undefined ? arguments[4] : false;
65
+ try {
66
+ const clipboardImpl = getClipboardImplementation();
67
+ const copyMethod = isHtml ? clipboardImpl.copyHTML : clipboardImpl.copy;
68
+ await copyMethod(text);
69
+ if (successMessage) {
70
+ alertService.successMessage(successMessage, delay);
71
+ }
72
+ } catch (e) {
73
+ if (errorMessage) {
74
+ alertService.error(errorMessage, delay);
75
+ }
76
+ // eslint-disable-next-line no-console
77
+ console.error(e);
78
+ }
79
+ }
80
+ const clipboard = {
81
+ copyText: async function (text, successMessage, errorMessage) {
82
+ let delay = arguments.length > 3 && arguments[3] !== undefined ? arguments[3] : ALERT_DELAY;
83
+ return await copy(text, successMessage, errorMessage, delay);
84
+ },
85
+ copyHTML: async function (html, successMessage, errorMessage) {
86
+ let delay = arguments.length > 3 && arguments[3] !== undefined ? arguments[3] : ALERT_DELAY;
87
+ return await copy(html, successMessage, errorMessage, delay, true);
88
+ }
89
+ };
90
+
91
+ export { clipboard as default };