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

Sign up to get free protection for your applications and to get access to all the features.
@@ -0,0 +1,406 @@
1
+ import _extends from "@babel/runtime/helpers/extends";
2
+ import _objectWithoutProperties from "@babel/runtime/helpers/objectWithoutProperties";
3
+ import _objectSpread from "@babel/runtime/helpers/objectSpread";
4
+ // @inheritedComponent HiSelectContent
5
+ import React from 'react';
6
+ import PropTypes from 'prop-types';
7
+ import HiSelectContent from './HiSelectContent';
8
+ import HiIcon from '../HiIcon';
9
+ import withStyles from '../styles/withStyles';
10
+ import { foldAccents } from '../utils/helpers';
11
+ /**
12
+ * Return array of final item id in nested list (via props chlidren)
13
+ * @param itemList
14
+ * @param finalItemIdList
15
+ * @returns {*[]}
16
+ */
17
+
18
+ export function getRecursiveFinalItemIdList(itemList, finalItemIdList = []) {
19
+ return [...finalItemIdList, ...itemList.reduce((memo, item) => {
20
+ if (item.children) {
21
+ return getRecursiveFinalItemIdList(item.children, memo);
22
+ }
23
+
24
+ return [...memo, item.id];
25
+ }, [])];
26
+ }
27
+ /**
28
+ * Find item by id in nested list (via props children)
29
+ * @param itemList
30
+ * @param searchId
31
+ * @returns {boolean}
32
+ */
33
+
34
+ export function findFinalItemRecursively(itemList, searchId) {
35
+ let foundItem = false;
36
+ itemList.some(item => {
37
+ if (item.id === searchId) {
38
+ foundItem = item;
39
+ } else if (item.children && !foundItem) {
40
+ foundItem = findFinalItemRecursively(item.children, searchId);
41
+ }
42
+
43
+ return foundItem !== false;
44
+ });
45
+ return foundItem;
46
+ }
47
+ /**
48
+ * Build item list by settings item props relative to the nested parent/child situation
49
+ * Reduce the item list to build specified items (displayed, pinned, disabled, selected, indeterminate)
50
+ * Parent item is selected if each children item is include in selectedItemIdList (s stay to true)
51
+ * Parent item is indeterminate if it is not selected & not unselected (s goes false & u goes false)
52
+ *
53
+ * @param itemList - initial list of item
54
+ * @param selectedItemIdList - global list of selected id
55
+ * @param searchValue - search value on which filter item
56
+ * @param visibleParent - visibility of the list parent item (default false)
57
+ * @param pinnedParent - parent will be displayed as pinned items
58
+ * @param disabledParent - parent will not be selectable
59
+ * @param nbChildrenAsInfo - Show children number as info
60
+ * @param translations - Translations
61
+ * @returns {*}
62
+ */
63
+
64
+ function buildFilteredItemList(itemList, selectedItemIdList = [], searchValue = '', visibleParent = false, pinnedParent = false, disabledParent = false, nbChildrenAsInfo = false, translations) {
65
+ return itemList.reduce(({
66
+ l: memoItemList,
67
+ s: memoSelected,
68
+ u: memoUnselected,
69
+ v: memoVisible
70
+ }, item) => {
71
+ const itemVisible = searchValue === '' || foldAccents(item.label.toString().toLowerCase()).search(foldAccents(searchValue.toLowerCase())) !== -1; // Parent item
72
+
73
+ if (item.children) {
74
+ const {
75
+ l: customizedChildren,
76
+ s: selected,
77
+ u: unselected,
78
+ v: visible
79
+ } = buildFilteredItemList(item.children, selectedItemIdList, searchValue, itemVisible, pinnedParent, disabledParent);
80
+
81
+ if (nbChildrenAsInfo) {
82
+ item.info = translations.n_children.replace('%s', item.children.length);
83
+ }
84
+
85
+ return {
86
+ l: [...memoItemList, _objectSpread({}, item, disabledParent && {
87
+ disabled: true,
88
+ hideCheckbox: true // don't display checkbox on disabled parent
89
+
90
+ }, {
91
+ pinned: pinnedParent,
92
+ children: customizedChildren,
93
+ selected,
94
+ indeterminate: !selected && !unselected,
95
+ displayed: itemVisible || visible
96
+ })],
97
+ s: memoSelected && selected,
98
+ u: memoUnselected && unselected,
99
+ v: memoVisible || itemVisible || visible
100
+ };
101
+ }
102
+
103
+ const itemSelected = selectedItemIdList.includes(item.id);
104
+ return {
105
+ l: [...memoItemList, _objectSpread({
106
+ displayed: itemVisible || visibleParent
107
+ }, item)],
108
+ s: itemSelected && memoSelected,
109
+ u: !itemSelected && memoUnselected,
110
+ v: itemVisible || visibleParent || memoVisible
111
+ };
112
+ }, {
113
+ l: [],
114
+ s: true,
115
+ u: true,
116
+ v: visibleParent
117
+ });
118
+ }
119
+
120
+ export const styles = theme => ({
121
+ root: {
122
+ backgroundColor: theme.palette.background2,
123
+ maxWidth: 500,
124
+ width: '100%',
125
+ position: 'relative'
126
+ },
127
+ popper: {
128
+ // width: '100%',
129
+ zIndex: 1200
130
+ },
131
+ paper: {
132
+ borderRadius: '0px 2px',
133
+ maxHeight: 480,
134
+ transition: 'none !important'
135
+ },
136
+ labelImg: {
137
+ height: 18,
138
+ width: 'auto',
139
+ margin: '0 4px',
140
+ verticalAlign: 'middle'
141
+ },
142
+ selectIconLabel: _objectSpread({
143
+ whiteSpace: 'nowrap',
144
+ overflow: 'hidden',
145
+ textOverflow: 'ellipsis',
146
+ paddingRight: 16
147
+ }, theme.typography.b1, {
148
+ display: 'inline-flex',
149
+ width: '100%'
150
+ }),
151
+ selectImgLabel: _objectSpread({
152
+ whiteSpace: 'nowrap',
153
+ overflow: 'hidden',
154
+ textOverflow: 'ellipsis',
155
+ paddingRight: 16
156
+ }, theme.typography.b1, {
157
+ display: 'inline-flex',
158
+ width: '100%'
159
+ })
160
+ });
161
+ /**
162
+ * HiNestedSelectContent hérite du composant HiSelectContent
163
+ *
164
+ * Sa fonction buildSelectProps construit la liste des options selon le comportement d'un object nested
165
+ * (association parent/child via la prop children). Le composant accepte des props spécifique à cet utilisation,
166
+ * comme disableParent ou pinnedParent. Uniquement les ids des enfants finaux (n'ayant pas d'enfants) sont considérés.
167
+ * Comportement:
168
+ * - si un parent est sélectionné, on ajoute tous ses enfants dans la liste des éléments sélectionné (mais pas le parent)
169
+ * - si tous les enfants sont sélectionnés, le parent est affiché "selected".
170
+ * - si une partie des enfants sont sélectionné, le parent est affiché "indeterminate".
171
+ * - si aucun enfant n'est sélectionné, le parent est affiché "unselected".
172
+ */
173
+
174
+ class HiNestedSelectContent extends React.PureComponent {
175
+ constructor(props) {
176
+ super(props);
177
+
178
+ this.handleSelect = (event, item) => {
179
+ const {
180
+ hasAll,
181
+ multiple,
182
+ onChange,
183
+ options,
184
+ value
185
+ } = this.props;
186
+
187
+ if (!multiple) {
188
+ // single value
189
+ onChange(event, item.id, item);
190
+ } else if (hasAll && item.id === '_all') {
191
+ // ALL
192
+ const selectableItemIdList = getRecursiveFinalItemIdList(options);
193
+
194
+ if (value.length === selectableItemIdList.length) {
195
+ // unselect _all options
196
+ onChange(event, [], item);
197
+ } else {
198
+ // select _all options
199
+ onChange(event, selectableItemIdList, item);
200
+ }
201
+ } else if (item.children) {
202
+ // PARENT
203
+ const parentSelectableItemIdList = getRecursiveFinalItemIdList(item.children); // deselect parent if every selectable child id is includes in value.
204
+
205
+ if (parentSelectableItemIdList.every(pid => value.includes(pid))) {
206
+ onChange(event, value.filter(vid => !parentSelectableItemIdList.includes(vid)), item);
207
+ } else {
208
+ // select parent > add each selectable child without duplicates.
209
+ onChange(event, [...value.filter(vid => !parentSelectableItemIdList.includes(vid)), ...parentSelectableItemIdList], item);
210
+ }
211
+ } else if (value.includes(item.id)) {
212
+ // unselect item
213
+ onChange(event, value.filter(id => id !== item.id), item);
214
+ } else {
215
+ onChange(event, [...value, item.id], item);
216
+ }
217
+ };
218
+
219
+ this.buildSelectProps = (options, value = [], search = '', loading = false) => {
220
+ const {
221
+ classes,
222
+ disabledParent,
223
+ hasAll,
224
+ iconAll,
225
+ multiple,
226
+ nbChildrenAsInfo,
227
+ pinnedParent,
228
+ translations
229
+ } = this.props; // build item list
230
+
231
+ const {
232
+ l: filteredItemList,
233
+ s: allSelected,
234
+ u: allUnselected,
235
+ v: visible
236
+ } = buildFilteredItemList(options, value, search, false, pinnedParent, disabledParent || !multiple, nbChildrenAsInfo, translations);
237
+ const itemList = !visible ? [...(loading ? [{
238
+ id: '_loading',
239
+ type: 'loader',
240
+ disabled: true,
241
+ centered: true,
242
+ hideCheckbox: true,
243
+ label: 'loading'
244
+ }] : [{
245
+ id: '_no_result',
246
+ type: 'text',
247
+ disabled: true,
248
+ centered: true,
249
+ hideCheckbox: true,
250
+ label: translations.no_result_match
251
+ }])] : [...(loading ? [{
252
+ id: '_loading',
253
+ type: 'loader',
254
+ disabled: true,
255
+ centered: true,
256
+ hideCheckbox: true,
257
+ label: 'loading'
258
+ }] : []), ...(hasAll ? [{
259
+ id: '_all',
260
+ iconAll,
261
+ label: translations.all,
262
+ selected: allSelected,
263
+ indeterminate: !allSelected && !allUnselected,
264
+ displayed: search === ''
265
+ }] : []), ...filteredItemList];
266
+ return {
267
+ itemList
268
+ };
269
+ };
270
+
271
+ this.handleSelect = this.handleSelect.bind(this);
272
+ }
273
+ /**
274
+ * Call onChange with the updated value
275
+ *
276
+ * - handle single value
277
+ * - handle multiple value
278
+ * - handle '_all' id
279
+ *
280
+ * @param event
281
+ * @param item
282
+ */
283
+
284
+
285
+ render() {
286
+ const _this$props = this.props,
287
+ {
288
+ hasAll,
289
+ hiSelectableListProps,
290
+ multiple,
291
+ options,
292
+ searchable,
293
+ translations,
294
+ value
295
+ } = _this$props,
296
+ other = _objectWithoutProperties(_this$props, ["hasAll", "hiSelectableListProps", "multiple", "options", "searchable", "translations", "value"]);
297
+
298
+ if (multiple) {
299
+ if (!Array.isArray(value)) {
300
+ throw new Error('HiPay Material-UI: the `value` property must be an array ' + 'when using the `HiSelect` component with `multiple`.');
301
+ }
302
+ }
303
+
304
+ return React.createElement(HiSelectContent, _extends({
305
+ buildSelectProps: this.buildSelectProps,
306
+ hasAll: hasAll,
307
+ hiSelectableListProps: _objectSpread({
308
+ onSelect: this.handleSelect
309
+ }, hiSelectableListProps),
310
+ multiple: multiple,
311
+ options: options,
312
+ searchable: searchable,
313
+ translations: translations,
314
+ value: value
315
+ }, other));
316
+ }
317
+
318
+ }
319
+
320
+ HiNestedSelectContent.defaultProps = {
321
+ disabledParent: false,
322
+ hasAll: false,
323
+ multiple: false,
324
+ pinnedParent: false,
325
+ searchable: false,
326
+ translations: {
327
+ all: 'All',
328
+ no_result_match: 'No result match',
329
+ search: 'Search',
330
+ n_children: '%s',
331
+ one_child: '%s item'
332
+ }
333
+ };
334
+ HiNestedSelectContent.propTypes = process.env.NODE_ENV !== "production" ? {
335
+ /**
336
+ * Useful to extend the style applied to components.
337
+ */
338
+ classes: PropTypes.object,
339
+
340
+ /**
341
+ * Parent items are not selectable
342
+ */
343
+ disabledParent: PropTypes.bool,
344
+
345
+ /**
346
+ * Affiche l'élément 'All'
347
+ */
348
+ hasAll: PropTypes.bool,
349
+
350
+ /**
351
+ * id du select
352
+ */
353
+ id: PropTypes.string,
354
+
355
+ /**
356
+ * Ajoute un loader
357
+ */
358
+ loading: PropTypes.bool,
359
+
360
+ /**
361
+ * Autorise la sélection de plusieurs valeurs
362
+ */
363
+ multiple: PropTypes.bool,
364
+
365
+ /**
366
+ * Définit si l'on doit afficher le nombre d'enfants du parent dans son champ info
367
+ */
368
+ nbChildrenAsInfo: PropTypes.bool,
369
+
370
+ /**
371
+ * Fonction de callback qui renvoit la/les valeurs sélectionnées
372
+ *
373
+ * @param {object} event
374
+ * @param {string || array} value
375
+ */
376
+ onChange: PropTypes.func.isRequired,
377
+
378
+ /**
379
+ * Listes des options du select
380
+ */
381
+ options: PropTypes.array.isRequired,
382
+
383
+ /**
384
+ * Parent items are pinned, with sticky behavior (hide checkboxes but still selectable)
385
+ */
386
+ pinnedParent: PropTypes.bool,
387
+
388
+ /**
389
+ * Affiche un input de recherche permettant de filtrer les options
390
+ */
391
+ searchable: PropTypes.bool,
392
+
393
+ /**
394
+ * Traductions (par défaut en anglais)
395
+ */
396
+ translations: PropTypes.object,
397
+
398
+ /**
399
+ * Value(s) du select
400
+ */
401
+ value: PropTypes.oneOfType([PropTypes.number, PropTypes.string, PropTypes.array])
402
+ } : {};
403
+ export default withStyles(styles, {
404
+ hiComponent: true,
405
+ name: 'HmuiHiNestedSelectContent'
406
+ })(HiNestedSelectContent);