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.
- package/app/styles/_sd-tag-input.scss +213 -215
- package/app/styles/primereact/_pr-general.scss +2 -2
- package/app-typescript/components/DatePicker.tsx +8 -0
- package/app-typescript/components/Input.tsx +2 -0
- package/app-typescript/components/RadioButtonGroup.tsx +8 -2
- package/app-typescript/components/SelectWithTemplate.tsx +12 -2
- package/app-typescript/components/TabCustom.tsx +9 -2
- package/app-typescript/components/TimePicker.tsx +2 -0
- package/app-typescript/components/TreeSelect/TreeSelect.tsx +120 -107
- package/app-typescript/components/avatar/avatar-image.tsx +17 -5
- package/dist/examples.bundle.js +114 -84
- package/dist/superdesk-ui.bundle.css +186 -202
- package/dist/superdesk-ui.bundle.js +113 -83
- package/package.json +1 -1
- package/react/components/DatePicker.d.ts +1 -0
- package/react/components/DatePicker.js +4 -0
- package/react/components/Input.d.ts +1 -0
- package/react/components/Input.js +1 -1
- package/react/components/RadioButtonGroup.d.ts +1 -0
- package/react/components/RadioButtonGroup.js +2 -2
- package/react/components/SelectWithTemplate.d.ts +3 -0
- package/react/components/SelectWithTemplate.js +7 -1
- package/react/components/TabCustom.d.ts +2 -1
- package/react/components/TabCustom.js +9 -9
- package/react/components/TimePicker.d.ts +1 -0
- package/react/components/TimePicker.js +1 -1
- package/react/components/TreeSelect/TreeSelect.d.ts +1 -0
- package/react/components/TreeSelect/TreeSelect.js +70 -64
- 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.
|
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
|
-
|
775
|
-
|
776
|
-
|
777
|
-
|
778
|
-
|
779
|
-
|
780
|
-
|
781
|
-
|
782
|
-
|
783
|
-
|
784
|
-
|
785
|
-
|
786
|
-
|
787
|
-
|
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="
|
800
|
+
<Icon name="search" className="search"></Icon>
|
829
801
|
</div>
|
830
802
|
|
831
803
|
<div className='autocomplete__filter'>
|
832
|
-
<
|
833
|
-
|
834
|
-
|
835
|
-
|
836
|
-
}
|
837
|
-
|
838
|
-
|
839
|
-
|
840
|
-
|
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
|
-
|
847
|
-
|
848
|
-
|
849
|
-
|
850
|
-
|
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.
|
855
|
-
|
856
|
-
|
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
|
-
|
882
|
-
|
883
|
-
|
884
|
-
|
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
|
-
|
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
|
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"
|
19
|
-
<path
|
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
|
32
|
+
<span
|
33
|
+
{...maybeButtonProps}
|
34
|
+
className="sd-avatar-content"
|
35
|
+
title={tooltipText}
|
36
|
+
>
|
25
37
|
<img src={imageUrl} />
|
26
38
|
</span>
|
27
39
|
);
|