superdesk-ui-framework 3.0.53 → 3.0.55

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 (29) hide show
  1. package/app/styles/_sd-tag-input.scss +213 -215
  2. package/app/styles/primereact/_pr-general.scss +2 -2
  3. package/app-typescript/components/DatePicker.tsx +8 -0
  4. package/app-typescript/components/Input.tsx +2 -0
  5. package/app-typescript/components/RadioButtonGroup.tsx +8 -2
  6. package/app-typescript/components/SelectWithTemplate.tsx +12 -2
  7. package/app-typescript/components/TabCustom.tsx +9 -2
  8. package/app-typescript/components/TimePicker.tsx +2 -0
  9. package/app-typescript/components/TreeSelect/TreeSelect.tsx +120 -107
  10. package/app-typescript/components/avatar/avatar-image.tsx +17 -5
  11. package/dist/examples.bundle.js +114 -84
  12. package/dist/superdesk-ui.bundle.css +186 -202
  13. package/dist/superdesk-ui.bundle.js +113 -83
  14. package/package.json +1 -1
  15. package/react/components/DatePicker.d.ts +1 -0
  16. package/react/components/DatePicker.js +4 -0
  17. package/react/components/Input.d.ts +1 -0
  18. package/react/components/Input.js +1 -1
  19. package/react/components/RadioButtonGroup.d.ts +1 -0
  20. package/react/components/RadioButtonGroup.js +2 -2
  21. package/react/components/SelectWithTemplate.d.ts +3 -0
  22. package/react/components/SelectWithTemplate.js +7 -1
  23. package/react/components/TabCustom.d.ts +2 -1
  24. package/react/components/TabCustom.js +9 -9
  25. package/react/components/TimePicker.d.ts +1 -0
  26. package/react/components/TimePicker.js +1 -1
  27. package/react/components/TreeSelect/TreeSelect.d.ts +1 -0
  28. package/react/components/TreeSelect/TreeSelect.js +70 -64
  29. package/react/components/avatar/avatar-image.js +19 -5
@@ -11,6 +11,7 @@ import {IInputWrapper} from '../Form/InputWrapper';
11
11
  import {SelectPreview} from '../SelectPreview';
12
12
  import {TreeSelectPill} from './TreeSelectPill';
13
13
  import {getPrefixedItemId, TreeSelectItem} from './TreeSelectItem';
14
+ import {createPortal} from 'react-dom';
14
15
 
15
16
  interface IState<T> {
16
17
  value: Array<T>;
@@ -47,6 +48,7 @@ interface IPropsBase<T> extends IInputWrapper {
47
48
  optionTemplate?(item: T): React.ComponentType<T> | JSX.Element;
48
49
  valueTemplate?(item: T, Wrapper: React.ElementType): React.ComponentType<T> | JSX.Element;
49
50
  onChange(e: Array<T>): void;
51
+ 'data-test-id'?: string;
50
52
  }
51
53
 
52
54
  interface IPropsSync<T> extends IPropsBase<T> {
@@ -131,7 +133,8 @@ export class TreeSelect<T> extends React.Component<IProps<T>, IState<T>> {
131
133
 
132
134
  onMouseDown = (event: MouseEvent) => {
133
135
  if (
134
- (this.treeSelectRef .current?.contains(event.target as HTMLElement) !== true)
136
+ (this.dropdownRef.current?.contains(event.target as HTMLElement) !== true)
137
+ && (this.treeSelectRef.current?.contains(event.target as HTMLElement) !== true)
135
138
  && this.state.openDropdown
136
139
  ) {
137
140
  this.setState({openDropdown: false});
@@ -701,6 +704,7 @@ export class TreeSelect<T> extends React.Component<IProps<T>, IState<T>> {
701
704
  onClick={() => {
702
705
  this.setState({openDropdown: !this.state.openDropdown});
703
706
  }}
707
+ data-test-id={this.state.openDropdown ? undefined : this.props['data-test-id']}
704
708
  />
705
709
  }
706
710
 
@@ -770,129 +774,138 @@ export class TreeSelect<T> extends React.Component<IProps<T>, IState<T>> {
770
774
  })}
771
775
  </div>
772
776
  }
777
+ </div>
773
778
 
774
- {this.state.openDropdown
775
- && <div
776
- className={
777
- "autocomplete autocomplete--multi-select"
778
- + (this.props.width === 'medium' ? ' autocomplete--fixed-width' : '')
779
- }
780
- style={{zIndex: this.props.zIndex}}
781
- ref={this.dropdownRef}
782
- >
783
- <div className='autocomplete__header'>
784
- <div
785
- className="autocomplete__icon"
786
- onClick={() => {
787
- this.backButton();
788
- }}
789
- >
790
- <Icon name="search" className="search"></Icon>
791
- </div>
792
-
793
- <div className='autocomplete__filter'>
794
- <input
795
- className="autocomplete__input"
796
- type="text"
797
- placeholder={this.props.searchPlaceholder}
798
- ref={this.inputRef}
799
- value={this.state.searchFieldValue}
800
- onChange={(event) => {
801
- if (this.props.kind === 'synchronous') {
802
- this.setState({searchFieldValue: event.target.value});
803
- this.popperInstance?.update();
804
- } else if (this.props.kind === 'asynchronous') {
805
- if (this.ICancelFn) {
806
- this.ICancelFn();
807
- }
808
-
809
- this.setState({searchFieldValue: event.target.value, options: []});
810
- this.popperInstance?.update();
811
- this.debounceFn();
812
- } else {
813
- return;
814
- }
815
- }}
816
- />
817
- </div>
818
- </div>
819
-
820
- {(this.state.activeTree.length > 0 && this.state.buttonValue != null)
821
- && <div className='autocomplete__category-header'>
779
+ {createPortal(
780
+ this.state.openDropdown
781
+ && <div id='TREESELECT_DROPDOWN' data-test-id={this.props['data-test-id']}>
782
+ <div
783
+ className={
784
+ "autocomplete autocomplete--multi-select"
785
+ + (this.props.width === 'medium' ? ' autocomplete--fixed-width' : '')
786
+ }
787
+ style={{
788
+ zIndex: this.props.zIndex,
789
+ width: this.treeSelectRef.current?.offsetWidth,
790
+ }}
791
+ ref={this.dropdownRef}
792
+ >
793
+ <div className='autocomplete__header'>
822
794
  <div
823
795
  className="autocomplete__icon"
824
796
  onClick={() => {
825
797
  this.backButton();
826
798
  }}
827
799
  >
828
- <Icon name="arrow-left" className="arrow-left"></Icon>
800
+ <Icon name="search" className="search"></Icon>
829
801
  </div>
830
802
 
831
803
  <div className='autocomplete__filter'>
832
- <button className='autocomplete__category-title'>
833
- {this.props.optionTemplate
834
- ? this.props.optionTemplate(this.state.buttonValue.value)
835
- : this.props.getLabel(this.state.buttonValue.value)
836
- }
837
- </button>
838
-
839
- {this.props.selectBranchWithChildren
840
- && this.branchButton(this.state.buttonValue)
841
- }
804
+ <input
805
+ className="autocomplete__input"
806
+ type="text"
807
+ placeholder={this.props.searchPlaceholder}
808
+ ref={this.inputRef}
809
+ value={this.state.searchFieldValue}
810
+ onChange={(event) => {
811
+ if (this.props.kind === 'synchronous') {
812
+ this.setState({searchFieldValue: event.target.value});
813
+ this.popperInstance?.update();
814
+ } else if (this.props.kind === 'asynchronous') {
815
+ if (this.ICancelFn) {
816
+ this.ICancelFn();
817
+ }
818
+
819
+ this.setState({searchFieldValue: event.target.value, options: []});
820
+ this.popperInstance?.update();
821
+ this.debounceFn();
822
+ } else {
823
+ return;
824
+ }
825
+ }}
826
+ data-test-id="filter-input"
827
+ />
842
828
  </div>
843
829
  </div>
844
- }
845
830
 
846
- {this.state.loading
847
- ? <ul className="suggestion-list--loader"><Loader overlay={true}></Loader></ul>
848
- : this.state.searchFieldValue === ''
849
- ? this.props.getOptions
850
- ? <ul
831
+ {(this.state.activeTree.length > 0 && this.state.buttonValue != null)
832
+ && <div className='autocomplete__category-header'>
833
+ <div
834
+ className="autocomplete__icon"
835
+ onClick={() => {
836
+ this.backButton();
837
+ }}
838
+ >
839
+ <Icon name="arrow-left" className="arrow-left"></Icon>
840
+ </div>
841
+
842
+ <div className='autocomplete__filter'>
843
+ <button className='autocomplete__category-title'>
844
+ {this.props.optionTemplate
845
+ ? this.props.optionTemplate(this.state.buttonValue.value)
846
+ : this.props.getLabel(this.state.buttonValue.value)
847
+ }
848
+ </button>
849
+
850
+ {this.props.selectBranchWithChildren
851
+ && this.branchButton(this.state.buttonValue)
852
+ }
853
+ </div>
854
+ </div>
855
+ }
856
+
857
+ {this.state.loading
858
+ ? <ul className="suggestion-list--loader"><Loader overlay={true}></Loader></ul>
859
+ : this.state.searchFieldValue === ''
860
+ ? this.props.getOptions
861
+ ? <ul
862
+ className="suggestion-list suggestion-list--multi-select"
863
+ ref={this.ref}
864
+ data-test-id="options"
865
+ >
866
+ {this.state.options.map((option, i: React.Key | undefined) => {
867
+ let selectedItem = this.state.value.some((obj) =>
868
+ this.props.getId(obj) === this.props.getId(option.value),
869
+ );
870
+
871
+ return (
872
+ <TreeSelectItem
873
+ key={i}
874
+ option={option}
875
+ handleTree={this.handleTree}
876
+ selectedItem={selectedItem}
877
+ allowMultiple={this.props.allowMultiple}
878
+ getBorderColor={this.props.getBorderColor}
879
+ getBackgroundColor={this.props.getBackgroundColor}
880
+ getId={this.props.getId}
881
+ optionTemplate={this.props.optionTemplate}
882
+ getLabel={this.props.getLabel}
883
+ onKeyDown={() => this.setState({
884
+ buttonTarget: [
885
+ ...this.state.buttonTarget,
886
+ this.props.getId(option.value),
887
+ ],
888
+ })}
889
+ />
890
+ );
891
+ })}
892
+ </ul>
893
+ : null
894
+ : <ul
851
895
  className="suggestion-list suggestion-list--multi-select"
852
896
  ref={this.ref}
853
897
  >
854
- {this.state.options.map((option, i: React.Key | undefined) => {
855
- let selectedItem = this.state.value.some((obj) =>
856
- this.props.getId(obj) === this.props.getId(option.value),
857
- );
858
-
859
- return (
860
- <TreeSelectItem
861
- key={i}
862
- option={option}
863
- handleTree={this.handleTree}
864
- selectedItem={selectedItem}
865
- allowMultiple={this.props.allowMultiple}
866
- getBorderColor={this.props.getBorderColor}
867
- getBackgroundColor={this.props.getBackgroundColor}
868
- getId={this.props.getId}
869
- optionTemplate={this.props.optionTemplate}
870
- getLabel={this.props.getLabel}
871
- onKeyDown={() => this.setState({
872
- buttonTarget: [
873
- ...this.state.buttonTarget,
874
- this.props.getId(option.value),
875
- ],
876
- })}
877
- />
878
- );
879
- })}
898
+ {this.filteredItem(
899
+ this.props.singleLevelSearch
900
+ ? this.state.options
901
+ : this.state.filterArr,
902
+ )}
880
903
  </ul>
881
- : null
882
- : <ul
883
- className="suggestion-list suggestion-list--multi-select"
884
- ref={this.ref}
885
- >
886
- {this.filteredItem(
887
- this.props.singleLevelSearch
888
- ? this.state.options
889
- : this.state.filterArr,
890
- )}
891
- </ul>
892
- }
893
- </div>
894
- }
895
- </div>
904
+ }
905
+ </div>
906
+ </div>,
907
+ document.body,
908
+ )}
896
909
  </InputWrapper>
897
910
  );
898
911
  }
@@ -9,19 +9,31 @@ interface IPropsImageAvatar extends IPropsBase {
9
9
  export class AvatarContentImage extends React.PureComponent<IPropsImageAvatar> {
10
10
  render() {
11
11
  const {imageUrl, tooltipText, onClick} = this.props;
12
- const role: string | undefined = onClick == null ? undefined : 'button';
12
+
13
+ const maybeButtonProps: React.HTMLAttributes<HTMLSpanElement> = onClick == null ? {} : {
14
+ role: 'button',
15
+ onClick: () => onClick(),
16
+ };
13
17
 
14
18
  if (imageUrl == null) {
15
19
  return (
16
- <span className="sd-avatar-content sd-avatar-content--dummy-img" title={tooltipText} role={role}>
20
+ <span
21
+ {...maybeButtonProps}
22
+ className="sd-avatar-content sd-avatar-content--dummy-img"
23
+ title={tooltipText}
24
+ >
17
25
  <svg width="200" height="200" viewBox="0 0 200 200" fill="none" xmlns="http://www.w3.org/2000/svg">
18
- <circle cx="100" cy="100" r="100" fill="white" fill-opacity="0.01"/>
19
- <path fill-rule="evenodd" clip-rule="evenodd" d="M40 153V145.384C40 141.557 41.16 137.981 43.16 135C49.14 126.057 66.24 119.711 77.14 118C82.74 117.115 90.16 116.538 100 116.538C109.84 116.538 117.26 117.115 122.86 118C133.76 119.711 150.86 126.057 156.84 135C158.84 137.981 160 141.557 160 145.384V153C150 165 130 180 100 180C70 180 50 165 40 153ZM100 30C122.08 30 140 47.2307 140 68.4614C140 89.6922 122.08 106.923 100 106.923C77.92 106.923 60 89.6922 60 68.4614C60 47.2307 77.92 30 100 30Z" fill="var(--sd-colour-avatar-dummy)" fill-opacity="1"/>
26
+ <circle cx="100" cy="100" r="100" fill="white" fillOpacity="0.01"/>
27
+ <path fillRule="evenodd" clipRule="evenodd" d="M40 153V145.384C40 141.557 41.16 137.981 43.16 135C49.14 126.057 66.24 119.711 77.14 118C82.74 117.115 90.16 116.538 100 116.538C109.84 116.538 117.26 117.115 122.86 118C133.76 119.711 150.86 126.057 156.84 135C158.84 137.981 160 141.557 160 145.384V153C150 165 130 180 100 180C70 180 50 165 40 153ZM100 30C122.08 30 140 47.2307 140 68.4614C140 89.6922 122.08 106.923 100 106.923C77.92 106.923 60 89.6922 60 68.4614C60 47.2307 77.92 30 100 30Z" fill="var(--sd-colour-avatar-dummy)" fillOpacity="1"/>
20
28
  </svg>
21
29
  </span>);
22
30
  } else {
23
31
  return (
24
- <span className="sd-avatar-content" title={tooltipText} role={role}>
32
+ <span
33
+ {...maybeButtonProps}
34
+ className="sd-avatar-content"
35
+ title={tooltipText}
36
+ >
25
37
  <img src={imageUrl} />
26
38
  </span>
27
39
  );