superdesk-ui-framework 3.0.43 → 3.0.45

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.
@@ -1,14 +1,16 @@
1
1
  import * as React from "react";
2
- import { Icon } from "./Icon";
3
- import { Loader } from "./Loader";
2
+ import { Icon } from "../Icon";
3
+ import { Loader } from "../Loader";
4
4
  import nextId from "react-id-generator";
5
5
  import _debounce from 'lodash/debounce';
6
- import { InputWrapper } from "./Form";
6
+ import { InputWrapper } from "../Form";
7
7
  import { createPopper, Instance } from '@popperjs/core';
8
8
  import {isEqual} from 'lodash';
9
- import {getTextColor} from './Label';
10
- import {IInputWrapper} from './Form/InputWrapper';
11
- import {SelectPreview} from './SelectPreview';
9
+ import {getTextColor} from '../Label';
10
+ import {IInputWrapper} from '../Form/InputWrapper';
11
+ import {SelectPreview} from '../SelectPreview';
12
+ import {TreeSelectPill} from './TreeSelectPill';
13
+ import {getPrefixedItemId, TreeSelectItem} from './TreeSelectItem';
12
14
 
13
15
  interface IState<T> {
14
16
  value: Array<T>;
@@ -22,7 +24,9 @@ interface IState<T> {
22
24
  buttonValue: ITreeNode<T> | null;
23
25
  buttonMouseEvent: boolean;
24
26
  loading: boolean;
25
- buttonTarget: Array<string>; // array of class names
27
+
28
+ // array of classNames; used to focus an item after returning for another level
29
+ buttonTarget: Array<string>;
26
30
  }
27
31
 
28
32
  interface IPropsBase<T> extends IInputWrapper {
@@ -71,6 +75,7 @@ export class TreeSelect<T> extends React.Component<IProps<T>, IState<T>> {
71
75
  private inputRef: React.RefObject<HTMLInputElement>;
72
76
  private categoryButtonRef: React.RefObject<HTMLButtonElement>;
73
77
  private openDropdownRef: React.RefObject<HTMLButtonElement>;
78
+ private treeSelectRef: React.RefObject<HTMLDivElement>;
74
79
  private htmlId: string = nextId();
75
80
  private popperInstance: Instance | null;
76
81
 
@@ -80,22 +85,21 @@ export class TreeSelect<T> extends React.Component<IProps<T>, IState<T>> {
80
85
  value: this.props.value ? this.props.value : [],
81
86
  options: this.props.getOptions ? this.props.getOptions() : [],
82
87
  firstBranchOptions: this.props.getOptions ? this.props.getOptions() : [],
88
+ searchFieldValue: '',
83
89
  activeTree: [],
84
90
  filterArr: [],
85
- searchFieldValue: '',
86
91
  buttonTree: [],
92
+ buttonTarget: [],
87
93
  buttonValue: null,
88
94
  buttonMouseEvent: false,
89
95
  openDropdown: false,
90
96
  loading: false,
91
- buttonTarget: [],
92
97
  };
93
98
 
94
99
  this.removeClick = this.removeClick.bind(this);
95
100
  this.handleMultiLevel = this.handleMultiLevel.bind(this);
96
101
  this.backButton = this.backButton.bind(this);
97
102
  this.handleButton = this.handleButton.bind(this);
98
- this.backButtonValue = this.backButtonValue.bind(this);
99
103
  this.handleTree = this.handleTree.bind(this);
100
104
  this.filteredItem = this.filteredItem.bind(this);
101
105
  this.branchButton = this.branchButton.bind(this);
@@ -108,24 +112,27 @@ export class TreeSelect<T> extends React.Component<IProps<T>, IState<T>> {
108
112
  this.inputRef = React.createRef();
109
113
  this.categoryButtonRef = React.createRef();
110
114
  this.openDropdownRef = React.createRef();
115
+ this.treeSelectRef = React.createRef();
111
116
  this.popperInstance = null;
112
117
  }
113
118
 
114
119
  inputFocus = () => {
115
120
  this.inputRef.current?.focus();
116
121
  }
122
+
117
123
  listNavigation = () => {
118
124
  const element: HTMLElement = document.querySelector('.suggestion-item--btn') as HTMLElement;
119
125
  element.focus();
120
126
  }
127
+
121
128
  buttonFocus = () => {
122
129
  this.categoryButtonRef.current?.focus();
123
130
  }
124
131
 
125
132
  onMouseDown = (event: MouseEvent) => {
126
133
  if (
127
- (this.dropdownRef.current?.contains(event.target as HTMLElement) !== true)
128
- && (this.openDropdownRef.current?.contains(event.target as HTMLElement) !== true)
134
+ (this.treeSelectRef .current?.contains(event.target as HTMLElement) !== true)
135
+ && this.state.openDropdown
129
136
  ) {
130
137
  this.setState({openDropdown: false});
131
138
  }
@@ -138,14 +145,14 @@ export class TreeSelect<T> extends React.Component<IProps<T>, IState<T>> {
138
145
  this.ref.current,
139
146
  this.categoryButtonRef.current ? this.buttonFocus : this.inputFocus,
140
147
  );
141
- if (e.key === 'Backspace') {
148
+
149
+ if (e.key === 'Backspace' && this.state.activeTree.length > 0) {
142
150
  this.backButton();
143
- this.backButtonValue();
144
151
 
145
- const {buttonTarget} = this.state;
146
- const className = `${buttonTarget.pop()}-focus`;
152
+ const lastElement = this.state.buttonTarget.pop();
147
153
 
148
- if (className != null) {
154
+ if (lastElement != null) {
155
+ const className = getPrefixedItemId(lastElement);
149
156
  const element: HTMLElement = document.getElementsByClassName(className)[0] as HTMLElement;
150
157
  element.focus();
151
158
  }
@@ -171,13 +178,17 @@ export class TreeSelect<T> extends React.Component<IProps<T>, IState<T>> {
171
178
  } else if (!isEqual(prevProps.value, this.props.value)) {
172
179
  this.props.onChange(this.state.value);
173
180
  }
181
+
174
182
  if (prevState.openDropdown !== this.state.openDropdown) {
175
183
  this.toggleMenu();
176
184
  }
185
+
177
186
  if (this.props.kind === 'synchronous') {
178
- if ((prevState.activeTree !== this.state.activeTree)
179
- || (prevState.filterArr !== this.state.filterArr)
180
- || (prevState.options !== this.state.options)) {
187
+ if (
188
+ (prevState.activeTree !== this.state.activeTree)
189
+ || (prevState.filterArr !== this.state.filterArr)
190
+ || (prevState.options !== this.state.options)
191
+ ) {
181
192
  this.popperInstance?.update();
182
193
  }
183
194
  }
@@ -198,6 +209,7 @@ export class TreeSelect<T> extends React.Component<IProps<T>, IState<T>> {
198
209
  ],
199
210
  });
200
211
  }
212
+
201
213
  this.inputRef.current?.addEventListener('keydown', (e: KeyboardEvent) => {
202
214
  if (e.key === 'ArrowDown') {
203
215
  e.preventDefault();
@@ -212,6 +224,7 @@ export class TreeSelect<T> extends React.Component<IProps<T>, IState<T>> {
212
224
  }
213
225
  }
214
226
  });
227
+
215
228
  if (this.inputRef.current) {
216
229
  this.inputFocus();
217
230
  } else {
@@ -230,6 +243,7 @@ export class TreeSelect<T> extends React.Component<IProps<T>, IState<T>> {
230
243
  this.setState({
231
244
  value: newTags,
232
245
  });
246
+
233
247
  this.props.onChange(this.state.value);
234
248
  }
235
249
 
@@ -260,9 +274,11 @@ export class TreeSelect<T> extends React.Component<IProps<T>, IState<T>> {
260
274
  let checkItem = this.state.value.find((valueItem: T) => {
261
275
  return this.props.getId(valueItem) === this.props.getId(item.value);
262
276
  });
277
+
263
278
  if (!checkItem) {
264
279
  this.setState({value: [...this.state.value, item.value]});
265
280
  }
281
+
266
282
  if (!event.ctrlKey) {
267
283
  if (this.props.getOptions) {
268
284
  this.setState({
@@ -275,14 +291,17 @@ export class TreeSelect<T> extends React.Component<IProps<T>, IState<T>> {
275
291
  this.setState({activeTree: [], buttonTarget: [], openDropdown: false});
276
292
  }
277
293
  }
294
+
278
295
  this.setState({buttonMouseEvent: false});
279
296
  } else {
280
297
  let checkItem = this.state.value.find((valueItem: T) => {
281
298
  return this.props.getId(valueItem) === this.props.getId(item.value);
282
299
  });
300
+
283
301
  if (!checkItem) {
284
302
  this.setState({value: [item.value]});
285
303
  }
304
+
286
305
  if (!event.ctrlKey) {
287
306
  this.setState({
288
307
  options: this.state.firstBranchOptions,
@@ -292,47 +311,50 @@ export class TreeSelect<T> extends React.Component<IProps<T>, IState<T>> {
292
311
  openDropdown: false,
293
312
  });
294
313
  }
314
+
295
315
  this.setState({buttonMouseEvent: false});
296
316
  }
297
317
  }
298
318
 
299
319
  handleBranchValue(event: React.MouseEvent<HTMLButtonElement, MouseEvent>, item: ITreeNode<T>) {
300
320
  if (this.props.allowMultiple) {
301
- if (this.props.selectBranchWithChildren) {
302
- let checkItem = this.state.value.find((valueItem: T) => {
303
- return this.props.getId(valueItem) === this.props.getId(item.value);
321
+ let checkItem = this.state.value.find((valueItem: T) => {
322
+ return this.props.getId(valueItem) === this.props.getId(item.value);
323
+ });
324
+
325
+ if (!checkItem) {
326
+ this.setState({value: [...this.state.value, item.value]});
327
+ }
328
+
329
+ if (!event.ctrlKey) {
330
+ this.setState({
331
+ options: this.state.firstBranchOptions,
332
+ activeTree: [],
333
+ buttonTarget: [],
334
+ openDropdown: false,
304
335
  });
305
- if (!checkItem) {
306
- this.setState({value: [...this.state.value, item.value]});
307
- }
308
- if (!event.ctrlKey) {
309
- this.setState({
310
- options: this.state.firstBranchOptions,
311
- activeTree: [],
312
- buttonTarget: [],
313
- openDropdown: false,
314
- });
315
- }
316
- this.setState({buttonMouseEvent: false});
317
336
  }
337
+
338
+ this.setState({buttonMouseEvent: false});
318
339
  } else {
319
- if (this.props.selectBranchWithChildren) {
320
- let checkItem = this.state.value.find((valueItem: T) => {
321
- return this.props.getId(valueItem) === this.props.getId(item.value);
340
+ let checkItem = this.state.value.find((valueItem: T) => {
341
+ return this.props.getId(valueItem) === this.props.getId(item.value);
342
+ });
343
+
344
+ if (!checkItem) {
345
+ this.setState({value: [item.value]});
346
+ }
347
+
348
+ if (!event.ctrlKey) {
349
+ this.setState({
350
+ options: this.state.firstBranchOptions,
351
+ activeTree: [],
352
+ buttonTarget: [],
353
+ openDropdown: false,
322
354
  });
323
- if (!checkItem) {
324
- this.setState({value: [item.value]});
325
- }
326
- if (!event.ctrlKey) {
327
- this.setState({
328
- options: this.state.firstBranchOptions,
329
- activeTree: [],
330
- buttonTarget: [],
331
- openDropdown: false,
332
- });
333
- }
334
- this.setState({buttonMouseEvent: false});
335
355
  }
356
+
357
+ this.setState({buttonMouseEvent: false});
336
358
  }
337
359
  }
338
360
 
@@ -340,14 +362,17 @@ export class TreeSelect<T> extends React.Component<IProps<T>, IState<T>> {
340
362
  if (option.children) {
341
363
  this.handleButton(option);
342
364
  this.handleMultiLevel(option);
365
+
343
366
  if (event.altKey && this.props.allowMultiple) {
344
367
  if (this.props.selectBranchWithChildren) {
345
368
  let filteredItems: Array<T> = [];
369
+
346
370
  option.children.forEach((item: { value: T; }) => {
347
371
  if (!this.state.value.includes(item.value)) {
348
372
  filteredItems.push(item.value);
349
373
  }
350
374
  });
375
+
351
376
  this.setState({
352
377
  value: [...this.state.value, ...filteredItems],
353
378
  options: this.state.firstBranchOptions,
@@ -357,12 +382,14 @@ export class TreeSelect<T> extends React.Component<IProps<T>, IState<T>> {
357
382
  });
358
383
  } else {
359
384
  let filteredItems: Array<T> = [];
385
+
360
386
  option.children.forEach((item: ITreeNode<T>) => {
361
387
  if (!this.state.value.includes(item.value)
362
388
  && !item.children) {
363
389
  filteredItems.push(item.value);
364
390
  }
365
391
  });
392
+
366
393
  if (filteredItems.length > 0) {
367
394
  this.setState({
368
395
  value: [...this.state.value, ...filteredItems],
@@ -376,6 +403,7 @@ export class TreeSelect<T> extends React.Component<IProps<T>, IState<T>> {
376
403
  }
377
404
  } else {
378
405
  this.handleValue(event, option);
406
+
379
407
  if (!event.ctrlKey) {
380
408
  this.setState({openDropdown: false});
381
409
  }
@@ -393,9 +421,7 @@ export class TreeSelect<T> extends React.Component<IProps<T>, IState<T>> {
393
421
  options: items,
394
422
  });
395
423
  }
396
- }
397
424
 
398
- backButtonValue = () => {
399
425
  const item = this.state.buttonTree.pop();
400
426
 
401
427
  if (item != null) {
@@ -408,6 +434,7 @@ export class TreeSelect<T> extends React.Component<IProps<T>, IState<T>> {
408
434
  recursion(arr: Array<ITreeNode<T>>) {
409
435
  arr.map((item) => {
410
436
  this.state.filterArr.push(item);
437
+
411
438
  if (item.children) {
412
439
  this.recursion(item.children);
413
440
  }
@@ -419,7 +446,9 @@ export class TreeSelect<T> extends React.Component<IProps<T>, IState<T>> {
419
446
  let filteredArr = arr.filter((item) => {
420
447
  if (this.state.searchFieldValue) {
421
448
  if (this.props.getLabel(item.value)
422
- .toLowerCase().includes(this.state.searchFieldValue.toLowerCase())) {
449
+ .toLowerCase()
450
+ .includes(this.state.searchFieldValue.toLowerCase())
451
+ ) {
423
452
  return item.value;
424
453
  } else {
425
454
  return;
@@ -430,59 +459,29 @@ export class TreeSelect<T> extends React.Component<IProps<T>, IState<T>> {
430
459
  });
431
460
 
432
461
  if (filteredArr.length === 0) {
433
- return <li className="suggestion-item--nothing-found">Nothing fonud</li>;
462
+ return <li className="suggestion-item--nothing-found">Nothing found</li>;
434
463
  } else {
435
464
  return filteredArr.map((option, i) => {
436
465
  let selectedItem = this.state.value.some((obj) =>
437
466
  this.props.getId(obj) === this.props.getId(option.value),
438
467
  );
468
+
439
469
  return (
440
- <li
470
+ <TreeSelectItem
441
471
  key={i}
442
- className={`suggestion-item suggestion-item--multi-select`}
443
- onClick={(event) => {
444
- this.setState({
445
- searchFieldValue: '',
446
- }),
447
- event.preventDefault();
448
- event.stopPropagation();
449
- this.handleTree(event, option);
450
- }}
451
- >
452
- <button className="suggestion-item--btn">
453
- {this.props.getBorderColor
454
- && <div
455
- className="item-border"
456
- style={{
457
- backgroundColor: this.props.getBorderColor(option.value),
458
- }}
459
- >
460
- </div>
461
- }
462
- <span
463
- className={'suggestion-item--bgcolor'
464
- + (selectedItem ? ' suggestion-item--disabled' : '')
465
- }
466
- style={this.props.getBackgroundColor
467
- ? {
468
- backgroundColor: this.props.getBackgroundColor(option.value),
469
- color: getTextColor(this.props.getBackgroundColor(option.value)),
470
- }
471
- : undefined
472
- }
473
- >
474
- {this.props.optionTemplate
475
- ? this.props.optionTemplate(option.value)
476
- : this.props.getLabel(option.value)
477
- }
478
- </span>
479
- {option.children
480
- && <span className="suggestion-item__icon">
481
- <Icon name="chevron-right-thin"></Icon>
482
- </span>
483
- }
484
- </button>
485
- </li>
472
+ option={option}
473
+ handleTree={this.handleTree}
474
+ selectedItem={selectedItem}
475
+ allowMultiple={this.props.allowMultiple}
476
+ getBorderColor={this.props.getBorderColor}
477
+ getBackgroundColor={this.props.getBackgroundColor}
478
+ getId={this.props.getId}
479
+ optionTemplate={this.props.optionTemplate}
480
+ getLabel={this.props.getLabel}
481
+ onClick={() => this.setState({
482
+ searchFieldValue: '',
483
+ })}
484
+ />
486
485
  );
487
486
  });
488
487
  }
@@ -491,23 +490,25 @@ export class TreeSelect<T> extends React.Component<IProps<T>, IState<T>> {
491
490
  let selectedItem = this.state.value.some((obj) =>
492
491
  this.props.getId(obj) === this.props.getId(item.value),
493
492
  );
493
+
494
494
  return (
495
495
  <li
496
496
  key={i}
497
- className={`suggestion-item suggestion-item--multi-select`}
497
+ className='suggestion-item suggestion-item--multi-select'
498
498
  onClick={(event) => {
499
- this.handleValue(event, item);
499
+ this.handleValue(event, item);
500
500
  }}
501
501
  >
502
502
  <button className="suggestion-item--btn">
503
503
  {this.props.optionTemplate
504
504
  ? this.props.optionTemplate(item.value)
505
- : <span
506
- className={selectedItem
507
- ? 'suggestion-item--disabled' : undefined}
508
- >
509
- {this.props.getLabel(item.value)}
510
- </span>
505
+ : (
506
+ <span
507
+ className={selectedItem ? 'suggestion-item--disabled' : undefined}
508
+ >
509
+ {this.props.getLabel(item.value)}
510
+ </span>
511
+ )
511
512
  }
512
513
  </button>
513
514
  </li>
@@ -524,15 +525,17 @@ export class TreeSelect<T> extends React.Component<IProps<T>, IState<T>> {
524
525
  if (e.key === 'ArrowDown') {
525
526
  e.preventDefault();
526
527
  e.stopPropagation();
528
+
527
529
  setTimeout(() => {
528
- const element: HTMLElement
529
- = document.querySelector('.suggestion-item--btn') as HTMLElement;
530
+ const element: HTMLElement = document.querySelector('.suggestion-item--btn') as HTMLElement;
530
531
  element.focus();
531
532
  });
532
533
  }
534
+
533
535
  if (e.key === 'ArrowUp') {
534
536
  e.preventDefault();
535
537
  e.stopPropagation();
538
+
536
539
  this.inputRef.current?.focus();
537
540
  }
538
541
  });
@@ -543,22 +546,25 @@ export class TreeSelect<T> extends React.Component<IProps<T>, IState<T>> {
543
546
  );
544
547
 
545
548
  if (!selectedButton) {
546
- return <button
547
- className={'autocomplete__button' + (this.props.selectBranchWithChildren ? ' autocomplete__button--multi-select' : '')}
548
- ref={this.categoryButtonRef}
549
- onMouseOver={() => this.setState({buttonMouseEvent: true})}
550
- onMouseOut={() => this.setState({buttonMouseEvent: false})}
551
- onClick={(event) => this.handleBranchValue(event, buttonValue)}
552
- >
553
- Choose entire category
554
- </button>;
549
+ return (
550
+ <button
551
+ className='autocomplete__button autocomplete__button--multi-select'
552
+ ref={this.categoryButtonRef}
553
+ onMouseOver={() => this.setState({buttonMouseEvent: true})}
554
+ onMouseOut={() => this.setState({buttonMouseEvent: false})}
555
+ onClick={(event) => this.handleBranchValue(event, buttonValue)}
556
+ >
557
+ Choose entire category
558
+ </button>
559
+ );
555
560
  } else {
556
- return <button
557
- className={'autocomplete__button'
558
- + (this.props.selectBranchWithChildren ? ' autocomplete__button--multi-select' : '') + ' autocomplete__button--disabled'}
559
- >
560
- Category selected
561
- </button>;
561
+ return (
562
+ <button
563
+ className='autocomplete__button autocomplete__button--multi-select autocomplete__button--disabled'
564
+ >
565
+ Category selected
566
+ </button>
567
+ );
562
568
  }
563
569
  }
564
570
 
@@ -567,11 +573,13 @@ export class TreeSelect<T> extends React.Component<IProps<T>, IState<T>> {
567
573
 
568
574
  handleDebounce() {
569
575
  this.setState({options: []});
576
+
570
577
  if (this.props.kind === 'asynchronous') {
571
578
  if (this.state.searchFieldValue) {
572
579
  this.setState({
573
580
  loading: true,
574
581
  });
582
+
575
583
  this.ICancelFn = this.props.searchOptions(this.state.searchFieldValue, (items) => {
576
584
  this.setState({options: items, loading: false});
577
585
  this.popperInstance?.update();
@@ -613,13 +621,19 @@ export class TreeSelect<T> extends React.Component<IProps<T>, IState<T>> {
613
621
  htmlId={this.htmlId}
614
622
  tabindex={this.props.tabindex}
615
623
  >
616
- <div className={`tags-input sd-input__input tags-input--${this.props.allowMultiple ? 'multi-select' : 'single-select'}`}>
624
+ <div
625
+ className={`tags-input sd-input__input tags-input--${this.props.allowMultiple ? 'multi-select' : 'single-select'}`}
626
+ ref={this.treeSelectRef}
627
+ >
617
628
  {this.props.allowMultiple
618
629
  ? <div className="tags-input__tags">
619
630
  {this.props.readOnly
620
- || <button ref={this.openDropdownRef}
631
+ || <button
632
+ ref={this.openDropdownRef}
621
633
  className={`tags-input__add-button ${this.props.disabled ? 'tags-input__add-button--disabled' : ''}`}
622
- onClick={() => {
634
+ onClick={(e) => {
635
+ e.stopPropagation();
636
+
623
637
  if (!this.props.disabled) {
624
638
  this.setState({openDropdown: !this.state.openDropdown});
625
639
  }
@@ -628,59 +642,48 @@ export class TreeSelect<T> extends React.Component<IProps<T>, IState<T>> {
628
642
  <i className="icon-plus-large"></i>
629
643
  </button>
630
644
  }
645
+
631
646
  <ul className="tags-input__tag-list">
632
647
  {this.state.value.map((item, i: number) => {
633
648
  const Wrapper: React.ComponentType<{backgroundColor?: string}>
634
649
  = ({backgroundColor, children}) => (
635
- <li
636
- className={"tags-input__tag-item tags-input__tag-item--multi-select"
637
- + (this.props.readOnly ? ' tags-input__tag-item--readonly' : '')}
638
- onClick={() => (!this.props.readOnly && !this.props.disabled)
639
- && this.removeClick(i)
640
- }
641
- style={this.props.valueTemplate
642
- ? {backgroundColor}
643
- : this.props.getBackgroundColor
644
- && {backgroundColor: this.props.getBackgroundColor(item)}}
650
+ <TreeSelectPill
651
+ item={item}
652
+ readOnly={this.props.readOnly}
653
+ disabled={this.props.disabled}
654
+ valueTemplate={this.props.valueTemplate}
655
+ backgroundColor={backgroundColor}
656
+ onRemove={() => this.removeClick(i)}
657
+ getBackgroundColor={this.props.getBackgroundColor}
645
658
  >
646
- <span
647
- className="tags-input__helper-box"
648
- style={
649
- {color: backgroundColor
650
- ? getTextColor(backgroundColor)
651
- : this.props.getBackgroundColor
652
- && getTextColor(this.props.getBackgroundColor(item)),
653
- }
654
- }
655
- >
656
- {children}
657
- {!this.props.readOnly
658
- && <span className="tags-input__remove-button">
659
- <Icon name="close-small"></Icon>
660
- </span>
661
- }
662
- </span>
663
- </li>
659
+ {children}
660
+ </TreeSelectPill>
664
661
  );
665
662
 
666
663
  return (
667
664
  <React.Fragment key={i}>
668
665
  {this.props.valueTemplate
669
666
  ? this.props.valueTemplate(item, Wrapper)
670
- : <Wrapper>
671
- <span>{this.props.getLabel(item)}</span>
672
- </Wrapper>
667
+ : (
668
+ <Wrapper>
669
+ <span>{this.props.getLabel(item)}</span>
670
+ </Wrapper>
671
+ )
673
672
  }
674
673
  </React.Fragment>
675
674
  );
676
675
  })}
677
676
  </ul>
677
+
678
678
  {this.state.value.length > 0
679
679
  ? (this.props.readOnly || this.props.disabled)
680
680
  || <button
681
681
  className="tags-input__remove-value"
682
682
  style={{position: 'relative', bottom: '2px'}}
683
- onClick={() => this.setState({value: []})}
683
+ onClick={(e) => {
684
+ e.stopPropagation();
685
+ this.setState({value: []});
686
+ }}
684
687
  >
685
688
  <Icon name='remove-sign'></Icon>
686
689
  </button>
@@ -692,10 +695,12 @@ export class TreeSelect<T> extends React.Component<IProps<T>, IState<T>> {
692
695
  || <button
693
696
  className="tags-input__overlay-button"
694
697
  ref={this.openDropdownRef}
695
- onClick={() => this.setState({openDropdown: !this.state.openDropdown})}
696
- >
697
- </button>
698
+ onClick={() => {
699
+ this.setState({openDropdown: !this.state.openDropdown});
700
+ }}
701
+ />
698
702
  }
703
+
699
704
  {this.state.value.length < 1
700
705
  && <span
701
706
  className={ 'tags-input__single-item'
@@ -707,15 +712,16 @@ export class TreeSelect<T> extends React.Component<IProps<T>, IState<T>> {
707
712
  </span>
708
713
  </span>
709
714
  }
715
+
710
716
  {this.state.value.map((item, i: number) => {
711
717
  const Wrapper: React.ComponentType<{backgroundColor?: string, borderColor?: string}>
712
718
  = ({backgroundColor, borderColor, children}) => (
713
719
  <span
714
- className={ 'tags-input__single-item'
720
+ className={
721
+ 'tags-input__single-item'
715
722
  + (this.props.readOnly ? ' tags-input__tag-item--readonly' : '')
716
723
  }
717
- onClick={() => !this.props.readOnly && this.removeClick(i)
718
- }
724
+ onClick={() => !this.props.readOnly && this.removeClick(i)}
719
725
  >
720
726
  {this.props.getBorderColor
721
727
  && <div
@@ -727,9 +733,10 @@ export class TreeSelect<T> extends React.Component<IProps<T>, IState<T>> {
727
733
  >
728
734
  </div>
729
735
  }
736
+
730
737
  <span
731
- style={{color: backgroundColor && getTextColor(backgroundColor)}}
732
738
  className="tags-input__helper-box"
739
+ style={{color: backgroundColor && getTextColor(backgroundColor)}}
733
740
  >
734
741
  <span
735
742
  className={backgroundColor && `tags-input__tag-item`}
@@ -737,6 +744,7 @@ export class TreeSelect<T> extends React.Component<IProps<T>, IState<T>> {
737
744
  >
738
745
  {children}
739
746
  </span>
747
+
740
748
  {this.props.readOnly
741
749
  || <span className="tags-input__remove-button">
742
750
  <Icon name='remove-sign'></Icon>
@@ -749,9 +757,11 @@ export class TreeSelect<T> extends React.Component<IProps<T>, IState<T>> {
749
757
  return <React.Fragment key={i}>
750
758
  {this.props.valueTemplate
751
759
  ? this.props.valueTemplate(item, Wrapper)
752
- : <Wrapper>
753
- <span>{this.props.getLabel(item)}</span>
754
- </Wrapper>
760
+ : (
761
+ <Wrapper>
762
+ <span>{this.props.getLabel(item)}</span>
763
+ </Wrapper>
764
+ )
755
765
  }
756
766
  </React.Fragment>;
757
767
  })}
@@ -760,7 +770,8 @@ export class TreeSelect<T> extends React.Component<IProps<T>, IState<T>> {
760
770
 
761
771
  {this.state.openDropdown
762
772
  && <div
763
- className={"autocomplete autocomplete--multi-select"
773
+ className={
774
+ "autocomplete autocomplete--multi-select"
764
775
  + (this.props.width === 'medium' ? ' autocomplete--fixed-width' : '')
765
776
  }
766
777
  style={{zIndex: this.props.zIndex}}
@@ -770,12 +781,12 @@ export class TreeSelect<T> extends React.Component<IProps<T>, IState<T>> {
770
781
  <div
771
782
  className="autocomplete__icon"
772
783
  onClick={() => {
773
- this.backButtonValue();
774
784
  this.backButton();
775
785
  }}
776
786
  >
777
787
  <Icon name="search" className="search"></Icon>
778
788
  </div>
789
+
779
790
  <div className='autocomplete__filter'>
780
791
  <input
781
792
  className="autocomplete__input"
@@ -791,6 +802,7 @@ export class TreeSelect<T> extends React.Component<IProps<T>, IState<T>> {
791
802
  if (this.ICancelFn) {
792
803
  this.ICancelFn();
793
804
  }
805
+
794
806
  this.setState({searchFieldValue: event.target.value, options: []});
795
807
  this.popperInstance?.update();
796
808
  this.debounceFn();
@@ -801,19 +813,20 @@ export class TreeSelect<T> extends React.Component<IProps<T>, IState<T>> {
801
813
  />
802
814
  </div>
803
815
  </div>
816
+
804
817
  {(this.state.activeTree.length > 0 && this.state.buttonValue != null)
805
818
  && <div className='autocomplete__category-header'>
806
819
  <div
807
820
  className="autocomplete__icon"
808
821
  onClick={() => {
809
- this.backButtonValue();
810
822
  this.backButton();
811
823
  }}
812
824
  >
813
825
  <Icon name="arrow-left" className="arrow-left"></Icon>
814
826
  </div>
827
+
815
828
  <div className='autocomplete__filter'>
816
- <button className={'autocomplete__category-title'}>
829
+ <button className='autocomplete__category-title'>
817
830
  {this.props.optionTemplate
818
831
  ? this.props.optionTemplate(this.state.buttonValue.value)
819
832
  : this.props.getLabel(this.state.buttonValue.value)
@@ -826,95 +839,53 @@ export class TreeSelect<T> extends React.Component<IProps<T>, IState<T>> {
826
839
  </div>
827
840
  </div>
828
841
  }
842
+
829
843
  {this.state.loading
830
- ? <ul className="suggestion-list--loader"><Loader overlay={true}></Loader></ul>
831
- : this.state.searchFieldValue === ''
832
- ? this.props.getOptions
833
- ? <ul
844
+ ? <ul className="suggestion-list--loader"><Loader overlay={true}></Loader></ul>
845
+ : this.state.searchFieldValue === ''
846
+ ? this.props.getOptions
847
+ ? <ul
848
+ className="suggestion-list suggestion-list--multi-select"
849
+ ref={this.ref}
850
+ >
851
+ {this.state.options.map((option, i: React.Key | undefined) => {
852
+ let selectedItem = this.state.value.some((obj) =>
853
+ this.props.getId(obj) === this.props.getId(option.value),
854
+ );
855
+
856
+ return (
857
+ <TreeSelectItem
858
+ key={i}
859
+ option={option}
860
+ handleTree={this.handleTree}
861
+ selectedItem={selectedItem}
862
+ allowMultiple={this.props.allowMultiple}
863
+ getBorderColor={this.props.getBorderColor}
864
+ getBackgroundColor={this.props.getBackgroundColor}
865
+ getId={this.props.getId}
866
+ optionTemplate={this.props.optionTemplate}
867
+ getLabel={this.props.getLabel}
868
+ onKeyDown={() => this.setState({
869
+ buttonTarget: [
870
+ ...this.state.buttonTarget,
871
+ this.props.getId(option.value),
872
+ ],
873
+ })}
874
+ />
875
+ );
876
+ })}
877
+ </ul>
878
+ : null
879
+ : <ul
834
880
  className="suggestion-list suggestion-list--multi-select"
835
881
  ref={this.ref}
836
882
  >
837
- {this.state.options.map((option, i: React.Key | undefined) => {
838
- let selectedItem = this.state.value.some((obj) =>
839
- this.props.getId(obj) === this.props.getId(option.value),
840
- );
841
- return (
842
- <li
843
- key={i}
844
- className={`suggestion-item suggestion-item--multi-select`}
845
- onClick={(event) => {
846
- event.preventDefault();
847
- event.stopPropagation();
848
- this.handleTree(event, option);
849
- }}
850
- >
851
- <button
852
- className={`suggestion-item--btn ${this.props.getId(option.value)}-focus`}
853
- onKeyDown={(event) => {
854
- if (event.key === 'Enter' && option.children) {
855
- this.setState({
856
- buttonTarget: [
857
- ...this.state.buttonTarget,
858
- this.props.getId(option.value),
859
- ],
860
- });
861
- }
862
- }}
863
- >
864
- {(this.props.getBorderColor && !this.props.allowMultiple)
865
- && <div
866
- className="item-border"
867
- style={{
868
- backgroundColor: this.props.getBorderColor(
869
- option.value,
870
- ),
871
- }}
872
- >
873
- </div>
874
- }
875
- <span
876
- className={
877
- 'suggestion-item--bgcolor'
878
- + (selectedItem ? ' suggestion-item--disabled' : '')
879
- }
880
- style={
881
- (this.props.getBackgroundColor && option.value)
882
- ? {
883
- backgroundColor:
884
- this.props.getBackgroundColor(option.value),
885
- color:
886
- getTextColor(this.props.getBackgroundColor(
887
- option.value,
888
- ),
889
- ),
890
- }
891
- : undefined
892
- }
893
- >
894
- {this.props.optionTemplate
895
- ? this.props.optionTemplate(option.value)
896
- : this.props.getLabel(option.value)
897
- }
898
- </span>
899
- {option.children
900
- && <span className="suggestion-item__icon">
901
- <Icon name="chevron-right-thin"></Icon>
902
- </span>
903
- }
904
- </button>
905
- </li>
906
- );
907
- })}
883
+ {this.filteredItem(
884
+ this.props.singleLevelSearch
885
+ ? this.state.options
886
+ : this.state.filterArr,
887
+ )}
908
888
  </ul>
909
- : null
910
- : <ul
911
- className="suggestion-list suggestion-list--multi-select"
912
- ref={this.ref}
913
- >
914
- {this.filteredItem(this.props.singleLevelSearch
915
- ? this.state.options : this.state.filterArr)
916
- }
917
- </ul>
918
889
  }
919
890
  </div>
920
891
  }