superdesk-ui-framework 4.0.13 → 4.0.16
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/.github/workflows/publish-to-npm.yml +1 -0
- package/app/styles/app.scss +1 -0
- package/app-typescript/components/CreateButton.tsx +1 -1
- package/app-typescript/components/DateTimePicker.tsx +33 -29
- package/app-typescript/components/Editor/EditorButton.tsx +1 -1
- package/app-typescript/components/IconButton.tsx +1 -3
- package/app-typescript/components/Lists/TableList.tsx +4 -4
- package/app-typescript/components/Switch.tsx +0 -1
- package/app-typescript/components/Tooltip.tsx +76 -48
- package/app-typescript/components/TreeSelect/TreeSelect.tsx +14 -1
- package/dist/components/Tooltips.tsx +1 -44
- package/dist/components/TreeSelect.tsx +10 -15
- package/dist/examples.bundle.js +3588 -1104
- package/dist/playgrounds/react-playgrounds/RundownEditor.tsx +1 -1
- package/dist/playgrounds/react-playgrounds/TestGround.tsx +26 -26
- package/dist/superdesk-ui.bundle.css +1 -1
- package/dist/superdesk-ui.bundle.js +3545 -1041
- package/examples/pages/components/Tooltips.tsx +1 -44
- package/examples/pages/components/TreeSelect.tsx +10 -15
- package/examples/pages/playgrounds/react-playgrounds/RundownEditor.tsx +1 -1
- package/examples/pages/playgrounds/react-playgrounds/TestGround.tsx +26 -26
- package/package.json +3 -2
- package/react/components/CreateButton.js +1 -1
- package/react/components/DateTimePicker.js +9 -7
- package/react/components/IconButton.js +1 -1
- package/react/components/Lists/TableList.js +4 -4
- package/react/components/Switch.js +1 -1
- package/react/components/Tooltip.d.ts +10 -4
- package/react/components/Tooltip.js +64 -64
- package/react/components/TreeSelect/TreeSelect.d.ts +1 -0
- package/react/components/TreeSelect/TreeSelect.js +8 -1
package/app/styles/app.scss
CHANGED
@@ -108,6 +108,7 @@
|
|
108
108
|
// Prime React
|
109
109
|
@import '../../node_modules/@superdesk/primereact/resources/primereact.min.css';
|
110
110
|
@import '../../node_modules/primeicons/primeicons.css';
|
111
|
+
@import '~tippy.js/dist/tippy.css';
|
111
112
|
@import 'pr-superdesk-theme';
|
112
113
|
@import 'primereact/pr-dialog';
|
113
114
|
@import 'primereact/pr-menu';
|
@@ -22,7 +22,7 @@ export class CreateButton extends React.PureComponent<IProps> {
|
|
22
22
|
});
|
23
23
|
const value = this.props.value === undefined ? 'button' : this.props.value;
|
24
24
|
return (
|
25
|
-
<Tooltip text={this.props.ariaValue} flow={this.props.toolTipFlow}
|
25
|
+
<Tooltip text={this.props.ariaValue} flow={this.props.toolTipFlow}>
|
26
26
|
<button type={value}
|
27
27
|
className={classes}
|
28
28
|
tabIndex={0}
|
@@ -59,35 +59,39 @@ export class DateTimePicker extends React.PureComponent<IProps> {
|
|
59
59
|
|
60
60
|
return (
|
61
61
|
<div style={{width: this.props.width ? this.props.width : MIN_WIDTH}}>
|
62
|
-
<Spacer h gap="8" alignItems='end'>
|
63
|
-
<
|
64
|
-
|
65
|
-
|
66
|
-
|
67
|
-
|
68
|
-
|
69
|
-
|
70
|
-
|
71
|
-
|
72
|
-
|
73
|
-
|
74
|
-
|
75
|
-
|
76
|
-
|
77
|
-
|
78
|
-
|
79
|
-
|
80
|
-
|
81
|
-
|
82
|
-
|
83
|
-
this.
|
84
|
-
|
85
|
-
|
86
|
-
|
87
|
-
|
88
|
-
|
89
|
-
|
90
|
-
|
62
|
+
<Spacer h gap="8" alignItems='end' noWrap>
|
63
|
+
<div style={{flexGrow: 1}}>
|
64
|
+
<DatePicker
|
65
|
+
disabled={this.props.disabled}
|
66
|
+
preview={this.props.preview}
|
67
|
+
required={this.props.required}
|
68
|
+
hideClearButton={true}
|
69
|
+
value={this.props.value}
|
70
|
+
onChange={(val) => {
|
71
|
+
this.handleDateChange(val);
|
72
|
+
}}
|
73
|
+
dateFormat={this.props.dateFormat}
|
74
|
+
label={this.props.label.text}
|
75
|
+
inlineLabel={this.props.label.hidden ?? false}
|
76
|
+
labelHidden={this.props.label.hidden ?? false}
|
77
|
+
fullWidth={this.props.fullWidth}
|
78
|
+
/>
|
79
|
+
</div>
|
80
|
+
<div style={{flexGrow: 1}}>
|
81
|
+
<TimePicker
|
82
|
+
disabled={this.props.disabled}
|
83
|
+
preview={this.props.preview}
|
84
|
+
value={convertedTimeValue}
|
85
|
+
onChange={(val) => {
|
86
|
+
this.handleTimeChange(val);
|
87
|
+
}}
|
88
|
+
inlineLabel
|
89
|
+
labelHidden
|
90
|
+
allowSeconds={this.props.allowSeconds}
|
91
|
+
fullWidth={this.props.fullWidth}
|
92
|
+
required={this.props.required}
|
93
|
+
/>
|
94
|
+
</div>
|
91
95
|
{this.props.preview !== true && (
|
92
96
|
<IconButton
|
93
97
|
disabled={this.props.disabled}
|
@@ -19,7 +19,7 @@ export class EditorButton extends React.PureComponent<IProps> {
|
|
19
19
|
'icn-btn--small': this.props.size === 'small',
|
20
20
|
});
|
21
21
|
return (
|
22
|
-
<Tooltip text={this.props.ariaValue} flow={this.props.toolTipFlow}
|
22
|
+
<Tooltip text={this.props.ariaValue} flow={this.props.toolTipFlow}>
|
23
23
|
<button
|
24
24
|
id={this.props.id}
|
25
25
|
tabIndex={0}
|
@@ -28,10 +28,8 @@ export class IconButton extends React.PureComponent<IProps> {
|
|
28
28
|
|
29
29
|
return (
|
30
30
|
<Tooltip
|
31
|
-
text={this.props.ariaValue}
|
31
|
+
text={this.props.disabled ? null : this.props.ariaValue}
|
32
32
|
flow={this.props.toolTipFlow}
|
33
|
-
appendToBody={this.props.toolTipAppend}
|
34
|
-
disabled={this.props.disabled}
|
35
33
|
>
|
36
34
|
<button
|
37
35
|
id={this.props.id}
|
@@ -187,7 +187,7 @@ class TableList extends React.PureComponent<IProps, IState> {
|
|
187
187
|
{
|
188
188
|
(this.props.addItem && !this.props.readOnly)
|
189
189
|
&& <div className={`table-list__add-item table-list__item--margin`}>
|
190
|
-
<Tooltip text='Add item' flow='top'
|
190
|
+
<Tooltip text='Add item' flow='top'>
|
191
191
|
<div className='table-list__add-item--container sd-margin-x--auto'>
|
192
192
|
{this.dropDown()}
|
193
193
|
</div>
|
@@ -233,7 +233,7 @@ class TableList extends React.PureComponent<IProps, IState> {
|
|
233
233
|
{
|
234
234
|
(this.props.addItem && !this.props.readOnly)
|
235
235
|
&& <div className={`table-list__add-item table-list__item--margin`}>
|
236
|
-
<Tooltip text='Add item' flow='top'
|
236
|
+
<Tooltip text='Add item' flow='top'>
|
237
237
|
<div className='table-list__add-item--container sd-margin-x--auto'>
|
238
238
|
{this.dropDown()}
|
239
239
|
</div>
|
@@ -244,7 +244,7 @@ class TableList extends React.PureComponent<IProps, IState> {
|
|
244
244
|
: (this.props.addItem && !this.props.readOnly)
|
245
245
|
? <div role='list' className={classes}>
|
246
246
|
<div className={`table-list__add-item table-list__item--margin`}>
|
247
|
-
<Tooltip text='Add item' flow='top'
|
247
|
+
<Tooltip text='Add item' flow='top'>
|
248
248
|
<div className='table-list__add-item--container sd-margin-x--auto'>
|
249
249
|
{this.dropDown()}
|
250
250
|
</div>
|
@@ -354,7 +354,7 @@ class TableListItem extends React.PureComponent<IPropsItem> {
|
|
354
354
|
{
|
355
355
|
this.props.addItem
|
356
356
|
&& <div className='table-list__add-bar-container'>
|
357
|
-
<Tooltip text='Add item' flow='top'
|
357
|
+
<Tooltip text='Add item' flow='top'>
|
358
358
|
<div className='table-list__add-bar'>
|
359
359
|
<Dropdown
|
360
360
|
onChange={this.props.onAddItem}
|
@@ -1,59 +1,87 @@
|
|
1
1
|
import * as React from 'react';
|
2
|
-
import
|
3
|
-
import {
|
2
|
+
import tippy, {Instance, Placement} from 'tippy.js';
|
3
|
+
import {assertNever} from '../helpers';
|
4
|
+
|
4
5
|
interface IProps {
|
5
|
-
text: string;
|
6
|
+
text: string | undefined | null;
|
6
7
|
flow?: 'top' | 'left' | 'right' | 'down'; // defaults to 'top'
|
7
|
-
appendToBody?: boolean;
|
8
|
-
disabled?: boolean;
|
9
8
|
}
|
10
9
|
|
11
|
-
|
12
|
-
|
13
|
-
|
14
|
-
|
15
|
-
|
16
|
-
|
17
|
-
|
18
|
-
|
19
|
-
|
20
|
-
|
21
|
-
|
22
|
-
|
23
|
-
|
24
|
-
|
25
|
-
}
|
26
|
-
}
|
27
|
-
render() {
|
28
|
-
if (React.isValidElement(this.props.children)) {
|
29
|
-
const attrs = {id: 't' + this.htmlId};
|
30
|
-
|
31
|
-
return (
|
32
|
-
React.cloneElement(this.props.children, attrs)
|
33
|
-
);
|
34
|
-
} else {
|
35
|
-
return (
|
36
|
-
<React.Fragment />
|
37
|
-
);
|
38
|
-
}
|
10
|
+
function flowToPlacement(flow: IProps['flow']): Placement | undefined {
|
11
|
+
switch (flow) {
|
12
|
+
case undefined:
|
13
|
+
return undefined;
|
14
|
+
case 'top':
|
15
|
+
return 'top';
|
16
|
+
case 'right':
|
17
|
+
return 'right';
|
18
|
+
case 'down':
|
19
|
+
return 'bottom';
|
20
|
+
case 'left':
|
21
|
+
return 'left';
|
22
|
+
default:
|
23
|
+
return assertNever(flow);
|
39
24
|
}
|
40
25
|
}
|
41
26
|
|
42
|
-
|
43
|
-
|
44
|
-
|
27
|
+
export class Tooltip extends React.PureComponent<IProps> {
|
28
|
+
private id: string;
|
29
|
+
private instance: Instance | null;
|
45
30
|
|
46
|
-
|
47
|
-
|
48
|
-
<PRTooltip target={"#" + triggerId} content={text} position={position ?? 'top'}/>
|
49
|
-
{ React.isValidElement(children)
|
50
|
-
? (() => {
|
51
|
-
const attrs = {id: triggerId};
|
31
|
+
constructor(props: IProps) {
|
32
|
+
super(props);
|
52
33
|
|
53
|
-
|
54
|
-
|
55
|
-
|
34
|
+
this.id = 'tooltip-' + Math.random().toString().slice(2);
|
35
|
+
this.instance = null;
|
36
|
+
}
|
37
|
+
|
38
|
+
private setupTooltip() {
|
39
|
+
const placement = flowToPlacement(this.props.flow ?? 'top');
|
40
|
+
const content = this.props.text;
|
41
|
+
|
42
|
+
if (this.instance == null) {
|
43
|
+
this.instance = tippy('#' + this.id, {
|
44
|
+
placement: placement,
|
45
|
+
})[0];
|
46
|
+
|
47
|
+
if (content != null) {
|
48
|
+
this.instance.setContent(content);
|
49
|
+
} else {
|
50
|
+
this.instance.hide();
|
51
|
+
this.instance.disable();
|
56
52
|
}
|
57
|
-
|
58
|
-
|
59
|
-
|
53
|
+
}
|
54
|
+
|
55
|
+
const willBeEnabled = content != null;
|
56
|
+
const isEnabled = this.instance.state.isEnabled;
|
57
|
+
|
58
|
+
if (isEnabled && willBeEnabled) {
|
59
|
+
this.instance.setContent(content);
|
60
|
+
} else if (isEnabled) {
|
61
|
+
// enabled now, but needs to be disabled
|
62
|
+
this.instance.hide();
|
63
|
+
this.instance.disable();
|
64
|
+
} else if (willBeEnabled) {
|
65
|
+
// disabled now, but needs to be enabled
|
66
|
+
this.instance.setContent(content);
|
67
|
+
this.instance.enable();
|
68
|
+
this.instance.show();
|
69
|
+
}
|
70
|
+
}
|
71
|
+
|
72
|
+
componentDidMount(): void {
|
73
|
+
this.setupTooltip();
|
74
|
+
}
|
75
|
+
|
76
|
+
componentDidUpdate(): void {
|
77
|
+
this.setupTooltip();
|
78
|
+
}
|
79
|
+
|
80
|
+
render() {
|
81
|
+
return (
|
82
|
+
<div id={this.id} style={{display: 'inline-flex'}}>
|
83
|
+
{this.props.children}
|
84
|
+
</div>
|
85
|
+
);
|
86
|
+
}
|
87
|
+
}
|
@@ -96,6 +96,13 @@ export class TreeSelect<T> extends React.Component<IProps<T>, IState<T>> {
|
|
96
96
|
private popperInstance: Instance | null;
|
97
97
|
private zIndex: number = getNextZIndex();
|
98
98
|
|
99
|
+
/*
|
100
|
+
* This variable is used to distinguish changes coming from outside (from props.value)
|
101
|
+
* from those made by the user through interaction with the component.
|
102
|
+
* It prevents triggering `onChange` when `props.value` updates externally.
|
103
|
+
*/
|
104
|
+
private changesFromOutside: boolean;
|
105
|
+
|
99
106
|
constructor(props: IProps<T>) {
|
100
107
|
super(props);
|
101
108
|
this.state = {
|
@@ -133,6 +140,7 @@ export class TreeSelect<T> extends React.Component<IProps<T>, IState<T>> {
|
|
133
140
|
this.treeSelectRef = React.createRef();
|
134
141
|
this.popperInstance = null;
|
135
142
|
this.onDragEnd = this.onDragEnd.bind(this);
|
143
|
+
this.changesFromOutside = false;
|
136
144
|
}
|
137
145
|
|
138
146
|
inputFocus = () => {
|
@@ -212,8 +220,13 @@ export class TreeSelect<T> extends React.Component<IProps<T>, IState<T>> {
|
|
212
220
|
|
213
221
|
componentDidUpdate(prevProps: Readonly<IProps<T>>, prevState: Readonly<IState<T>>): void {
|
214
222
|
if (!isEqual(prevState.value, this.state.value)) {
|
215
|
-
|
223
|
+
if (this.changesFromOutside) {
|
224
|
+
this.changesFromOutside = false;
|
225
|
+
} else {
|
226
|
+
this.props.onChange(this.state.value);
|
227
|
+
}
|
216
228
|
} else if (!isEqual(prevProps.value, this.props.value)) {
|
229
|
+
this.changesFromOutside = true;
|
217
230
|
this.setState({
|
218
231
|
value: this.props.value ?? [],
|
219
232
|
});
|
@@ -31,7 +31,7 @@ export default class TooltipDoc extends React.Component {
|
|
31
31
|
</Tooltip>
|
32
32
|
<Tooltip text="Right on!" flow='right'>
|
33
33
|
<Button text='right' onClick={() => false} />
|
34
|
-
</Tooltip>
|
34
|
+
</Tooltip>
|
35
35
|
</div>
|
36
36
|
</Markup.ReactMarkupPreview>
|
37
37
|
<Markup.ReactMarkupCode>{`
|
@@ -51,53 +51,10 @@ export default class TooltipDoc extends React.Component {
|
|
51
51
|
</Markup.ReactMarkupCode>
|
52
52
|
</Markup.ReactMarkup>
|
53
53
|
|
54
|
-
<h3 className="docs-page__h3">Appended to body</h3>
|
55
|
-
<p className="docs-page__paragraph">
|
56
|
-
Appends tooltip element to body therefore avoids overflow issues. For performance reasons don't use it if not necessary.
|
57
|
-
</p>
|
58
|
-
<Markup.ReactMarkup>
|
59
|
-
<Markup.ReactMarkupPreview>
|
60
|
-
|
61
|
-
<div className="docs-page__content-row docs-page__content-row--no-margin">
|
62
|
-
|
63
|
-
<div className="docs-page__content-row docs-page__content-row--no-margin">
|
64
|
-
<Tooltip text="I'm appended to body" flow='top' appendToBody={true}>
|
65
|
-
<Button text='top' onClick={() => false} />
|
66
|
-
</Tooltip>
|
67
|
-
<Tooltip text="I'm appended to body" flow='down' appendToBody={true}>
|
68
|
-
<Button text='Down' onClick={() => false} />
|
69
|
-
</Tooltip>
|
70
|
-
<Tooltip text="I'm appended to body" flow='left' appendToBody={true}>
|
71
|
-
<Button text='left' onClick={() => false} />
|
72
|
-
</Tooltip>
|
73
|
-
<Tooltip text="I'm appended to body" flow='right' appendToBody={true}>
|
74
|
-
<Button text='right' onClick={() => false} />
|
75
|
-
</Tooltip>
|
76
|
-
</div>
|
77
|
-
</div>
|
78
|
-
</Markup.ReactMarkupPreview>
|
79
|
-
<Markup.ReactMarkupCode>{`
|
80
|
-
<Tooltip text="I'm appended to body" flow='top' appendToBody={true}>
|
81
|
-
<Button text='top' onClick={() => false} />
|
82
|
-
</Tooltip>
|
83
|
-
<Tooltip text="I'm appended to body" flow='down' appendToBody={true}>
|
84
|
-
<Button text='Down' onClick={() => false} />
|
85
|
-
</Tooltip>
|
86
|
-
<Tooltip text="I'm appended to body" flow='left' appendToBody={true}>
|
87
|
-
<Button text='left' onClick={() => false} />
|
88
|
-
</Tooltip>
|
89
|
-
<Tooltip text="I'm appended to body" flow='right' appendToBody={true}>
|
90
|
-
<Button text='right' onClick={() => false} />
|
91
|
-
</Tooltip>
|
92
|
-
`}
|
93
|
-
</Markup.ReactMarkupCode>
|
94
|
-
</Markup.ReactMarkup>
|
95
|
-
|
96
54
|
<h3 className="docs-page__h3">Props</h3>
|
97
55
|
<PropsList>
|
98
56
|
<Prop name='text' isRequired={true} type='string' default='/' description='Tooltip text value.' />
|
99
57
|
<Prop name='flow' isRequired={false} type='top | left | right | down' default='top' description='Position of tooltip text.' />
|
100
|
-
<Prop name='appendToBody' isRequired={false} type='boolean' default='false' description='Appends element to body therefore avoids overflow issues.' />
|
101
58
|
</PropsList>
|
102
59
|
</section>
|
103
60
|
)
|
@@ -12,7 +12,7 @@ interface IState {
|
|
12
12
|
arr: any;
|
13
13
|
}
|
14
14
|
|
15
|
-
|
15
|
+
const multiSelectOptions = [
|
16
16
|
{
|
17
17
|
value: {name: 'Category1'},
|
18
18
|
children: [
|
@@ -93,7 +93,7 @@ let options = [
|
|
93
93
|
},
|
94
94
|
]
|
95
95
|
|
96
|
-
|
96
|
+
const singleSelectOptions = [
|
97
97
|
{
|
98
98
|
value: {name: 'Category1', border: 'red'},
|
99
99
|
children: [
|
@@ -169,9 +169,6 @@ let options2 = [
|
|
169
169
|
},
|
170
170
|
]
|
171
171
|
|
172
|
-
let fetchedArr = [];
|
173
|
-
fetch('https://nominatim.openstreetmap.org/search/berlin?format=json&addressdetails=1&limit=20').then(response => response.json()).then(data => fetchedArr = data);
|
174
|
-
|
175
172
|
type ICancelFn = () => void;
|
176
173
|
|
177
174
|
function searchOptions(
|
@@ -181,9 +178,7 @@ function searchOptions(
|
|
181
178
|
let timeout = setTimeout(() => {
|
182
179
|
|
183
180
|
callback(
|
184
|
-
|
185
|
-
.filter((item: any) => item.display_name.toLocaleLowerCase().includes(term.toLocaleLowerCase()))
|
186
|
-
.map((item) => ({value: item})),
|
181
|
+
multiSelectOptions.filter((item: any) => item.value.name.toLocaleLowerCase().includes(term.toLocaleLowerCase()))
|
187
182
|
);
|
188
183
|
}, 1000);
|
189
184
|
|
@@ -198,8 +193,8 @@ export class TreeSelectDocs extends React.Component<{}, IState> {
|
|
198
193
|
this.state = {
|
199
194
|
value: [],
|
200
195
|
value2: [],
|
201
|
-
options:
|
202
|
-
options2:
|
196
|
+
options: multiSelectOptions,
|
197
|
+
options2: multiSelectOptions,
|
203
198
|
inputValue: '',
|
204
199
|
arr: []
|
205
200
|
}
|
@@ -244,7 +239,7 @@ export class TreeSelectDocs extends React.Component<{}, IState> {
|
|
244
239
|
<TreeSelect
|
245
240
|
kind='synchronous'
|
246
241
|
value={[{name: 'Category1'}]}
|
247
|
-
getOptions={() =>
|
242
|
+
getOptions={() => multiSelectOptions}
|
248
243
|
getId={(item) => item.name}
|
249
244
|
getLabel={(item) => item.name}
|
250
245
|
selectBranchWithChildren
|
@@ -300,7 +295,7 @@ export class TreeSelectDocs extends React.Component<{}, IState> {
|
|
300
295
|
<TreeSelect
|
301
296
|
kind='synchronous'
|
302
297
|
value={[{name: 'Category1'}, {name: 'Category2'}, {name: 'Category3'}]}
|
303
|
-
getOptions={() =>
|
298
|
+
getOptions={() => multiSelectOptions}
|
304
299
|
getId={(item) => item.name}
|
305
300
|
getLabel={(item) => item.name}
|
306
301
|
selectBranchWithChildren
|
@@ -358,8 +353,8 @@ export class TreeSelectDocs extends React.Component<{}, IState> {
|
|
358
353
|
<TreeSelect
|
359
354
|
kind="asynchronous"
|
360
355
|
value={this.state.value}
|
361
|
-
getLabel={({
|
362
|
-
getId={({
|
356
|
+
getLabel={({name}) => name}
|
357
|
+
getId={({name}) => name}
|
363
358
|
selectBranchWithChildren
|
364
359
|
allowMultiple
|
365
360
|
searchOptions={searchOptions}
|
@@ -400,7 +395,7 @@ export class TreeSelectDocs extends React.Component<{}, IState> {
|
|
400
395
|
<TreeSelect
|
401
396
|
kind='synchronous'
|
402
397
|
value={[]}
|
403
|
-
getOptions={() =>
|
398
|
+
getOptions={() => singleSelectOptions}
|
404
399
|
getLabel={(item) => item.name}
|
405
400
|
getId={(item) => item.name}
|
406
401
|
getBorderColor={(item) => item.border}
|