@jetbrains/ring-ui 5.0.136 → 5.0.138

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (193) hide show
  1. package/components/auth/auth__core.d.ts +1 -1
  2. package/components/auth/auth__core.js +21 -26
  3. package/components/auth-dialog/auth-dialog.js +3 -1
  4. package/components/button/button.css +7 -7
  5. package/components/button/button.d.ts +0 -1
  6. package/components/button/button.js +0 -1
  7. package/components/button-group/button-group.css +2 -2
  8. package/components/button-group/button-group.d.ts +0 -1
  9. package/components/button-group/button-group.js +0 -1
  10. package/components/button-group-ng/button-group-ng.js +0 -1
  11. package/components/button-ng/button-ng.js +0 -1
  12. package/components/checkbox/checkbox.css +1 -1
  13. package/components/checkbox/checkbox.d.ts +0 -1
  14. package/components/checkbox/checkbox.js +0 -1
  15. package/components/checkbox-ng/checkbox-ng.js +0 -1
  16. package/components/date-picker/date-input.js +3 -1
  17. package/components/editable-heading/editable-heading.css +7 -3
  18. package/components/editable-heading/editable-heading.js +29 -8
  19. package/components/global/react-render-adapter.js +16 -31
  20. package/components/header/profile.d.ts +54 -1
  21. package/components/header/profile.js +15 -11
  22. package/components/i18n/README.md +3 -0
  23. package/components/i18n/i18n-context.d.ts +54 -0
  24. package/components/i18n/i18n-context.js +3 -0
  25. package/components/i18n/i18n.d.ts +56 -0
  26. package/components/i18n/i18n.js +8 -0
  27. package/components/i18n/messages.json +53 -0
  28. package/components/input/input.d.ts +1 -4
  29. package/components/input/input.js +16 -16
  30. package/components/island/island.css +1 -1
  31. package/components/island/island.d.ts +0 -1
  32. package/components/island/island.js +0 -1
  33. package/components/island-ng/island-ng.js +0 -1
  34. package/components/link/link.css +1 -1
  35. package/components/link/link.d.ts +0 -1
  36. package/components/link/link.js +0 -1
  37. package/components/link-ng/link-ng.js +0 -1
  38. package/components/message/message.d.ts +1 -5
  39. package/components/message/message.js +15 -16
  40. package/components/pager/pager.d.ts +54 -8
  41. package/components/pager/pager.js +10 -12
  42. package/components/query-assist/query-assist.d.ts +1 -5
  43. package/components/query-assist/query-assist.js +30 -29
  44. package/components/select/select.css +2 -2
  45. package/components/select/select.d.ts +2 -5
  46. package/components/select/select.js +14 -12
  47. package/components/select/select__filter.d.ts +0 -1
  48. package/components/select/select__filter.js +4 -2
  49. package/components/tabs/dumb-tabs.d.ts +0 -1
  50. package/components/tabs/dumb-tabs.js +0 -1
  51. package/components/tabs/tabs.css +1 -1
  52. package/components/tabs-ng/tabs-ng.js +0 -1
  53. package/components/tag/tag.css +3 -3
  54. package/components/tag/tag.d.ts +0 -1
  55. package/components/tag/tag.js +0 -1
  56. package/components/user-agreement/user-agreement.d.ts +1 -9
  57. package/components/user-agreement/user-agreement.js +31 -30
  58. package/components/user-card/card.d.ts +65 -13
  59. package/components/user-card/card.js +19 -22
  60. package/dist/_helpers/card.js +19 -28
  61. package/dist/_helpers/select__filter.js +14 -10
  62. package/dist/alert/alert.js +0 -1
  63. package/dist/alert-service/alert-service.js +0 -1
  64. package/dist/auth/auth.js +1 -1
  65. package/dist/auth/auth__core.d.ts +1 -1
  66. package/dist/auth/auth__core.js +19 -28
  67. package/dist/auth/down-notification.js +0 -1
  68. package/dist/auth/iframe-flow.js +0 -1
  69. package/dist/auth/landing.js +1 -1
  70. package/dist/auth/storage.js +0 -1
  71. package/dist/auth-dialog/auth-dialog.js +1 -2
  72. package/dist/auth-dialog-service/auth-dialog-service.js +0 -1
  73. package/dist/auth-ng/auth-ng.js +1 -1
  74. package/dist/avatar-editor-ng/avatar-editor-ng.js +0 -1
  75. package/dist/breadcrumb-ng/breadcrumb-ng.js +0 -1
  76. package/dist/button/button.d.ts +0 -1
  77. package/dist/button/button.js +0 -1
  78. package/dist/button-group/button-group.d.ts +0 -1
  79. package/dist/button-group/button-group.js +0 -1
  80. package/dist/button-group-ng/button-group-ng.js +0 -1
  81. package/dist/button-ng/button-ng.js +0 -1
  82. package/dist/checkbox/checkbox.d.ts +0 -1
  83. package/dist/checkbox/checkbox.js +0 -1
  84. package/dist/checkbox-ng/checkbox-ng.js +0 -1
  85. package/dist/clipboard/clipboard.js +0 -1
  86. package/dist/confirm/confirm.js +0 -1
  87. package/dist/confirm-ng/confirm-ng.js +0 -1
  88. package/dist/confirm-service/confirm-service.js +0 -1
  89. package/dist/data-list/data-list.js +0 -1
  90. package/dist/data-list/data-list.mock.js +0 -1
  91. package/dist/data-list/item.js +0 -1
  92. package/dist/data-list/title.js +0 -1
  93. package/dist/data-list-ng/data-list-ng.js +0 -1
  94. package/dist/date-picker/date-input.js +3 -2
  95. package/dist/date-picker/date-picker.js +2 -1
  96. package/dist/date-picker/date-popup.js +2 -1
  97. package/dist/dialog/dialog.js +0 -1
  98. package/dist/dialog-ng/dialog-ng.js +0 -1
  99. package/dist/dropdown/anchor.js +0 -1
  100. package/dist/dropdown/dropdown.js +0 -1
  101. package/dist/dropdown-menu/dropdown-menu.js +0 -1
  102. package/dist/editable-heading/editable-heading.js +32 -10
  103. package/dist/error-message-ng/error-message-ng.js +0 -1
  104. package/dist/footer/footer.js +0 -1
  105. package/dist/footer-ng/footer-ng.js +0 -1
  106. package/dist/global/react-render-adapter.js +0 -2
  107. package/dist/header/header.js +2 -1
  108. package/dist/header/profile.d.ts +54 -1
  109. package/dist/header/profile.js +22 -16
  110. package/dist/header/services-link.js +0 -1
  111. package/dist/header/services.js +0 -1
  112. package/dist/header/smart-profile.js +2 -1
  113. package/dist/header/smart-services.js +1 -1
  114. package/dist/header/tray-icon.js +0 -1
  115. package/dist/i18n/i18n-context.d.ts +54 -0
  116. package/dist/i18n/i18n-context.js +6 -0
  117. package/dist/i18n/i18n.d.ts +56 -0
  118. package/dist/i18n/i18n.js +114 -0
  119. package/dist/input/input.d.ts +1 -4
  120. package/dist/input/input.js +6 -8
  121. package/dist/input-ng/input-ng.js +0 -1
  122. package/dist/island/island.d.ts +0 -1
  123. package/dist/island/island.js +0 -1
  124. package/dist/island-ng/island-ng.js +0 -1
  125. package/dist/link/link.d.ts +0 -1
  126. package/dist/link/link.js +0 -1
  127. package/dist/link-ng/link-ng.js +0 -1
  128. package/dist/list/list.js +0 -1
  129. package/dist/list/list__item.js +0 -1
  130. package/dist/list/list__link.js +0 -1
  131. package/dist/list/list__users-groups-source.js +0 -1
  132. package/dist/login-dialog/login-dialog.js +0 -1
  133. package/dist/login-dialog/service.js +0 -1
  134. package/dist/markdown/link.js +0 -1
  135. package/dist/markdown/markdown.js +0 -1
  136. package/dist/message/message.d.ts +1 -5
  137. package/dist/message/message.js +5 -8
  138. package/dist/pager/pager.d.ts +54 -8
  139. package/dist/pager/pager.js +19 -16
  140. package/dist/pager-ng/pager-ng.js +2 -1
  141. package/dist/permissions-ng/permissions-ng.js +1 -1
  142. package/dist/popup-menu/popup-menu.js +0 -1
  143. package/dist/promised-click-ng/promised-click-ng.js +0 -1
  144. package/dist/query-assist/query-assist.d.ts +1 -5
  145. package/dist/query-assist/query-assist.js +22 -20
  146. package/dist/query-assist/query-assist__suggestions.js +0 -1
  147. package/dist/query-assist-ng/query-assist-ng.js +2 -1
  148. package/dist/save-field-ng/save-field-ng.js +0 -1
  149. package/dist/select/select.d.ts +2 -5
  150. package/dist/select/select.js +49 -46
  151. package/dist/select/select__filter.d.ts +0 -1
  152. package/dist/select/select__filter.js +2 -1
  153. package/dist/select/select__popup.js +2 -1
  154. package/dist/select-ng/select-ng.js +2 -1
  155. package/dist/select-ng/select-ng__lazy.js +2 -1
  156. package/dist/shortcuts-hint-ng/shortcuts-hint-ng.js +0 -1
  157. package/dist/sidebar-ng/sidebar-ng.js +0 -1
  158. package/dist/storage/storage.js +0 -1
  159. package/dist/storage/storage__local.js +0 -1
  160. package/dist/style.css +1 -1
  161. package/dist/table/header.js +0 -1
  162. package/dist/table/row-with-focus-sensor.js +0 -1
  163. package/dist/table/row.js +0 -1
  164. package/dist/table/smart-table.js +0 -1
  165. package/dist/table/table.js +0 -1
  166. package/dist/table-legacy-ng/table-legacy-ng.js +2 -1
  167. package/dist/table-legacy-ng/table-legacy-ng__pager.js +2 -1
  168. package/dist/table-ng/smart-table-ng.js +0 -1
  169. package/dist/table-ng/table-ng.js +0 -1
  170. package/dist/tabs/collapsible-more.js +0 -1
  171. package/dist/tabs/collapsible-tab.js +0 -1
  172. package/dist/tabs/collapsible-tabs.js +0 -1
  173. package/dist/tabs/dumb-tabs.d.ts +0 -1
  174. package/dist/tabs/dumb-tabs.js +0 -1
  175. package/dist/tabs/smart-tabs.js +0 -1
  176. package/dist/tabs/tab-link.js +0 -1
  177. package/dist/tabs/tabs.js +0 -1
  178. package/dist/tabs-ng/tabs-ng.js +0 -1
  179. package/dist/tag/tag.d.ts +0 -1
  180. package/dist/tag/tag.js +0 -1
  181. package/dist/tags-input/tags-input.js +2 -1
  182. package/dist/tags-input-ng/tags-input-ng.js +2 -1
  183. package/dist/tags-list/tags-list.js +0 -1
  184. package/dist/user-agreement/service.js +2 -1
  185. package/dist/user-agreement/user-agreement.d.ts +1 -9
  186. package/dist/user-agreement/user-agreement.js +11 -18
  187. package/dist/user-card/card.d.ts +65 -13
  188. package/dist/user-card/card.js +2 -1
  189. package/dist/user-card/smart-user-card-tooltip.js +2 -1
  190. package/dist/user-card/tooltip.js +2 -1
  191. package/dist/user-card/user-card.js +2 -1
  192. package/dist/user-card-ng/user-card-ng.js +2 -1
  193. package/package.json +37 -38
@@ -77,7 +77,7 @@ export interface AuthConfig extends TokenValidatorConfig {
77
77
  checkBackendIsUp: () => Promise<unknown>;
78
78
  onBackendDown: (params: BackendDownParams) => () => void;
79
79
  defaultExpiresIn: number;
80
- translations: AuthTranslations;
80
+ translations?: AuthTranslations | null | undefined;
81
81
  userParams?: RequestParams | undefined;
82
82
  waitForRedirectTimeout: number;
83
83
  }
@@ -2,6 +2,7 @@ import { fixUrl, getAbsoluteBaseURL } from '../global/url';
2
2
  import Listeners from '../global/listeners';
3
3
  import HTTP from '../http/http';
4
4
  import promiseWithTimeout from '../global/promise-with-timeout';
5
+ import { getTranslations } from '../i18n/i18n';
5
6
  import AuthStorage from './storage';
6
7
  import AuthResponseParser from './response-parser';
7
8
  import AuthRequestBuilder from './request-builder';
@@ -42,19 +43,7 @@ const DEFAULT_CONFIG = {
42
43
  onBackendDown: () => () => { },
43
44
  defaultExpiresIn: DEFAULT_EXPIRES_TIMEOUT,
44
45
  waitForRedirectTimeout: DEFAULT_WAIT_FOR_REDIRECT_TIMEOUT,
45
- translations: {
46
- login: 'Log in',
47
- loginTo: 'Log in to %serviceName%',
48
- cancel: 'Cancel',
49
- tryAgainLabel: 'Try again',
50
- postpone: 'Postpone',
51
- youHaveLoggedInAs: 'You have logged in as another user: %userName%',
52
- applyChange: 'Apply change',
53
- backendIsNotAvailable: 'Connection lost',
54
- checkAgain: 'try again',
55
- nothingHappensLink: 'Click here if nothing happens',
56
- errorMessage: 'There may be a problem with your network connection. Make sure that you are online and'
57
- }
46
+ translations: null
58
47
  };
59
48
  class Auth {
60
49
  static DEFAULT_CONFIG = DEFAULT_CONFIG;
@@ -131,7 +120,7 @@ class Auth {
131
120
  }
132
121
  this._backgroundFlow = new BackgroundFlow(this._requestBuilder, this._storage, backgroundRefreshTimeout);
133
122
  if (this.config.EmbeddedLoginFlow) {
134
- this._embeddedFlow = new this.config.EmbeddedLoginFlow(this._requestBuilder, this._storage, this.config.translations);
123
+ this._embeddedFlow = new this.config.EmbeddedLoginFlow(this._requestBuilder, this._storage, this.config.translations ?? getTranslations());
135
124
  }
136
125
  const API_BASE = this.config.serverUri + Auth.API_PATH;
137
126
  const fetchConfig = config.fetchCredentials
@@ -491,6 +480,7 @@ class Auth {
491
480
  _showAuthDialog({ nonInteractive, error, canCancel, onTryAgain } = {}) {
492
481
  const { embeddedLogin, onPostponeLogout, translations } = this.config;
493
482
  const cancelable = this.user?.guest || canCancel;
483
+ const actualTranslations = translations ?? getTranslations();
494
484
  this._createInitDeferred();
495
485
  const closeDialog = () => {
496
486
  /* eslint-disable @typescript-eslint/no-use-before-define */
@@ -530,11 +520,11 @@ class Auth {
530
520
  };
531
521
  const hide = this._authDialogService?.({
532
522
  ...this._service,
533
- loginCaption: translations.login,
534
- loginToCaption: translations.loginTo,
535
- confirmLabel: translations.login,
536
- tryAgainLabel: translations.tryAgainLabel,
537
- cancelLabel: cancelable ? translations.cancel : translations.postpone,
523
+ loginCaption: actualTranslations.login,
524
+ loginToCaption: actualTranslations.loginTo,
525
+ confirmLabel: actualTranslations.login,
526
+ tryAgainLabel: actualTranslations.tryAgainLabel,
527
+ cancelLabel: cancelable ? actualTranslations.cancel : actualTranslations.postpone,
538
528
  errorMessage: this._extractErrorMessage(error, true),
539
529
  onConfirm,
540
530
  onCancel,
@@ -550,6 +540,7 @@ class Auth {
550
540
  }
551
541
  _showUserChangedDialog({ newUser, onApply, onPostpone }) {
552
542
  const { translations } = this.config;
543
+ const actualTranslations = translations ?? getTranslations();
553
544
  this._createInitDeferred();
554
545
  const done = () => {
555
546
  this._initDeferred?.resolve?.();
@@ -558,12 +549,14 @@ class Auth {
558
549
  };
559
550
  const hide = this._authDialogService?.({
560
551
  ...this._service,
561
- title: translations.youHaveLoggedInAs.replace('%userName%', newUser.name ?? ''),
562
- loginCaption: translations.login,
563
- loginToCaption: translations.loginTo,
564
- confirmLabel: translations.applyChange,
565
- tryAgainLabel: translations.tryAgainLabel,
566
- cancelLabel: translations.postpone,
552
+ title: actualTranslations.youHaveLoggedInAs.
553
+ replace('%userName%', newUser.name ?? '').
554
+ replace('{{userName}}', newUser.name ?? ''),
555
+ loginCaption: actualTranslations.login,
556
+ loginToCaption: actualTranslations.loginTo,
557
+ confirmLabel: actualTranslations.applyChange,
558
+ tryAgainLabel: actualTranslations.tryAgainLabel,
559
+ cancelLabel: actualTranslations.postpone,
567
560
  onConfirm: () => {
568
561
  done();
569
562
  onApply();
@@ -623,7 +616,9 @@ class Auth {
623
616
  done();
624
617
  reject(new Error('Auth(@jetbrains/ring-ui): postponed by user'));
625
618
  };
626
- const hide = onBackendDown({ onCheckAgain, onPostpone, backendError, translations });
619
+ const hide = onBackendDown({
620
+ onCheckAgain, onPostpone, backendError, translations: translations ?? getTranslations()
621
+ });
627
622
  window.addEventListener('online', onCheckAgain);
628
623
  function networkWatchdog() {
629
624
  if (navigator && navigator.onLine) {
@@ -68,7 +68,9 @@ class AuthDialog extends Component {
68
68
  const { show, className, errorMessage, serviceImage, serviceName, loginCaption, loginToCaption, confirmLabel, cancelLabel, tryAgainLabel, onConfirm, onCancel, onTryAgain } = this.props;
69
69
  const { retrying } = this.state;
70
70
  const defaultTitle = serviceName ? loginToCaption : loginCaption;
71
- const title = (this.props.title || defaultTitle).replace('%serviceName%', serviceName ?? '');
71
+ const title = (this.props.title || defaultTitle).
72
+ replace('%serviceName%', serviceName ?? '').
73
+ replace('{{serviceName}}', serviceName ?? '');
72
74
  return (<Dialog label={title} data-test="ring-auth-dialog" className={className} contentClassName={classNames(className, styles.dialog)} onEscPress={this.onEscPress} show={show} trapFocus>
73
75
  <Content>
74
76
  <div className={styles.content}>
@@ -60,7 +60,7 @@
60
60
  box-shadow: button-shadow var(--ring-border-hover-color);
61
61
  }
62
62
 
63
- &:global(.focus-visible) {
63
+ &:focus-visible {
64
64
  transition: none;
65
65
 
66
66
  box-shadow: button-shadow var(--ring-border-hover-color), 0 0 0 1px var(--ring-border-hover-color);
@@ -73,7 +73,7 @@
73
73
  box-shadow: button-shadow var(--ring-main-color);
74
74
  }
75
75
 
76
- &:global(.focus-visible).active {
76
+ &:focus-visible.active {
77
77
  box-shadow: inset 0 0 0 2px var(--ring-main-color), 0 0 0 1px var(--ring-border-hover-color);
78
78
  }
79
79
 
@@ -128,7 +128,7 @@
128
128
  color: var(--ring-action-link-color);
129
129
  }
130
130
 
131
- &:global(.focus-visible),
131
+ &:focus-visible,
132
132
  &:active,
133
133
  &.active {
134
134
  background-color: var(--ring-button-primary-background-color);
@@ -186,12 +186,12 @@
186
186
 
187
187
  &:active,
188
188
  &.active,
189
- &:global(.focus-visible),
189
+ &:focus-visible,
190
190
  &:hover {
191
191
  box-shadow: button-shadow var(--ring-button-danger-hover-color);
192
192
  }
193
193
 
194
- &:global(.focus-visible),
194
+ &:focus-visible,
195
195
  &:hover {
196
196
  transition: none;
197
197
  }
@@ -212,7 +212,7 @@
212
212
  box-shadow: none;
213
213
  }
214
214
 
215
- &:global(.focus-visible) {
215
+ &:focus-visible {
216
216
  box-shadow: inset 0 0 0 2px var(--ring-border-hover-color);
217
217
  }
218
218
  }
@@ -228,7 +228,7 @@
228
228
  box-shadow: none;
229
229
  }
230
230
 
231
- .withIcon:hover:not(:global(.focus-visible)) {
231
+ .withIcon:hover:not(:focus-visible) {
232
232
  background-color: transparent;
233
233
  box-shadow: none;
234
234
  }
@@ -1,4 +1,3 @@
1
- import 'focus-visible';
2
1
  import React, { PureComponent, ButtonHTMLAttributes } from 'react';
3
2
  import PropTypes from 'prop-types';
4
3
  import { IconProps, IconType, Size } from '../icon/icon';
@@ -1,4 +1,3 @@
1
- import 'focus-visible';
2
1
  import React, { createRef, PureComponent } from 'react';
3
2
  import PropTypes from 'prop-types';
4
3
  import classNames from 'classnames';
@@ -111,7 +111,7 @@
111
111
  }
112
112
 
113
113
  /* stylelint-disable-next-line selector-max-specificity */
114
- .buttonGroup .button.button:global(.focus-visible) {
114
+ .buttonGroup .button.button:focus-visible {
115
115
  border-radius: var(--ring-border-radius);
116
116
  box-shadow: button-shadow var(--ring-border-hover-color), 0 0 0 1px var(--ring-border-hover-color);
117
117
  }
@@ -123,7 +123,7 @@
123
123
  }
124
124
 
125
125
  /* stylelint-disable-next-line selector-max-specificity */
126
- .buttonGroup .button:global(.focus-visible).active {
126
+ .buttonGroup .button:focus-visible.active {
127
127
  border-radius: var(--ring-border-radius);
128
128
  box-shadow: button-shadow var(--ring-main-color), 0 0 0 1px var(--ring-border-hover-color);
129
129
  }
@@ -1,4 +1,3 @@
1
- import 'focus-visible';
2
1
  import { PureComponent, HTMLAttributes } from 'react';
3
2
  import PropTypes from 'prop-types';
4
3
  import Caption from './caption';
@@ -1,4 +1,3 @@
1
- import 'focus-visible';
2
1
  import React, { PureComponent } from 'react';
3
2
  import PropTypes from 'prop-types';
4
3
  import classNames from 'classnames';
@@ -1,4 +1,3 @@
1
- import 'focus-visible';
2
1
  import angular from 'angular';
3
2
 
4
3
  import classNames from 'classnames';
@@ -1,4 +1,3 @@
1
- import 'focus-visible';
2
1
  import angular from 'angular';
3
2
 
4
3
  import classNames from 'classnames';
@@ -92,7 +92,7 @@
92
92
  opacity: 1;
93
93
  }
94
94
 
95
- &:global(.focus-visible) + .cell,
95
+ &:focus-visible + .cell,
96
96
  &.focus + .cell {
97
97
  transition: background-color var(--ring-ease);
98
98
 
@@ -1,4 +1,3 @@
1
- import 'focus-visible';
2
1
  import { PureComponent, InputHTMLAttributes, CSSProperties, Ref } from 'react';
3
2
  import PropTypes from 'prop-types';
4
3
  export interface CheckboxProps extends InputHTMLAttributes<HTMLInputElement> {
@@ -1,4 +1,3 @@
1
- import 'focus-visible';
2
1
  import React, { PureComponent } from 'react';
3
2
  import PropTypes from 'prop-types';
4
3
  import classNames from 'classnames';
@@ -1,4 +1,3 @@
1
- import 'focus-visible';
2
1
  import angular from 'angular';
3
2
 
4
3
  import checkmarkIcon from '@jetbrains/icons/checkmark-14px';
@@ -89,7 +89,9 @@ class DateInput extends React.PureComponent {
89
89
  case 'time':
90
90
  return timePlaceholder || translations.addTime;
91
91
  default:
92
- return translations.selectName.replace('%name%', name);
92
+ return translations.selectName.
93
+ replace('%name%', name).
94
+ replace('{{name}}', name);
93
95
  }
94
96
  })();
95
97
  const classes = classNames(styles.filter, styles[`${name}Input`], divider && styles[`${name}InputWithDivider`], 'ring-js-shortcuts');
@@ -22,6 +22,7 @@
22
22
  padding: 0;
23
23
 
24
24
  cursor: pointer;
25
+ user-select: text;
25
26
 
26
27
  text-align: inherit;
27
28
 
@@ -33,7 +34,8 @@
33
34
 
34
35
  font-size: inherit;
35
36
 
36
- @nest .disabled & {
37
+ @nest .disabled &,
38
+ .selectionMode & {
37
39
  user-select: text;
38
40
 
39
41
  border-radius: 0;
@@ -43,7 +45,8 @@
43
45
  outline: 1px solid var(--ring-border-hover-color);
44
46
  }
45
47
 
46
- @nest .disabled &:focus {
48
+ @nest .disabled &:focus,
49
+ .selectionMode &:focus {
47
50
  outline: none;
48
51
  }
49
52
 
@@ -51,7 +54,8 @@
51
54
  background-color: var(--ring-hover-background-color);
52
55
  }
53
56
 
54
- @nest .disabled &:hover {
57
+ @nest .disabled &:hover,
58
+ .selectionMode &:hover {
55
59
  cursor: initial;
56
60
 
57
61
  background-color: initial;
@@ -1,4 +1,4 @@
1
- import React from 'react';
1
+ import React, { useEffect } from 'react';
2
2
  import classNames from 'classnames';
3
3
  import Heading, { Levels } from '../heading/heading';
4
4
  import Button from '../button/button';
@@ -17,6 +17,8 @@ export const EditableHeading = (props) => {
17
17
  }, ...restProps } = props;
18
18
  const [shortcutsScope] = React.useState(getUID('ring-editable-heading-'));
19
19
  const [isInFocus, setIsInFocus] = React.useState(false);
20
+ const [isMouseDown, setIsMouseDown] = React.useState(false);
21
+ const [isInSelectionMode, setIsInSelectionMode] = React.useState(false);
20
22
  const hasError = error !== undefined;
21
23
  const isSaveDisabled = !isSavingPossible || !children || children.trim() === '' || hasError || isSaving;
22
24
  const isCancelDisabled = isSaving;
@@ -36,16 +38,27 @@ export const EditableHeading = (props) => {
36
38
  [styles.isEditing]: isEditing,
37
39
  [styles.error]: hasError,
38
40
  [styles.disabled]: disabled,
39
- [styles.multiline]: multiline
41
+ [styles.multiline]: multiline,
42
+ [styles.selectionMode]: isInSelectionMode
40
43
  });
41
44
  const headingClasses = classNames(styles.heading, headingClassName, styles[`size${size}`]);
42
45
  const inputClasses = classNames('ring-js-shortcuts', styles.input, inputStyles[`size${size}`], styles[`level${level}`], inputClassName);
43
- const onHeadingClick = React.useCallback(() => {
44
- if (disabled) {
45
- return undefined;
46
+ const onHeadingMouseDown = React.useCallback(() => {
47
+ setIsMouseDown(true);
48
+ }, []);
49
+ const onMouseMove = React.useCallback(() => {
50
+ if (!isMouseDown) {
51
+ return;
46
52
  }
47
- return onEdit();
48
- }, [disabled, onEdit]);
53
+ setIsInSelectionMode(true);
54
+ }, [isMouseDown]);
55
+ const onMouseUp = React.useCallback(() => {
56
+ if (isMouseDown && !isInSelectionMode && !disabled) {
57
+ onEdit();
58
+ }
59
+ setIsMouseDown(false);
60
+ setIsInSelectionMode(false);
61
+ }, [isMouseDown, isInSelectionMode, disabled, onEdit]);
49
62
  const onInputFocus = React.useCallback((e) => {
50
63
  setIsInFocus(true);
51
64
  onFocus?.(e);
@@ -54,6 +67,14 @@ export const EditableHeading = (props) => {
54
67
  setIsInFocus(false);
55
68
  onBlur?.(e);
56
69
  }, [onBlur]);
70
+ useEffect(() => {
71
+ window.addEventListener('mousemove', onMouseMove);
72
+ window.addEventListener('mouseup', onMouseUp);
73
+ return () => {
74
+ window.removeEventListener('mousemove', onMouseMove);
75
+ window.removeEventListener('mouseup', onMouseUp);
76
+ };
77
+ });
57
78
  return (<>
58
79
  <div className={classes}>
59
80
  {!disabled && isEditing
@@ -62,7 +83,7 @@ export const EditableHeading = (props) => {
62
83
 
63
84
  <input className={inputClasses} value={children} autoFocus={autoFocus} data-test={dataTest} disabled={isSaving} {...restProps} onFocus={onInputFocus} onBlur={onInputBlur}/>
64
85
  </>)
65
- : (<button type="button" className={styles.headingWrapperButton} onClick={onHeadingClick}>
86
+ : (<button type="button" className={styles.headingWrapperButton} onMouseDown={onHeadingMouseDown}>
66
87
  <Heading className={headingClasses} level={level} data-test={dataTest}>{children}</Heading>
67
88
  </button>)}
68
89
 
@@ -1,36 +1,21 @@
1
- // Allows overriding ReactDOM.render when using React 18:
2
- // import * as client from 'react-dom/client'
3
- // import {setClient} from '@jetbrains/ring-ui/components/global/react-render-adapter'
4
- //
5
- // setClient(client)
6
- import {
7
- render as legacyRender,
8
- unmountComponentAtNode as legacyUnmountComponentAtNode,
9
- hydrate as legacyHydrate
10
- } from 'react-dom';
11
-
1
+ import { render as legacyRender, unmountComponentAtNode as legacyUnmountComponentAtNode, hydrate as legacyHydrate } from 'react-dom';
12
2
  /* eslint-disable import/no-mutable-exports */
13
3
  export let render = legacyRender;
14
4
  export let unmountComponentAtNode = legacyUnmountComponentAtNode;
15
5
  export let hydrate = legacyHydrate;
16
- /* eslint-enable */
17
-
18
- export function setClient({createRoot, hydrateRoot}) {
19
- const roots = new WeakMap();
20
-
21
- render = (element, container) => {
22
- let root = roots.get(container);
23
- if (root == null) {
24
- root = createRoot(container);
25
- roots.set(container, root);
26
- }
27
- root.render(element);
28
- };
29
-
30
- unmountComponentAtNode = container => roots.get(container)?.unmount();
31
-
32
- hydrate = (element, container) => {
33
- const root = hydrateRoot(container, element);
34
- roots.set(container, root);
35
- };
6
+ export function setClient({ createRoot, hydrateRoot }) {
7
+ const roots = new WeakMap();
8
+ render = (element, container) => {
9
+ let root = roots.get(container);
10
+ if (root == null) {
11
+ root = createRoot(container);
12
+ roots.set(container, root);
13
+ }
14
+ root.render(element);
15
+ };
16
+ unmountComponentAtNode = container => roots.get(container)?.unmount();
17
+ hydrate = (element, container) => {
18
+ const root = hydrateRoot(container, element);
19
+ roots.set(container, root);
20
+ };
36
21
  }
@@ -15,7 +15,7 @@ export interface ProfileTranslations {
15
15
  export interface ProfileProps extends Omit<HTMLAttributes<HTMLDivElement>, 'onSelect'> {
16
16
  closeOnSelect: boolean;
17
17
  renderPopupItems: (items: ListDataItem[]) => readonly ListDataItem[];
18
- translations: ProfileTranslations;
18
+ translations?: ProfileTranslations | null | undefined;
19
19
  size: Size;
20
20
  renderGuest: (props: ProfileProps) => ReactNode;
21
21
  hasUpdates?: boolean | null | undefined;
@@ -67,6 +67,59 @@ export default class Profile extends PureComponent<ProfileProps> {
67
67
  renderGuest: PropTypes.Requireable<(...args: any[]) => any>;
68
68
  };
69
69
  static defaultProps: ProfileProps;
70
+ static contextType: React.Context<{
71
+ login: string;
72
+ logout: string;
73
+ loginTo: string;
74
+ ok: string;
75
+ cancel: string;
76
+ tryAgainLabel: string;
77
+ postpone: string;
78
+ youHaveLoggedInAs: string;
79
+ applyChange: string;
80
+ backendIsNotAvailable: string;
81
+ checkAgain: string;
82
+ nothingHappensLink: string;
83
+ errorMessage: string;
84
+ applyChangedUser: string;
85
+ profile: string;
86
+ switchUser: string;
87
+ addFirstDate: string;
88
+ addSecondDate: string;
89
+ addTime: string;
90
+ selectName: string;
91
+ setDate: string;
92
+ setDateTime: string;
93
+ setPeriod: string;
94
+ clear: string;
95
+ gotIt: string;
96
+ dismiss: string;
97
+ perPage: string;
98
+ firstPage: string;
99
+ lastPage: string;
100
+ nextPage: string;
101
+ previousPage: string;
102
+ searchTitle: string;
103
+ clearTitle: string;
104
+ userAgreement: string;
105
+ accept: string;
106
+ decline: string;
107
+ close: string;
108
+ scrollToAccept: string;
109
+ remindLater: string;
110
+ filterItems: string;
111
+ selectOption: string;
112
+ progress: string;
113
+ loading: string;
114
+ noOptionsFound: string;
115
+ banned: string;
116
+ online: string;
117
+ offline: string;
118
+ copyToClipboard: string;
119
+ copiedToClipboard: string;
120
+ copingToClipboardError: string;
121
+ unverified: string;
122
+ }>;
70
123
  static Size: typeof Size;
71
124
  render(): string | number | boolean | JSX.Element | React.ReactFragment | null | undefined;
72
125
  }
@@ -5,6 +5,7 @@ import Avatar, { Size } from '../avatar/avatar';
5
5
  import Button from '../button/button';
6
6
  import DropdownMenu from '../dropdown-menu/dropdown-menu';
7
7
  import PopupMenu from '../popup-menu/popup-menu';
8
+ import { I18nContext } from '../i18n/i18n-context';
8
9
  import { isTruthy } from '../global/typescript-utils';
9
10
  import styles from './header.css';
10
11
  const rgItemType = PopupMenu.ListProps.Type.LINK;
@@ -48,17 +49,20 @@ class Profile extends PureComponent {
48
49
  static defaultProps = {
49
50
  closeOnSelect: true,
50
51
  renderPopupItems: items => items,
51
- translations: {},
52
52
  size: Size.Size32,
53
- renderGuest: ({ loading, onLogin, className, translations }) => (<div className={classNames(styles.profileEmpty, className)}>
54
- <Button primary data-test="ring-header-login-button" disabled={loading} loader={loading} onClick={onLogin}>
55
- {translations.login || 'Log in...'}
56
- </Button>
57
- </div>)
53
+ renderGuest: ({ loading, onLogin, className, translations }) => (<I18nContext.Consumer>
54
+ {messages => (<div className={classNames(styles.profileEmpty, className)}>
55
+ <Button primary data-test="ring-header-login-button" disabled={loading} loader={loading} onClick={onLogin}>
56
+ {translations?.login ?? messages.login}
57
+ </Button>
58
+ </div>)}
59
+ </I18nContext.Consumer>)
58
60
  };
61
+ static contextType = I18nContext;
59
62
  static Size = Size;
60
63
  render() {
61
64
  const { className, closeOnSelect, hasUpdates, onLogout, user, profileUrl, LinkComponent, onSwitchUser, renderPopupItems, onRevertPostponement, showApplyChangedUser, showLogIn, showLogOut, showSwitchUser, renderGuest, translations, size, round, loading, onLogin, ...props } = this.props;
65
+ const messages = this.context;
62
66
  if (!user) {
63
67
  return (<div {...props} className={classNames(styles.profileEmpty, className)}>
64
68
  <Avatar size={size} round={round}/>
@@ -76,32 +80,32 @@ class Profile extends PureComponent {
76
80
  const items = [
77
81
  showApplyChangedUser && {
78
82
  rgItemType,
79
- label: translations.applyChangedUser || 'Apply changed user',
83
+ label: translations?.applyChangedUser ?? messages.applyChangedUser,
80
84
  className: styles.profileMenuItem,
81
85
  onClick: onRevertPostponement
82
86
  },
83
87
  showLogIn && {
84
88
  rgItemType,
85
- label: translations.login || 'Log in',
89
+ label: translations?.login ?? messages.login,
86
90
  className: styles.profileMenuItem,
87
91
  onClick: onRevertPostponement
88
92
  },
89
93
  {
90
94
  rgItemType: PopupMenu.ListProps.Type.LINK,
91
- label: translations.profile || 'Profile',
95
+ label: translations?.profile ?? messages.profile,
92
96
  target: '_self',
93
97
  href: profileUrl,
94
98
  LinkComponent
95
99
  },
96
100
  showSwitchUser && {
97
101
  rgItemType,
98
- label: translations.switchUser || 'Switch user',
102
+ label: translations?.switchUser ?? messages.switchUser,
99
103
  className: styles.profileMenuItem,
100
104
  onClick: onSwitchUser
101
105
  },
102
106
  showLogOut && {
103
107
  rgItemType,
104
- label: translations.logout || 'Log out',
108
+ label: translations?.logout ?? messages.logout,
105
109
  onClick: onLogout
106
110
  }
107
111
  ].filter(isTruthy);
@@ -0,0 +1,3 @@
1
+ This is localisation layer, that allows to translate the app into different languages.
2
+
3
+ All messages should be stored in a messages.json, using that format https://www.i18next.com/misc/json-format#i18next-json-v4
@@ -0,0 +1,54 @@
1
+ import React from 'react';
2
+ export declare const I18nContext: React.Context<{
3
+ login: string;
4
+ logout: string;
5
+ loginTo: string;
6
+ ok: string;
7
+ cancel: string;
8
+ tryAgainLabel: string;
9
+ postpone: string;
10
+ youHaveLoggedInAs: string;
11
+ applyChange: string;
12
+ backendIsNotAvailable: string;
13
+ checkAgain: string;
14
+ nothingHappensLink: string;
15
+ errorMessage: string;
16
+ applyChangedUser: string;
17
+ profile: string;
18
+ switchUser: string;
19
+ addFirstDate: string;
20
+ addSecondDate: string;
21
+ addTime: string;
22
+ selectName: string;
23
+ setDate: string;
24
+ setDateTime: string;
25
+ setPeriod: string;
26
+ clear: string;
27
+ gotIt: string;
28
+ dismiss: string;
29
+ perPage: string;
30
+ firstPage: string;
31
+ lastPage: string;
32
+ nextPage: string;
33
+ previousPage: string;
34
+ searchTitle: string;
35
+ clearTitle: string;
36
+ userAgreement: string;
37
+ accept: string;
38
+ decline: string;
39
+ close: string;
40
+ scrollToAccept: string;
41
+ remindLater: string;
42
+ filterItems: string;
43
+ selectOption: string;
44
+ progress: string;
45
+ loading: string;
46
+ noOptionsFound: string;
47
+ banned: string;
48
+ online: string;
49
+ offline: string;
50
+ copyToClipboard: string;
51
+ copiedToClipboard: string;
52
+ copingToClipboardError: string;
53
+ unverified: string;
54
+ }>;
@@ -0,0 +1,3 @@
1
+ import React from 'react';
2
+ import { getTranslations } from './i18n';
3
+ export const I18nContext = React.createContext(getTranslations());