@jetbrains/ring-ui 5.0.137 → 5.0.139

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 (87) 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/date-picker/date-input.js +3 -1
  5. package/components/editable-heading/editable-heading.css +7 -3
  6. package/components/editable-heading/editable-heading.js +29 -8
  7. package/components/global/react-render-adapter.js +16 -31
  8. package/components/header/profile.d.ts +3 -1
  9. package/components/header/profile.js +15 -11
  10. package/components/i18n/README.md +46 -0
  11. package/components/i18n/i18n-context.d.ts +13 -0
  12. package/components/i18n/i18n-context.js +14 -0
  13. package/components/i18n/i18n.d.ts +59 -0
  14. package/components/i18n/i18n.js +26 -0
  15. package/components/i18n/messages.json +53 -0
  16. package/components/input/input.d.ts +1 -4
  17. package/components/input/input.js +16 -16
  18. package/components/message/message.d.ts +1 -5
  19. package/components/message/message.js +17 -16
  20. package/components/pager/pager.d.ts +3 -8
  21. package/components/pager/pager.js +11 -12
  22. package/components/query-assist/query-assist.d.ts +1 -5
  23. package/components/query-assist/query-assist.js +30 -29
  24. package/components/select/select.d.ts +2 -4
  25. package/components/select/select.js +14 -11
  26. package/components/select/select__filter.d.ts +0 -1
  27. package/components/select/select__filter.js +4 -2
  28. package/components/user-agreement/user-agreement.d.ts +1 -9
  29. package/components/user-agreement/user-agreement.js +31 -30
  30. package/components/user-card/card.d.ts +14 -13
  31. package/components/user-card/card.js +26 -27
  32. package/dist/_helpers/card.js +28 -33
  33. package/dist/_helpers/select__filter.js +17 -10
  34. package/dist/auth/auth.js +1 -0
  35. package/dist/auth/auth__core.d.ts +1 -1
  36. package/dist/auth/auth__core.js +18 -27
  37. package/dist/auth/landing.js +1 -0
  38. package/dist/auth-dialog/auth-dialog.js +1 -1
  39. package/dist/auth-ng/auth-ng.js +1 -0
  40. package/dist/date-picker/date-input.js +3 -1
  41. package/dist/date-picker/date-picker.js +2 -0
  42. package/dist/date-picker/date-popup.js +2 -0
  43. package/dist/editable-heading/editable-heading.js +32 -9
  44. package/dist/global/react-render-adapter.js +0 -2
  45. package/dist/header/header.js +2 -0
  46. package/dist/header/profile.d.ts +3 -1
  47. package/dist/header/profile.js +27 -15
  48. package/dist/header/smart-profile.js +2 -0
  49. package/dist/header/smart-services.js +1 -0
  50. package/dist/i18n/i18n-context.d.ts +13 -0
  51. package/dist/i18n/i18n-context.js +24 -0
  52. package/dist/i18n/i18n.d.ts +59 -0
  53. package/dist/i18n/i18n.js +136 -0
  54. package/dist/input/input.d.ts +1 -4
  55. package/dist/input/input.js +35 -30
  56. package/dist/link/link.js +1 -1
  57. package/dist/message/message.d.ts +1 -5
  58. package/dist/message/message.js +41 -35
  59. package/dist/pager/pager.d.ts +3 -8
  60. package/dist/pager/pager.js +25 -15
  61. package/dist/pager-ng/pager-ng.js +2 -0
  62. package/dist/permissions-ng/permissions-ng.js +1 -0
  63. package/dist/query-assist/query-assist.d.ts +1 -5
  64. package/dist/query-assist/query-assist.js +105 -93
  65. package/dist/query-assist-ng/query-assist-ng.js +2 -0
  66. package/dist/select/select.d.ts +2 -4
  67. package/dist/select/select.js +54 -47
  68. package/dist/select/select__filter.d.ts +0 -1
  69. package/dist/select/select__filter.js +2 -0
  70. package/dist/select/select__popup.js +2 -0
  71. package/dist/select-ng/select-ng.js +2 -0
  72. package/dist/select-ng/select-ng__lazy.js +2 -0
  73. package/dist/style.css +1 -1
  74. package/dist/table-legacy-ng/table-legacy-ng.js +2 -0
  75. package/dist/table-legacy-ng/table-legacy-ng__pager.js +2 -0
  76. package/dist/tags-input/tags-input.js +2 -0
  77. package/dist/tags-input-ng/tags-input-ng.js +2 -0
  78. package/dist/user-agreement/service.js +2 -0
  79. package/dist/user-agreement/user-agreement.d.ts +1 -9
  80. package/dist/user-agreement/user-agreement.js +41 -41
  81. package/dist/user-card/card.d.ts +14 -13
  82. package/dist/user-card/card.js +2 -0
  83. package/dist/user-card/smart-user-card-tooltip.js +2 -0
  84. package/dist/user-card/tooltip.js +2 -0
  85. package/dist/user-card/user-card.js +2 -0
  86. package/dist/user-card-ng/user-card-ng.js +2 -0
  87. package/package.json +32 -32
@@ -6,6 +6,7 @@ import { refObject } from '../global/prop-types';
6
6
  import Button from '../button/button';
7
7
  import getUID from '../global/get-uid';
8
8
  import Icon from '../icon/icon';
9
+ import { I18nContext } from '../i18n/i18n-context';
9
10
  import composeRefs from '../global/composeRefs';
10
11
  import { ControlsHeightContext } from '../global/controls-height';
11
12
  import styles from './input.css';
@@ -27,10 +28,7 @@ class Input extends PureComponent {
27
28
  size: Size.M,
28
29
  onChange: noop,
29
30
  inputRef: noop,
30
- enableShortcuts: ['esc'],
31
- translations: {
32
- clear: 'Clear input'
33
- }
31
+ enableShortcuts: ['esc']
34
32
  };
35
33
  state = {
36
34
  empty: true
@@ -120,18 +118,20 @@ class Input extends PureComponent {
120
118
  'aria-label': typeof label === 'string' && label ? label : placeholder,
121
119
  'data-enabled-shortcuts': Array.isArray(enableShortcuts) ? enableShortcuts.join(',') : null
122
120
  };
123
- return (<div className={classes} data-test="ring-input">
124
- {label && (<InputLabel htmlFor={this.getId()} disabled={disabled} label={label}/>)}
125
- <div className={styles.container}>
126
- {icon && <Icon glyph={icon} className={styles.icon}/>}
127
- {multiline
128
- ? (<textarea onChange={this.handleTextareaChange} rows={1} {...commonProps} {...restProps}/>)
129
- : (<input onChange={this.handleInputChange} {...commonProps} {...restProps}/>)}
130
- {clearable && !disabled && (<Button title={translations.clear} data-test="ring-input-clear" className={styles.clear} icon={closeIcon} onClick={this.clear}/>)}
131
- {afterInput}
132
- </div>
133
- {error && <div className={styles.errorText}>{error}</div>}
134
- </div>);
121
+ return (<I18nContext.Consumer>
122
+ {({ translate }) => (<div className={classes} data-test="ring-input">
123
+ {label && (<InputLabel htmlFor={this.getId()} disabled={disabled} label={label}/>)}
124
+ <div className={styles.container}>
125
+ {icon && <Icon glyph={icon} className={styles.icon}/>}
126
+ {multiline
127
+ ? (<textarea onChange={this.handleTextareaChange} rows={1} {...commonProps} {...restProps}/>)
128
+ : (<input onChange={this.handleInputChange} {...commonProps} {...restProps}/>)}
129
+ {clearable && !disabled && (<Button title={translations?.clear ?? translate('clear')} data-test="ring-input-clear" className={styles.clear} icon={closeIcon} onClick={this.clear}/>)}
130
+ {afterInput}
131
+ </div>
132
+ {error && <div className={styles.errorText}>{error}</div>}
133
+ </div>)}
134
+ </I18nContext.Consumer>);
135
135
  }
136
136
  }
137
137
  export { Input };
@@ -11,7 +11,7 @@ export interface MessageTranslations {
11
11
  export interface MessageProps {
12
12
  icon: string | IconType | null;
13
13
  directions: readonly Directions[];
14
- translations: MessageTranslations;
14
+ translations?: MessageTranslations | null | undefined;
15
15
  theme: Theme;
16
16
  title?: string | null | undefined;
17
17
  children?: ReactNode;
@@ -34,10 +34,6 @@ export default class Message extends Component<MessageProps> {
34
34
  static defaultProps: {
35
35
  icon: string;
36
36
  directions: Directions[];
37
- translations: {
38
- gotIt: string;
39
- dismiss: string;
40
- };
41
37
  theme: Theme;
42
38
  };
43
39
  state: MessageState;
@@ -6,6 +6,7 @@ import Popup from '../popup/popup';
6
6
  import { Directions } from '../popup/popup.consts';
7
7
  import Icon from '../icon/icon';
8
8
  import Button from '../button/button';
9
+ import { I18nContext } from '../i18n/i18n-context';
9
10
  import Theme, { ThemeProvider, WithThemeClasses } from '../global/theme';
10
11
  import darkStyles from '../global/variables_dark.css';
11
12
  import styles from './message.css';
@@ -52,10 +53,6 @@ class Message extends Component {
52
53
  Directions.RIGHT_TOP, Directions.RIGHT_BOTTOM, Directions.RIGHT_CENTER,
53
54
  Directions.LEFT_TOP, Directions.LEFT_BOTTOM, Directions.LEFT_CENTER
54
55
  ],
55
- translations: {
56
- gotIt: 'Got it',
57
- dismiss: 'Dismiss'
58
- },
59
56
  theme: Theme.DARK
60
57
  };
61
58
  state = {};
@@ -96,19 +93,23 @@ class Message extends Component {
96
93
  ? [this.props.direction]
97
94
  : this.props.directions;
98
95
  const { direction } = this.state;
99
- return (<WithThemeClasses theme={theme}>
100
- {themeClasses => (<Popup ref={this.popupRef} hidden={false} directions={popupDirections} className={classNames(classes, themeClasses)} offset={UNIT * 2} onDirectionChange={this._onDirectionChange} {...popupProps}>
101
- <ThemeProvider theme={theme} passToPopups>
102
- {direction && (<div className={tailClasses} style={getTailOffsets(this.getTailOffset())[direction]}/>)}
96
+ return (<I18nContext.Consumer>
97
+ {({ translate }) => (<WithThemeClasses theme={theme}>
98
+ {themeClasses => (<Popup ref={this.popupRef} hidden={false} directions={popupDirections} className={classNames(classes, themeClasses)} offset={UNIT * 2} onDirectionChange={this._onDirectionChange} {...popupProps}>
99
+ <ThemeProvider theme={theme} passToPopups>
100
+ {direction && (<div className={tailClasses} style={getTailOffsets(this.getTailOffset())[direction]}/>)}
103
101
 
104
- {icon && <Icon className={styles.icon} glyph={icon}/>}
105
- {title && <h1 data-test="rgMessageTitle" className={styles.title}>{title}</h1>}
106
- {children && <div className={styles.description}>{children}</div>}
107
- {(onClose || buttonProps) && (<Button className={styles.button} onClick={onClose} primary {...buttonProps}>{translations.gotIt}</Button>)}
108
- {onDismiss && <Button onClick={onDismiss} text>{translations.dismiss}</Button>}
109
- </ThemeProvider>
110
- </Popup>)}
111
- </WithThemeClasses>);
102
+ {icon && <Icon className={styles.icon} glyph={icon}/>}
103
+ {title && <h1 data-test="rgMessageTitle" className={styles.title}>{title}</h1>}
104
+ {children && <div className={styles.description}>{children}</div>}
105
+ {(onClose || buttonProps) && (<Button className={styles.button} onClick={onClose} primary {...buttonProps}>{translations?.gotIt ?? translate('gotIt')}</Button>)}
106
+ {onDismiss && (<Button onClick={onDismiss} text>
107
+ {translations?.dismiss ?? translate('dismiss')}
108
+ </Button>)}
109
+ </ThemeProvider>
110
+ </Popup>)}
111
+ </WithThemeClasses>)}
112
+ </I18nContext.Consumer>);
112
113
  }
113
114
  }
114
115
  export default Message;
@@ -19,7 +19,7 @@ export interface PagerProps {
19
19
  disablePageSizeSelector: boolean;
20
20
  openTotal: boolean;
21
21
  canLoadLastPageWithOpenTotal: boolean;
22
- translations: PagerTranslations;
22
+ translations?: PagerTranslations | null | undefined;
23
23
  loader: boolean;
24
24
  loaderNavigation: boolean;
25
25
  onPageSizeChange: (size: number) => void;
@@ -40,18 +40,13 @@ export default class Pager extends PureComponent<PagerProps> {
40
40
  disablePageSizeSelector: boolean;
41
41
  openTotal: boolean;
42
42
  canLoadLastPageWithOpenTotal: boolean;
43
- translations: {
44
- perPage: string;
45
- firstPage: string;
46
- lastPage: string;
47
- nextPage: string;
48
- previousPage: string;
49
- };
50
43
  loader: boolean;
51
44
  loaderNavigation: boolean;
52
45
  onPageSizeChange: () => void;
53
46
  onLoadPage: () => void;
54
47
  };
48
+ static contextType: React.Context<import("../i18n/i18n-context").I18nContextProps>;
49
+ context: React.ContextType<typeof Pager.contextType>;
55
50
  getSelectOptions(): {
56
51
  selected: SelectItem<PagerSizeItem> | undefined;
57
52
  data: SelectItem<PagerSizeItem>[];
@@ -13,6 +13,7 @@ import Select from '../select/select';
13
13
  import memoize from '../global/memoize';
14
14
  import Link from '../link/link';
15
15
  import Icon from '../icon/icon';
16
+ import { I18nContext } from '../i18n/i18n-context';
16
17
  import style from './pager.css';
17
18
  class Pager extends PureComponent {
18
19
  static defaultProps = {
@@ -24,23 +25,18 @@ class Pager extends PureComponent {
24
25
  disablePageSizeSelector: false,
25
26
  openTotal: false,
26
27
  canLoadLastPageWithOpenTotal: false,
27
- translations: {
28
- perPage: 'per page',
29
- firstPage: 'First page',
30
- lastPage: 'Last page',
31
- nextPage: 'Next page',
32
- previousPage: 'Previous'
33
- },
34
28
  loader: false,
35
29
  loaderNavigation: false,
36
30
  onPageSizeChange: () => { },
37
31
  onLoadPage: () => { }
38
32
  };
33
+ static contextType = I18nContext;
39
34
  getSelectOptions() {
40
35
  const { pageSize, pageSizes } = this.props;
36
+ const { translate } = this.context;
41
37
  const data = pageSizes.map(size => ({
42
38
  key: size,
43
- label: `${size} ${this.props.translations.perPage}`
39
+ label: `${size} ${this.props.translations?.perPage ?? translate('perPage')}`
44
40
  }));
45
41
  const selected = data.find(it => it.key === pageSize);
46
42
  return { selected, data };
@@ -103,13 +99,14 @@ class Pager extends PureComponent {
103
99
  </div>);
104
100
  }
105
101
  getPagerLinks() {
102
+ const { translate } = this.context;
106
103
  const prevLinkAvailable = this.props.currentPage !== 1;
107
104
  const nextLinkAvailable = this.props.openTotal ||
108
105
  this.props.currentPage !== this.getTotalPages();
109
106
  const nextIcon = (<Icon glyph={chevronRightIcon} key="icon"/>);
110
107
  const prevIcon = (<Icon glyph={chevronLeftIcon} key="icon"/>);
111
- const prevText = this.props.translations.previousPage;
112
- const nextText = this.props.translations.nextPage;
108
+ const prevText = this.props.translations?.previousPage ?? translate('previousPage');
109
+ const nextText = this.props.translations?.nextPage ?? translate('nextPage');
113
110
  const nextLinkContent = (WrapText) => [
114
111
  <span key="text"><WrapText>{nextText}</WrapText></span>,
115
112
  nextIcon
@@ -148,6 +145,7 @@ class Pager extends PureComponent {
148
145
  getPagerContent() {
149
146
  const { currentPage, visiblePagesLimit } = this.props;
150
147
  const totalPages = this.getTotalPages();
148
+ const { translate } = this.context;
151
149
  if (totalPages < this.props.currentPage) {
152
150
  this.props.onPageChange?.(totalPages);
153
151
  }
@@ -182,7 +180,8 @@ class Pager extends PureComponent {
182
180
  {this.getPagerLinks()}
183
181
 
184
182
  <ButtonToolbar>
185
- {start > 1 && this.getButton(1, this.props.translations.firstPage)}
183
+ {start > 1 &&
184
+ this.getButton(1, this.props.translations?.firstPage ?? translate('firstPage'))}
186
185
 
187
186
  <ButtonGroup>
188
187
  {start > 1 && this.getButton(start - 1, '...')}
@@ -194,7 +193,7 @@ class Pager extends PureComponent {
194
193
  {end === totalPages && this.props.openTotal && (<Button href={this.generateHref(end + 1)} disabled={this.props.loader} {...this.getClickProps(this.handleLoadMore(end + 1))}>{'...'}</Button>)}
195
194
  </ButtonGroup>
196
195
 
197
- {lastPageButtonAvailable && this.getButton(this.props.openTotal ? -1 : totalPages, this.props.translations.lastPage)}
196
+ {lastPageButtonAvailable && this.getButton(this.props.openTotal ? -1 : totalPages, this.props.translations?.lastPage ?? translate('lastPage'))}
198
197
  </ButtonToolbar>
199
198
 
200
199
  {this.getPageSizeSelector()}
@@ -40,7 +40,7 @@ export interface QueryAssistProps {
40
40
  onApplySuggestion: (suggestion: QueryAssistSuggestion, change: QueryAssistChange) => void;
41
41
  onClear: () => void;
42
42
  onFocusChange: (change: FocusChange) => void;
43
- translations: QueryAssistTranslations;
43
+ translations?: QueryAssistTranslations | null | undefined;
44
44
  autoOpen?: boolean | null | undefined | 'force';
45
45
  caret?: number | null | undefined;
46
46
  clear?: boolean | null | undefined;
@@ -226,10 +226,6 @@ export default class QueryAssist extends Component<QueryAssistProps> {
226
226
  onClear: typeof noop;
227
227
  onFocusChange: typeof noop;
228
228
  size: Size;
229
- translations: {
230
- searchTitle: string;
231
- clearTitle: string;
232
- };
233
229
  };
234
230
  static getDerivedStateFromProps({ query }: QueryAssistProps, { prevQuery }: QueryAssistState): Partial<QueryAssistState>;
235
231
  constructor(props: QueryAssistProps);
@@ -19,6 +19,7 @@ import Icon from '../icon/icon';
19
19
  import { ControlsHeight, ControlsHeightContext } from '../global/controls-height';
20
20
  import { Size } from '../input/input';
21
21
  import inputStyles from '../input/input.css';
22
+ import { I18nContext } from '../i18n/i18n-context';
22
23
  import QueryAssistSuggestions from './query-assist__suggestions';
23
24
  import styles from './query-assist.css';
24
25
  const POPUP_COMPENSATION = PopupMenu.ListProps.Dimension.ITEM_PADDING +
@@ -166,11 +167,7 @@ class QueryAssist extends Component {
166
167
  onApplySuggestion: noop,
167
168
  onClear: noop,
168
169
  onFocusChange: noop,
169
- size: Size.L,
170
- translations: {
171
- searchTitle: 'Search',
172
- clearTitle: 'Clear search input'
173
- }
170
+ size: Size.L
174
171
  };
175
172
  static getDerivedStateFromProps({ query }, { prevQuery }) {
176
173
  const nextState = { prevQuery: query };
@@ -775,12 +772,14 @@ class QueryAssist extends Component {
775
772
  const actions = [...(this.props.actions || [])];
776
773
  const renderClear = this.props.clear && !!this.state.query;
777
774
  if (renderClear) {
778
- actions.push(<Button icon={closeIcon} key={'clearAction'} className={styles.clear} title={this.props.translations.clearTitle} ref={this.clearRef} onClick={this.clearQuery} data-test="query-assist-clear-icon"/>);
775
+ actions.push(<I18nContext.Consumer key={'clearAction'}>
776
+ {({ translate }) => (<Button icon={closeIcon} className={styles.clear} title={this.props.translations?.clearTitle ?? translate('clearTitle')} ref={this.clearRef} onClick={this.clearQuery} data-test="query-assist-clear-icon"/>)}
777
+ </I18nContext.Consumer>);
779
778
  }
780
779
  return actions;
781
780
  }
782
781
  render() {
783
- const { glass, 'data-test': dataTest, className, useCustomItemRender, huge, size } = this.props;
782
+ const { glass, 'data-test': dataTest, className, useCustomItemRender, huge, size, translations } = this.props;
784
783
  const renderPlaceholder = !!this.props.placeholder && this.state.placeholderEnabled;
785
784
  const renderLoader = this.props.loader !== false && this.state.loading;
786
785
  const renderGlass = glass && !renderLoader;
@@ -803,36 +802,38 @@ class QueryAssist extends Component {
803
802
  [styles.withoutGlass]: !glass || (!renderLoader && huge)
804
803
  });
805
804
  return (<ControlsHeightContext.Provider value={ControlsHeight.M}>
806
- <div data-test={dataTests('ring-query-assist', dataTest)} className={containerClasses} role="presentation" ref={this.nodeRef}>
807
- {this.state.shortcuts && (<Shortcuts map={this.shortcutsMap} scope={this.shortcutsScope}/>)}
805
+ <I18nContext.Consumer>
806
+ {({ translate }) => (<div data-test={dataTests('ring-query-assist', dataTest)} className={containerClasses} role="presentation" ref={this.nodeRef}>
807
+ {this.state.shortcuts && (<Shortcuts map={this.shortcutsMap} scope={this.shortcutsScope}/>)}
808
808
 
809
- {renderGlass && !huge && (<Icon glyph={searchIcon} className={styles.icon} title={this.props.translations.searchTitle} ref={this.glassRef} data-test="query-assist-search-icon"/>)}
809
+ {renderGlass && !huge && (<Icon glyph={searchIcon} className={styles.icon} title={translations?.searchTitle ?? translate('searchTitle')} ref={this.glassRef} data-test="query-assist-search-icon"/>)}
810
810
 
811
- {renderLoader && (<div className={classNames(styles.icon, styles.loader, {
812
- [styles.loaderOnTheRight]: !glass && !huge,
813
- [styles.loaderActive]: renderLoader
814
- })} ref={this.loaderRef}>
815
- <LoaderInline />
816
- </div>)}
811
+ {renderLoader && (<div className={classNames(styles.icon, styles.loader, {
812
+ [styles.loaderOnTheRight]: !glass && !huge,
813
+ [styles.loaderActive]: renderLoader
814
+ })} ref={this.loaderRef}>
815
+ <LoaderInline />
816
+ </div>)}
817
817
 
818
- <ContentEditable aria-label={this.props.translations.searchTitle} className={inputClasses} data-test="ring-query-assist-input" inputRef={this.inputRef} disabled={this.props.disabled} onComponentUpdate={() => this.setCaretPosition({ fromContentEditable: true })} onBlur={this.handleFocusChange} onClick={this.handleCaretMove} onCompositionStart={this.trackCompositionState} onCompositionEnd={this.trackCompositionState} onFocus={this.handleFocusChange} onInput={this.handleInput} // To support IE use the same method
819
- onKeyUp={this.handleInput} // to handle input and key up
820
- onKeyDown={this.handleEnter} onPaste={this.handlePaste} spellCheck="false">{this.state.query && <span>{this.renderQuery()}</span>}</ContentEditable>
818
+ <ContentEditable aria-label={translations?.searchTitle ?? translate('searchTitle')} className={inputClasses} data-test="ring-query-assist-input" inputRef={this.inputRef} disabled={this.props.disabled} onComponentUpdate={() => this.setCaretPosition({ fromContentEditable: true })} onBlur={this.handleFocusChange} onClick={this.handleCaretMove} onCompositionStart={this.trackCompositionState} onCompositionEnd={this.trackCompositionState} onFocus={this.handleFocusChange} onInput={this.handleInput} // To support IE use the same method
819
+ onKeyUp={this.handleInput} // to handle input and key up
820
+ onKeyDown={this.handleEnter} onPaste={this.handlePaste} spellCheck="false">{this.state.query && <span>{this.renderQuery()}</span>}</ContentEditable>
821
821
 
822
- {renderPlaceholder && (<button type="button" className={placeholderStyles} ref={this.placeholderRef} onClick={this.handleCaretMove} data-test="query-assist-placeholder">
823
- {this.props.placeholder}
824
- </button>)}
822
+ {renderPlaceholder && (<button type="button" className={placeholderStyles} ref={this.placeholderRef} onClick={this.handleCaretMove} data-test="query-assist-placeholder">
823
+ {this.props.placeholder}
824
+ </button>)}
825
825
 
826
- {actions.length
827
- ? (<div data-test="ring-query-assist-actions" className={styles.actions}>{actions}</div>)
828
- : null}
826
+ {actions.length
827
+ ? (<div data-test="ring-query-assist-actions" className={styles.actions}>{actions}</div>)
828
+ : null}
829
829
 
830
- <PopupMenu hidden={!this.state.showPopup} onCloseAttempt={this.closePopup} ref={this.popupRef} anchorElement={this.node} keepMounted attached className={this.props.popupClassName} directions={[PopupMenu.PopupProps.Directions.BOTTOM_RIGHT]} data={useCustomItemRender ? this.state.suggestions : this.renderSuggestions()} data-test="ring-query-assist-popup" hint={this.props.hint} hintOnSelection={this.props.hintOnSelection} left={this.getPopupOffset(this.state.suggestions)} maxHeight={PopupMenu.PopupProps.MaxHeight.SCREEN} onMouseDown={this.trackPopupMouseState} onMouseUp={this.trackPopupMouseState} onSelect={item => this.handleComplete(item)}/>
830
+ <PopupMenu hidden={!this.state.showPopup} onCloseAttempt={this.closePopup} ref={this.popupRef} anchorElement={this.node} keepMounted attached className={this.props.popupClassName} directions={[PopupMenu.PopupProps.Directions.BOTTOM_RIGHT]} data={useCustomItemRender ? this.state.suggestions : this.renderSuggestions()} data-test="ring-query-assist-popup" hint={this.props.hint} hintOnSelection={this.props.hintOnSelection} left={this.getPopupOffset(this.state.suggestions)} maxHeight={PopupMenu.PopupProps.MaxHeight.SCREEN} onMouseDown={this.trackPopupMouseState} onMouseUp={this.trackPopupMouseState} onSelect={item => this.handleComplete(item)}/>
831
831
 
832
- {glass && huge && (<div className={styles.rightSearchButton} data-test="query-assist-search-button">
833
- <Icon glyph={searchIcon} className={styles.rightSearchIcon} title={this.props.translations.searchTitle} onClick={this.handleApply} ref={this.glassRef} data-test="query-assist-search-icon"/>
832
+ {glass && huge && (<div className={styles.rightSearchButton} data-test="query-assist-search-button">
833
+ <Icon glyph={searchIcon} className={styles.rightSearchIcon} title={translations?.searchTitle ?? translate('searchTitle')} onClick={this.handleApply} ref={this.glassRef} data-test="query-assist-search-icon"/>
834
+ </div>)}
834
835
  </div>)}
835
- </div>
836
+ </I18nContext.Consumer>
836
837
  </ControlsHeightContext.Provider>);
837
838
  }
838
839
  }
@@ -54,8 +54,8 @@ export interface BaseSelectProps<T = unknown> {
54
54
  clear: boolean;
55
55
  loading: boolean;
56
56
  disabled: boolean;
57
- loadingMessage: string;
58
- notFoundMessage: string;
57
+ loadingMessage?: string;
58
+ notFoundMessage?: string;
59
59
  type: Type;
60
60
  size: Size;
61
61
  hideSelected: boolean;
@@ -155,8 +155,6 @@ export default class Select<T = unknown> extends Component<SelectProps<T>, Selec
155
155
  clear: boolean;
156
156
  loading: boolean;
157
157
  disabled: boolean;
158
- loadingMessage: string;
159
- notFoundMessage: string;
160
158
  type: Type;
161
159
  size: Size;
162
160
  targetElement: null;
@@ -17,6 +17,7 @@ import getUID from '../global/get-uid';
17
17
  import rerenderHOC from '../global/rerender-hoc';
18
18
  import fuzzyHighlight from '../global/fuzzy-highlight';
19
19
  import memoize from '../global/memoize';
20
+ import { I18nContext } from '../i18n/i18n-context';
20
21
  import { isArray } from '../global/typescript-utils';
21
22
  import { ControlsHeight, ControlsHeightContext } from '../global/controls-height';
22
23
  import inputStyles from '../input/input.css';
@@ -183,8 +184,6 @@ class Select extends Component {
183
184
  clear: false,
184
185
  loading: false,
185
186
  disabled: false,
186
- loadingMessage: 'Loading...',
187
- notFoundMessage: 'No options found',
188
187
  type: Type.BUTTON,
189
188
  size: Size.M,
190
189
  targetElement: null,
@@ -423,15 +422,19 @@ class Select extends Component {
423
422
  const anchorElement = this.props.targetElement || this.node;
424
423
  const { showPopup, shownData } = this.state;
425
424
  const _shownData = this._prependResetOption(shownData);
426
- let message;
427
- if (this.props.loading) {
428
- message = this.props.loadingMessage;
429
- }
430
- else if (!shownData.length) {
431
- message = this.props.notFoundMessage;
432
- }
433
- return (<SelectPopup data={_shownData} message={message} toolbar={showPopup && this.getToolbar()} loading={this.props.loading} activeIndex={this.state.selectedIndex} hidden={!showPopup} ref={this.popupRef} maxHeight={this.props.maxHeight} minWidth={this.props.minWidth} directions={this.props.directions} className={this.props.popupClassName} style={this.props.popupStyle} top={this.props.top} left={this.props.left} filter={this.isInputMode() ? false : this.props.filter} // disable popup filter in INPUT mode
434
- multiple={this.props.multiple} filterValue={this.state.filterValue} anchorElement={anchorElement} onCloseAttempt={this._onCloseAttempt} onSelect={this._listSelectHandler} onSelectAll={this._listSelectAllHandler} onFilter={this._filterChangeHandler} onClear={this.clearFilter} onLoadMore={this.props.onLoadMore} isInputMode={this.isInputMode()} selected={this.state.selected} tags={this.props.tags} compact={this.props.compact} renderOptimization={this.props.renderOptimization} ringPopupTarget={this.props.ringPopupTarget} disableMoveOverflow={this.props.disableMoveOverflow} disableScrollToActive={this.props.disableScrollToActive} dir={this.props.dir} onEmptyPopupEnter={this.onEmptyPopupEnter} listId={this.listId}/>);
425
+ return (<I18nContext.Consumer>
426
+ {({ translate }) => {
427
+ let message;
428
+ if (this.props.loading) {
429
+ message = this.props.loadingMessage ?? translate('loading');
430
+ }
431
+ else if (!shownData.length) {
432
+ message = this.props.notFoundMessage ?? translate('noOptionsFound');
433
+ }
434
+ return (<SelectPopup data={_shownData} message={message} toolbar={showPopup && this.getToolbar()} loading={this.props.loading} activeIndex={this.state.selectedIndex} hidden={!showPopup} ref={this.popupRef} maxHeight={this.props.maxHeight} minWidth={this.props.minWidth} directions={this.props.directions} className={this.props.popupClassName} style={this.props.popupStyle} top={this.props.top} left={this.props.left} filter={this.isInputMode() ? false : this.props.filter} // disable popup filter in INPUT mode
435
+ multiple={this.props.multiple} filterValue={this.state.filterValue} anchorElement={anchorElement} onCloseAttempt={this._onCloseAttempt} onSelect={this._listSelectHandler} onSelectAll={this._listSelectAllHandler} onFilter={this._filterChangeHandler} onClear={this.clearFilter} onLoadMore={this.props.onLoadMore} isInputMode={this.isInputMode()} selected={this.state.selected} tags={this.props.tags} compact={this.props.compact} renderOptimization={this.props.renderOptimization} ringPopupTarget={this.props.ringPopupTarget} disableMoveOverflow={this.props.disableMoveOverflow} disableScrollToActive={this.props.disableScrollToActive} dir={this.props.dir} onEmptyPopupEnter={this.onEmptyPopupEnter} listId={this.listId}/>);
436
+ }}
437
+ </I18nContext.Consumer>);
435
438
  }
436
439
  _showPopup() {
437
440
  if (!this.node) {
@@ -7,7 +7,6 @@ type SelectFilterProps = InputAttrs & {
7
7
  };
8
8
  export default class SelectFilter extends Component<SelectFilterProps> {
9
9
  static defaultProps: {
10
- placeholder: string;
11
10
  inputRef: typeof noop;
12
11
  };
13
12
  componentWillUnmount(): void;
@@ -4,11 +4,11 @@ import classNames from 'classnames';
4
4
  import Input from '../input/input';
5
5
  import sniffr from '../global/sniffer';
6
6
  import { ActiveItemContext } from '../list/list';
7
+ import { I18nContext } from '../i18n/i18n-context';
7
8
  import styles from './select-popup.css';
8
9
  function noop() { }
9
10
  class SelectFilter extends Component {
10
11
  static defaultProps = {
11
- placeholder: 'Filter items',
12
12
  inputRef: noop
13
13
  };
14
14
  componentWillUnmount() {
@@ -34,7 +34,9 @@ class SelectFilter extends Component {
34
34
  const { className, listId, ...restProps } = this.props;
35
35
  const classes = classNames(styles.filter, className);
36
36
  return (<ActiveItemContext.ValueContext.Consumer>
37
- {activeItemId => (<Input {...restProps} aria-owns={listId} aria-activedescendant={activeItemId} autoComplete="off" autoFocus borderless inputRef={this.inputRef} className={classes}/>)}
37
+ {activeItemId => (<I18nContext.Consumer>
38
+ {({ translate }) => (<Input {...restProps} placeholder={restProps.placeholder ?? translate('filterItems')} aria-owns={listId} aria-activedescendant={activeItemId} autoComplete="off" autoFocus borderless inputRef={this.inputRef} className={classes}/>)}
39
+ </I18nContext.Consumer>)}
38
40
  </ActiveItemContext.ValueContext.Consumer>);
39
41
  }
40
42
  }
@@ -14,7 +14,7 @@ export interface UserAgreementTranslations {
14
14
  }
15
15
  export interface UserAgreementProps {
16
16
  text: string;
17
- translations: UserAgreementTranslations;
17
+ translations?: UserAgreementTranslations | null | undefined;
18
18
  show: boolean;
19
19
  onAccept: () => void;
20
20
  onDecline: () => void;
@@ -46,14 +46,6 @@ export default class UserAgreement extends PureComponent<UserAgreementProps> {
46
46
  className: PropTypes.Requireable<string>;
47
47
  };
48
48
  static defaultProps: {
49
- translations: {
50
- userAgreement: string;
51
- accept: string;
52
- decline: string;
53
- close: string;
54
- scrollToAccept: string;
55
- remindLater: string;
56
- };
57
49
  show: boolean;
58
50
  onAccept: typeof noop;
59
51
  onDecline: typeof noop;
@@ -9,6 +9,7 @@ import { Content, Header } from '../island/island';
9
9
  import Panel from '../panel/panel';
10
10
  import Button from '../button/button';
11
11
  import Markdown from '../markdown/markdown';
12
+ import { I18nContext } from '../i18n/i18n-context';
12
13
  import style from './user-agreement.css';
13
14
  function noop() { }
14
15
  /**
@@ -34,14 +35,6 @@ class UserAgreement extends PureComponent {
34
35
  className: PropTypes.string
35
36
  };
36
37
  static defaultProps = {
37
- translations: {
38
- userAgreement: 'User Agreement',
39
- accept: 'Accept',
40
- decline: 'Decline',
41
- close: 'Close',
42
- scrollToAccept: 'View the entire agreement to continue',
43
- remindLater: 'Remind me later'
44
- },
45
38
  show: false,
46
39
  onAccept: noop,
47
40
  onDecline: noop,
@@ -54,29 +47,37 @@ class UserAgreement extends PureComponent {
54
47
  render() {
55
48
  const { scrolledDown } = this.state;
56
49
  const { translations, onAccept, onDecline, onClose, onRemindLater, text, show, preview, className } = this.props;
57
- return (<Dialog label={translations.userAgreement} show={show} className={classNames(style.agreementDialog, className)} contentClassName={style.dialogContent} trapFocus autoFocusFirst={false} data-test="user-agreement">
58
- <Header>{translations.userAgreement}</Header>
59
- <Content fade onScrollToBottom={this.onScrollToBottom}>
60
- <Markdown>{text}</Markdown>
61
- </Content>
62
- {!preview && (<Panel>
63
- {onRemindLater && !scrolledDown && (<div className={style.suggestion}>{translations.scrollToAccept}</div>)}
64
- <Button primary disabled={!scrolledDown} onClick={onAccept} data-test="accept">
65
- {translations.accept}
66
- </Button>
67
- <Button onClick={onDecline} autoFocus data-test="decline">
68
- {translations.decline}
69
- </Button>
50
+ return (<I18nContext.Consumer>
51
+ {({ translate }) => (<Dialog label={translations?.userAgreement ?? translate('userAgreement')} show={show} className={classNames(style.agreementDialog, className)} contentClassName={style.dialogContent} trapFocus autoFocusFirst={false} data-test="user-agreement">
52
+ <Header>{translations?.userAgreement ?? translate('userAgreement')}</Header>
53
+ <Content fade onScrollToBottom={this.onScrollToBottom}>
54
+ <Markdown>{text}</Markdown>
55
+ </Content>
56
+ {!preview && (<Panel>
57
+ {onRemindLater && !scrolledDown && (<div className={style.suggestion}>
58
+ {translations?.scrollToAccept ?? translate('scrollToAccept')}
59
+ </div>)}
60
+ <Button primary disabled={!scrolledDown} onClick={onAccept} data-test="accept">
61
+ {translations?.accept ?? translate('accept')}
62
+ </Button>
63
+ <Button onClick={onDecline} autoFocus data-test="decline">
64
+ {translations?.decline ?? translate('decline')}
65
+ </Button>
70
66
 
71
- {!onRemindLater && !scrolledDown && (<span className={style.suggestion}>{translations.scrollToAccept}</span>)}
72
- {onRemindLater && (<Button className={style.remindLaterButton} onClick={onRemindLater} data-test="later">
73
- {translations.remindLater}
74
- </Button>)}
75
- </Panel>)}
76
- {preview && (<Panel>
77
- <Button onClick={onClose} autoFocus data-test="close">{translations.close}</Button>
78
- </Panel>)}
79
- </Dialog>);
67
+ {!onRemindLater && !scrolledDown && (<span className={style.suggestion}>
68
+ {translations?.scrollToAccept ?? translate('scrollToAccept')}
69
+ </span>)}
70
+ {onRemindLater && (<Button className={style.remindLaterButton} onClick={onRemindLater} data-test="later">
71
+ {translations?.remindLater ?? translate('remindLater')}
72
+ </Button>)}
73
+ </Panel>)}
74
+ {preview && (<Panel>
75
+ <Button onClick={onClose} autoFocus data-test="close">
76
+ {translations?.close ?? translate('close')}
77
+ </Button>
78
+ </Panel>)}
79
+ </Dialog>)}
80
+ </I18nContext.Consumer>);
80
81
  }
81
82
  }
82
83
  export default UserAgreement;
@@ -1,4 +1,4 @@
1
- import { HTMLAttributes, PureComponent, ReactElement } from 'react';
1
+ import React, { HTMLAttributes, PureComponent, ReactElement } from 'react';
2
2
  import PropTypes from 'prop-types';
3
3
  export interface UserCardUser {
4
4
  name: string;
@@ -22,7 +22,8 @@ export interface UserCardWording {
22
22
  }
23
23
  export interface UserCardProps extends HTMLAttributes<HTMLDivElement> {
24
24
  user: UserCardUser;
25
- wording: UserCardWording;
25
+ wording?: UserCardWording | null | undefined;
26
+ translations?: UserCardWording | null | undefined;
26
27
  info?: ReactElement | readonly ReactElement[] | string;
27
28
  avatarInfo?: ReactElement | readonly ReactElement[] | string;
28
29
  'data-test'?: string | null | undefined;
@@ -52,18 +53,18 @@ export default class UserCard extends PureComponent<UserCardProps> {
52
53
  copingToClipboardError: PropTypes.Requireable<string>;
53
54
  unverified: PropTypes.Requireable<string>;
54
55
  }>>;
56
+ translations: PropTypes.Requireable<PropTypes.InferProps<{
57
+ banned: PropTypes.Validator<string>;
58
+ online: PropTypes.Validator<string>;
59
+ offline: PropTypes.Validator<string>;
60
+ copyToClipboard: PropTypes.Requireable<string>;
61
+ copiedToClipboard: PropTypes.Requireable<string>;
62
+ copingToClipboardError: PropTypes.Requireable<string>;
63
+ unverified: PropTypes.Requireable<string>;
64
+ }>>;
55
65
  };
56
- static defaultProps: {
57
- wording: {
58
- banned: string;
59
- online: string;
60
- offline: string;
61
- copyToClipboard: string;
62
- copiedToClipboard: string;
63
- copingToClipboardError: string;
64
- unverified: string;
65
- };
66
- };
66
+ static contextType: React.Context<import("../i18n/i18n-context").I18nContextProps>;
67
+ context: React.ContextType<typeof UserCard.contextType>;
67
68
  copyEmail: () => void;
68
69
  render(): JSX.Element;
69
70
  }