@hipay/hipay-material-ui 2.0.0-beta.50 → 2.0.0-beta.52

Sign up to get free protection for your applications and to get access to all the features.
@@ -0,0 +1,457 @@
1
+ import _extends from "@babel/runtime/helpers/extends";
2
+ import _objectSpread from "@babel/runtime/helpers/objectSpread";
3
+ import React from 'react';
4
+ import PropTypes from 'prop-types';
5
+ import Scrollbars from 'react-custom-scrollbars';
6
+ import HiSelectableList from '../HiSelectableList';
7
+ import HiInput from '../HiForm/HiInput';
8
+ import withStyles from '../styles/withStyles';
9
+ import { getNextItemSelectable, foldAccents } from '../utils/helpers';
10
+ import HiIcon from '../HiIcon';
11
+ import keycode from 'keycode';
12
+ export const styles = theme => ({
13
+ labelIcon: {
14
+ marginRight: 10
15
+ },
16
+ labelImg: {
17
+ height: 18,
18
+ width: 'auto',
19
+ margin: '0 4px',
20
+ verticalAlign: 'middle'
21
+ },
22
+ selectIconLabel: _objectSpread({
23
+ whiteSpace: 'nowrap',
24
+ overflow: 'hidden',
25
+ textOverflow: 'ellipsis',
26
+ paddingRight: 16
27
+ }, theme.typography.b1, {
28
+ display: 'inline-flex',
29
+ width: '100%'
30
+ }),
31
+ selectImgLabel: _objectSpread({
32
+ whiteSpace: 'nowrap',
33
+ overflow: 'hidden',
34
+ textOverflow: 'ellipsis',
35
+ paddingRight: 16
36
+ }, theme.typography.b1, {
37
+ display: 'inline-flex',
38
+ width: '100%'
39
+ })
40
+ });
41
+ /**
42
+ *
43
+ * Utilisé pour tous types de selects dans les formulaires.
44
+ * - single / multiple ( multi-select )
45
+ * - avec / sans checkboxes
46
+ * - avec / sans barre de recherche
47
+ * - avec / sans option "All"
48
+ * - prise en compte du type des éléments (text, image, icon, ...)
49
+ *
50
+ * Ce composant réuni les sous-composants
51
+ * - HiSelectInput : affiche l'élément dans le formulaire
52
+ * - HiSearchField : intègre une barre de recherche dans le Popper, il filtre la liste des suggestions
53
+ * - HiSelectableList : affiche la liste des suggestions selon le type des éléments
54
+ */
55
+
56
+ class HiSelectContent extends React.PureComponent {
57
+ constructor(props) {
58
+ super(props);
59
+
60
+ this.handleKeyDown = event => {
61
+ let nextItem;
62
+ const key = keycode(event);
63
+
64
+ if (key === 'down') {
65
+ event.preventDefault();
66
+ nextItem = getNextItemSelectable(document.activeElement, 'down');
67
+ } else if (key === 'up') {
68
+ event.preventDefault();
69
+ nextItem = getNextItemSelectable(document.activeElement, 'up');
70
+ } else if (key === 'tab' || key === 'esc') {
71
+ this.setState({
72
+ open: false
73
+ });
74
+ } else if (key === 'space' || key === 'enter' && !this.props.multiple) {
75
+ event.preventDefault();
76
+ const item = this.props.options.find(elem => String(elem.id) === event.target.id);
77
+ this.handleSelect(null, item);
78
+ } else if (key === 'enter' && this.props.multiple) {
79
+ event.preventDefault();
80
+ this.handleClose();
81
+ }
82
+
83
+ if (nextItem) {
84
+ nextItem.focus();
85
+ }
86
+ };
87
+
88
+ this.handleKeyDownSearch = event => {
89
+ const key = keycode(event);
90
+
91
+ if (this.overlay && (key === 'down' || key === 'up')) {
92
+ this.focusOnFirstItem();
93
+ } else if (this.overlay && key === 'esc' || key === 'enter') {
94
+ event.preventDefault();
95
+ this.handleClose();
96
+ }
97
+ };
98
+
99
+ this.handleSelect = (event, item) => {
100
+ const {
101
+ hasAll,
102
+ multiple,
103
+ onChange,
104
+ options,
105
+ value
106
+ } = this.props;
107
+
108
+ if (!multiple) {
109
+ // single value
110
+ this.handleClose();
111
+ onChange(event, item.id, item);
112
+ } else if (hasAll && item.id === '_all') {
113
+ if (value.length === options.length) {
114
+ // unselect _all options
115
+ onChange(event, [], item);
116
+ } else {
117
+ // select _all options
118
+ onChange(event, options.map(option => option.id), item);
119
+ }
120
+ } else if (value.includes(item.id)) {
121
+ // unselect item
122
+ onChange(event, value.filter(id => id !== item.id), item);
123
+ } else {
124
+ onChange(event, [...value, item.id], item);
125
+ }
126
+ };
127
+
128
+ this.handleClose = () => {
129
+ if (this.props.onClose) this.props.onClose();
130
+ };
131
+
132
+ this.handleSuggestions = suggestions => {
133
+ const {
134
+ hasAll,
135
+ iconAll,
136
+ translations
137
+ } = this.props;
138
+
139
+ if (suggestions.length === 0) {
140
+ // Add '_no_result' suggestion
141
+ this.setState(prevState => _objectSpread({}, prevState, {
142
+ suggestions: [{
143
+ id: '_no_result',
144
+ type: 'text',
145
+ disabled: true,
146
+ centered: true,
147
+ hideCheckbox: true,
148
+ label: translations.no_result_match
149
+ }]
150
+ }));
151
+ } else {
152
+ this.setState({
153
+ suggestions: [// Add '_all' suggestion
154
+ ...(hasAll ? [_objectSpread({
155
+ id: '_all',
156
+ label: translations.all
157
+ }, iconAll && {
158
+ type: 'icon',
159
+ icon: iconAll
160
+ })] : []), ...suggestions]
161
+ });
162
+ }
163
+ };
164
+
165
+ this.handleScroll = e => {
166
+ if (e.target.scrollHeight - e.target.clientHeight - e.target.scrollTop < 15) {
167
+ this.props.onScrollReachBottom();
168
+ }
169
+ };
170
+
171
+ this.handleSearch = (e, inputValue) => {
172
+ const searchValue = inputValue && e.target.value ? inputValue : e.target.value;
173
+
174
+ if (this.props.onSearch) {
175
+ this.props.onSearch(e, searchValue);
176
+ } else {
177
+ this.setState({
178
+ searchValue
179
+ });
180
+ }
181
+ };
182
+
183
+ this.handleSearchReset = () => {
184
+ this.handleSearch({
185
+ target: {
186
+ value: ''
187
+ }
188
+ }, '');
189
+ };
190
+
191
+ this.buildSelectProps = (options, value = [], search = '', loading = false) => {
192
+ // build item list
193
+ const itemList = [...(loading ? [{
194
+ id: '_loading',
195
+ type: 'loader',
196
+ disabled: true,
197
+ centered: true,
198
+ hideCheckbox: true,
199
+ label: 'loading'
200
+ }] : []), // simple one level filter on label
201
+ ...(search !== '' ? [...options.filter(item => item.label && foldAccents(item.label.toString().toLowerCase()).search(foldAccents(search.toLowerCase())) !== -1)] : [...(this.props.hasAll ? [_objectSpread({
202
+ id: '_all',
203
+ label: this.props.translations.all
204
+ }, this.props.iconAll && {
205
+ type: 'icon',
206
+ icon: this.props.iconAll
207
+ })] : []), ...options])];
208
+ return {
209
+ itemList
210
+ };
211
+ };
212
+
213
+ this.getInputElement = el => {
214
+ this.searchField = el;
215
+
216
+ if (this.props.inputRef) {
217
+ this.props.inputRef(this.searchField);
218
+ }
219
+ };
220
+
221
+ this.state = {
222
+ open: false,
223
+ focused: false,
224
+ searchValue: props.searchValue ? undefined : '',
225
+ suggestions: props.options
226
+ };
227
+ this.handleSearch = this.handleSearch.bind(this);
228
+ this.handleSearchReset = this.handleSearchReset.bind(this);
229
+ this.handleSelect = this.handleSelect.bind(this);
230
+ this.handleSuggestions = this.handleSuggestions.bind(this);
231
+ }
232
+
233
+ static getDerivedStateFromProps(nextProps, prevState) {
234
+ if (nextProps.options !== prevState.suggestions) {
235
+ return _objectSpread({}, prevState, {
236
+ suggestions: nextProps.options
237
+ });
238
+ }
239
+
240
+ return null;
241
+ } // Key down on list items
242
+
243
+
244
+ render() {
245
+ const {
246
+ classes,
247
+ disabled,
248
+ error,
249
+ loading,
250
+ options,
251
+ searchable,
252
+ type,
253
+ value,
254
+ multiple,
255
+ translations,
256
+ hiSelectableListProps,
257
+ hiSelectInputProps,
258
+ id,
259
+ onScrollReachBottom,
260
+ onSubmit,
261
+ startAdornment,
262
+ searchValue = this.state.searchValue,
263
+ buildSelectProps = this.buildSelectProps,
264
+ // use parent builder if defined
265
+ autoHeight,
266
+ height
267
+ } = this.props;
268
+
269
+ if (multiple) {
270
+ if (!Array.isArray(value)) {
271
+ throw new Error('HiPay Material-UI: the `value` property must be an array ' + 'when using the `HiSelect` component with `multiple`.');
272
+ }
273
+ }
274
+
275
+ let selectedItemIdList = [];
276
+
277
+ if (value) {
278
+ selectedItemIdList = multiple ? [...value] : [value];
279
+ }
280
+
281
+ const {
282
+ itemList
283
+ } = buildSelectProps(options, selectedItemIdList, searchValue, loading);
284
+ return React.createElement(React.Fragment, null, !!searchable && React.createElement(HiInput, {
285
+ value: searchValue,
286
+ autoFocus: true,
287
+ inputRef: this.getInputElement,
288
+ onKeyDown: this.handleKeyDownSearch,
289
+ onChange: this.handleSearch,
290
+ onReset: this.handleSearchReset,
291
+ placeholder: translations.search,
292
+ startAdornment: 'search',
293
+ tabIndex: 0
294
+ }), startAdornment, React.createElement(Scrollbars, _extends({
295
+ ref: contentEl => {
296
+ this.optionsContent = contentEl;
297
+ }
298
+ }, autoHeight ? {
299
+ autoHeight: true,
300
+ autoHeightMax: height
301
+ } : {
302
+ autoHeightMax: height,
303
+ autoHeightMin: height
304
+ }, {
305
+ autoHeight: true,
306
+ autoHeightMax: height // TODO ?
307
+
308
+ }, onScrollReachBottom && {
309
+ onScroll: this.handleScroll
310
+ }), React.createElement(HiSelectableList, _extends({
311
+ type: type,
312
+ itemList: itemList,
313
+ onKeyDown: this.handleKeyDown,
314
+ onSelect: this.handleSelect,
315
+ selectedItemIdList: selectedItemIdList,
316
+ fallbackImage: this.props.fallbackImage
317
+ }, hiSelectableListProps))));
318
+ }
319
+
320
+ }
321
+
322
+ HiSelectContent.defaultProps = {
323
+ autoHeight: true,
324
+ height: 400,
325
+ disabled: false,
326
+ error: false,
327
+ hasAll: false,
328
+ hiSelectableListProps: {},
329
+ hiSelectInputProps: {},
330
+ multiple: false,
331
+ searchable: false,
332
+ translations: {
333
+ all: 'All',
334
+ no_result_match: 'No result match',
335
+ search: 'Search',
336
+ n_items_selected: '%s items selected',
337
+ one_item_selected: '%s item selected',
338
+ n_children: '%s items',
339
+ one_child: '%s item'
340
+ },
341
+ type: 'text'
342
+ };
343
+ HiSelectContent.propTypes = process.env.NODE_ENV !== "production" ? {
344
+ autoHeight: PropTypes.bool,
345
+
346
+ /**
347
+ * Useful to extend the style applied to components.
348
+ */
349
+ classes: PropTypes.object,
350
+
351
+ /**
352
+ * Inactif
353
+ */
354
+ disabled: PropTypes.bool,
355
+
356
+ /**
357
+ * Applique le style error
358
+ */
359
+ error: PropTypes.bool,
360
+
361
+ /**
362
+ * Chemin vers l'image à afficher par défaut si une image n'est pas trouvée
363
+ */
364
+ fallbackImage: PropTypes.string,
365
+
366
+ /**
367
+ * Affiche l'élément 'All'
368
+ */
369
+ hasAll: PropTypes.bool,
370
+
371
+ /**
372
+ * Hauteur du container scrollable
373
+ */
374
+ height: PropTypes.number,
375
+
376
+ /**
377
+ * Override HiSelectableList props (
378
+ */
379
+ hiSelectableListProps: PropTypes.object,
380
+
381
+ /**
382
+ * Override HiSelectInput props
383
+ */
384
+ hiSelectInputProps: PropTypes.object,
385
+
386
+ /**
387
+ * Nom de l'icône
388
+ */
389
+ iconAll: PropTypes.string,
390
+
391
+ /**
392
+ * id du select
393
+ */
394
+ id: PropTypes.string,
395
+
396
+ /**
397
+ * Ajoute un loader
398
+ */
399
+ loading: PropTypes.bool,
400
+
401
+ /**
402
+ * Autorise la sélection de plusieurs valeurs
403
+ */
404
+ multiple: PropTypes.bool,
405
+
406
+ /**
407
+ * Fonction de callback qui renvoit la/les valeurs sélectionnées
408
+ *
409
+ * @param {object} event
410
+ * @param {string || array} value
411
+ */
412
+ onChange: PropTypes.func.isRequired,
413
+
414
+ /**
415
+ * Fonction de callback appelée lorsque le scroll atteint le bas de la liste
416
+ */
417
+ onScrollReachBottom: PropTypes.func,
418
+
419
+ /**
420
+ * Fonction de callback appelée lorsque le champs de recherche est utilisé
421
+ */
422
+ onSearch: PropTypes.func,
423
+
424
+ /**
425
+ * Listes des options du select
426
+ */
427
+ options: PropTypes.array.isRequired,
428
+
429
+ /**
430
+ * Affiche un input de recherche permettant de filtrer les options
431
+ */
432
+ searchable: PropTypes.bool,
433
+
434
+ /**
435
+ * Node qui s'ajoute entre la barre de recherche et la liste de résultats
436
+ */
437
+ startAdornment: PropTypes.object,
438
+
439
+ /**
440
+ * Traductions (par défaut en anglais)
441
+ */
442
+ translations: PropTypes.object,
443
+
444
+ /**
445
+ * Type des éléments du select, définit le rendu d'un élément
446
+ */
447
+ type: PropTypes.oneOf(['icon', 'text', 'image', 'primary-highlight']),
448
+
449
+ /**
450
+ * Value(s) du select
451
+ */
452
+ value: PropTypes.oneOfType([PropTypes.number, PropTypes.string, PropTypes.array])
453
+ } : {};
454
+ export default withStyles(styles, {
455
+ hiComponent: true,
456
+ name: 'HmuiHiSelectContent'
457
+ })(HiSelectContent);
@@ -1,4 +1,6 @@
1
1
  export { default } from './HiSelect';
2
2
  export { default as HiNestedSelect } from './HiNestedSelect';
3
3
  export { default as HiSelectField } from './HiSelectField';
4
- export { default as HiSelectInput } from './HiSelectInput';
4
+ export { default as HiSelectInput } from './HiSelectInput';
5
+ export { default as HiSelectContent } from './HiSelectContent';
6
+ export { default as HiNestedSelectContent, findFinalItemRecursively, getRecursiveFinalItemIdList } from './HiNestedSelectContent';
@@ -11,6 +11,9 @@ import HiColoredLabel from '../HiColoredLabel';
11
11
  import HiLoader from '../HiLoader';
12
12
  import withStyles from '../styles/withStyles';
13
13
  import { escapeHTML } from '../utils/helpers';
14
+ import pure from 'recompose/pure';
15
+ const PureListSubheader = pure(ListSubheader);
16
+ const PureListItem = pure(ListItem);
14
17
  export const styles = theme => ({
15
18
  root: {
16
19
  paddingLeft: 4
@@ -106,8 +109,7 @@ export const styles = theme => ({
106
109
  textOverflow: 'ellipsis',
107
110
  textAlign: 'right',
108
111
  margin: '4px 12px 4px 8px',
109
- alignSelf: 'center',
110
- width: '100%'
112
+ alignSelf: 'center'
111
113
  }),
112
114
  checkbox: {
113
115
  marginTop: 3
@@ -130,7 +132,7 @@ export const styles = theme => ({
130
132
  * Construit un élément de liste sélectionnable (avec checkbox)
131
133
  */
132
134
 
133
- class HiSelectableListItem extends React.Component {
135
+ class HiSelectableListItem extends React.PureComponent {
134
136
  constructor(props) {
135
137
  super(props);
136
138
 
@@ -236,7 +238,7 @@ class HiSelectableListItem extends React.Component {
236
238
  displayedIcon = icon;
237
239
  }
238
240
 
239
- const ListItemComponentName = pinned ? ListSubheader : ListItem;
241
+ const ListItemComponentName = pinned ? PureListSubheader : PureListItem;
240
242
  return React.createElement(ListItemComponentName, _extends({
241
243
  id: id,
242
244
  tabIndex: disabled ? '-1' : 0,
@@ -2,6 +2,7 @@
2
2
  import React from 'react';
3
3
  import PropTypes from 'prop-types';
4
4
  import keycode from 'keycode';
5
+ import classNames from 'classnames';
5
6
  import withStyles from '../styles/withStyles';
6
7
  import TableRow from '@material-ui/core/TableRow';
7
8
  import HiCellBuilder from './HiCellBuilder';
@@ -17,6 +18,9 @@ export const styles = theme => ({
17
18
  '&:hover, &:focus': {
18
19
  backgroundColor: `${theme.palette.action.hover} !important`
19
20
  }
21
+ },
22
+ clicableRow: {
23
+ cursor: 'pointer'
20
24
  }
21
25
  });
22
26
 
@@ -42,7 +46,9 @@ class HiTableRow extends React.PureComponent {
42
46
  rowdata
43
47
  } = this.props;
44
48
  return React.createElement(TableRow, {
45
- className: classes.row,
49
+ className: classNames(classes.row, {
50
+ [classes.clicableRow]: this.props.onClick
51
+ }),
46
52
  hover: true,
47
53
  onClick: event => this.handleClick(event, rowdata),
48
54
  onKeyDown: event => {
@@ -56,10 +62,10 @@ class HiTableRow extends React.PureComponent {
56
62
  height: dense ? cst.CELL_HEIGHT_DENSE : cst.CELL_HEIGHT
57
63
  },
58
64
  tabIndex: 0
59
- }, Object.keys(columns).map(key => {
65
+ }, Object.keys(columns).map(column => {
60
66
  return React.createElement(HiCellBuilder, {
61
- key: columns[key].colId,
62
- column: columns[key],
67
+ key: columns[column].colId,
68
+ column: columns[column],
63
69
  data: rowdata,
64
70
  locale: locale
65
71
  });
@@ -132,6 +132,7 @@ export default function createPalette(palette) {
132
132
  contrastText: '#FFFFFF'
133
133
  },
134
134
  negative = {
135
+ ultraLight: '#EA9494',
135
136
  light: '#E66666',
136
137
  main: '#D50000',
137
138
  dark: '#A00000',
@@ -144,6 +145,7 @@ export default function createPalette(palette) {
144
145
  contrastText: '#FFFFFF'
145
146
  },
146
147
  neutral = {
148
+ ultraLight: '#8B8B8B',
147
149
  light: '#838383',
148
150
  main: '#737373',
149
151
  dark: '#20272B',
@@ -154,13 +156,17 @@ export default function createPalette(palette) {
154
156
  main: red[500],
155
157
  dark: red[700]
156
158
  },
159
+ lookup = {
160
+ light: '#FFFF8D',
161
+ main: '#EDED14'
162
+ },
157
163
  type = 'light',
158
164
  contrastThreshold = 2.9,
159
165
  // max light contrast
160
166
  tonalOffset = 0.2,
161
167
  context = 'local'
162
168
  } = palette,
163
- other = _objectWithoutProperties(palette, ["primary", "secondary", "positive", "negative", "middle", "neutral", "error", "type", "contrastThreshold", "tonalOffset", "context"]);
169
+ other = _objectWithoutProperties(palette, ["primary", "secondary", "positive", "negative", "middle", "neutral", "error", "lookup", "type", "contrastThreshold", "tonalOffset", "context"]);
164
170
 
165
171
  function getContrastText(background) {
166
172
  // Use the same logic as
@@ -225,6 +231,8 @@ export default function createPalette(palette) {
225
231
  neutral,
226
232
  // The colors used to represent interface elements that the user should be made aware of.
227
233
  error,
234
+ // The colors used to represent form elements that have lookup state.
235
+ lookup,
228
236
  // The grey colors.
229
237
  grey,
230
238
  // Used by `getContrastText()` to maximize the contrast between the background and
package/index.es.js CHANGED
@@ -1,4 +1,4 @@
1
- /** @license HiPay-Material-UI v2.0.0-beta.50
1
+ /** @license HiPay-Material-UI v2.0.0-beta.52
2
2
  *
3
3
  * This source code is licensed under the MIT license found in the
4
4
  * LICENSE file in the root directory of this source tree.
package/index.js CHANGED
@@ -1,4 +1,4 @@
1
- /** @license HiPay-Material-UI v2.0.0-beta.50
1
+ /** @license HiPay-Material-UI v2.0.0-beta.52
2
2
  *
3
3
  * This source code is licensed under the MIT license found in the
4
4
  * LICENSE file in the root directory of this source tree.
package/package.json CHANGED
@@ -2,7 +2,7 @@
2
2
  "name": "@hipay/hipay-material-ui",
3
3
  "private": false,
4
4
  "author": "HiPay PSYCHE Team",
5
- "version": "2.0.0-beta.50",
5
+ "version": "2.0.0-beta.52",
6
6
  "description": "React components that implement Google's Material Design.",
7
7
  "keywords": [
8
8
  "react",
@@ -155,6 +155,7 @@ function createPalette(palette) {
155
155
  } : _palette$positive,
156
156
  _palette$negative = palette.negative,
157
157
  negative = _palette$negative === void 0 ? {
158
+ ultraLight: '#EA9494',
158
159
  light: '#E66666',
159
160
  main: '#D50000',
160
161
  dark: '#A00000',
@@ -169,6 +170,7 @@ function createPalette(palette) {
169
170
  } : _palette$middle,
170
171
  _palette$neutral = palette.neutral,
171
172
  neutral = _palette$neutral === void 0 ? {
173
+ ultraLight: '#8B8B8B',
172
174
  light: '#838383',
173
175
  main: '#737373',
174
176
  dark: '#20272B',
@@ -180,6 +182,11 @@ function createPalette(palette) {
180
182
  main: _red.default[500],
181
183
  dark: _red.default[700]
182
184
  } : _palette$error,
185
+ _palette$lookup = palette.lookup,
186
+ lookup = _palette$lookup === void 0 ? {
187
+ light: '#FFFF8D',
188
+ main: '#EDED14'
189
+ } : _palette$lookup,
183
190
  _palette$type = palette.type,
184
191
  type = _palette$type === void 0 ? 'light' : _palette$type,
185
192
  _palette$contrastThre = palette.contrastThreshold,
@@ -188,7 +195,7 @@ function createPalette(palette) {
188
195
  tonalOffset = _palette$tonalOffset === void 0 ? 0.2 : _palette$tonalOffset,
189
196
  _palette$context = palette.context,
190
197
  context = _palette$context === void 0 ? 'local' : _palette$context,
191
- other = (0, _objectWithoutProperties2.default)(palette, ["primary", "secondary", "positive", "negative", "middle", "neutral", "error", "type", "contrastThreshold", "tonalOffset", "context"]);
198
+ other = (0, _objectWithoutProperties2.default)(palette, ["primary", "secondary", "positive", "negative", "middle", "neutral", "error", "lookup", "type", "contrastThreshold", "tonalOffset", "context"]);
192
199
 
193
200
  function getContrastText(background) {
194
201
  // Use the same logic as
@@ -257,6 +264,8 @@ function createPalette(palette) {
257
264
  neutral: neutral,
258
265
  // The colors used to represent interface elements that the user should be made aware of.
259
266
  error: error,
267
+ // The colors used to represent form elements that have lookup state.
268
+ lookup: lookup,
260
269
  // The grey colors.
261
270
  grey: _grey.default,
262
271
  // Used by `getContrastText()` to maximize the contrast between the background and