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

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1,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);