superdesk-ui-framework 4.0.14 → 4.0.17

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.
@@ -4,6 +4,7 @@ on:
4
4
  push:
5
5
  branches:
6
6
  - 'develop'
7
+ - 'v3'
7
8
 
8
9
  jobs:
9
10
  publish:
@@ -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} appendToBody={true}>
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
- <DatePicker
64
- disabled={this.props.disabled}
65
- preview={this.props.preview}
66
- required={this.props.required}
67
- hideClearButton={true}
68
- value={this.props.value}
69
- onChange={(val) => {
70
- this.handleDateChange(val);
71
- }}
72
- dateFormat={this.props.dateFormat}
73
- label={this.props.label.text}
74
- inlineLabel={this.props.label.hidden ?? false}
75
- labelHidden={this.props.label.hidden ?? false}
76
- fullWidth={this.props.fullWidth}
77
- />
78
- <TimePicker
79
- disabled={this.props.disabled}
80
- preview={this.props.preview}
81
- value={convertedTimeValue}
82
- onChange={(val) => {
83
- this.handleTimeChange(val);
84
- }}
85
- inlineLabel
86
- labelHidden
87
- allowSeconds={this.props.allowSeconds}
88
- fullWidth={this.props.fullWidth}
89
- required={this.props.required}
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} appendToBody={this.props.toolTipAppend}>
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' appendToBody={true}>
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' appendToBody={true}>
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' appendToBody={true}>
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' appendToBody={true}>
357
+ <Tooltip text='Add item' flow='top'>
358
358
  <div className='table-list__add-bar'>
359
359
  <Dropdown
360
360
  onChange={this.props.onAddItem}
@@ -61,7 +61,6 @@ export class Switch extends React.PureComponent<IProps> {
61
61
  <Tooltip
62
62
  text={this.props.label.content}
63
63
  flow={this.props.toolTipFlow}
64
- appendToBody={this.props.toolTipAppend}
65
64
  >
66
65
  <span className="sd-switch__wrapper" tabIndex={-1}>
67
66
  {checkboxInput}
@@ -1,59 +1,92 @@
1
1
  import * as React from 'react';
2
- import nextId from "react-id-generator";
3
- import { Tooltip as PRTooltip } from '@superdesk/primereact/tooltip';
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
- export const Tooltip: React.FC<IProps> = ({appendToBody, children, disabled, ...otherProps}) =>
12
- disabled
13
- ? <React.Fragment>{children}</React.Fragment>
14
- : appendToBody
15
- ? <TooltipAppended {...otherProps}>{children}</TooltipAppended>
16
- : <TooltipBasic {...otherProps}>{children}</TooltipBasic>;
17
-
18
- class TooltipBasic extends React.PureComponent<IProps> {
19
- htmlId = nextId();
20
- componentDidMount() {
21
- let tooltip = document.getElementById('t' + this.htmlId);
22
- tooltip?.setAttribute('data-sd-tooltip', this.props.text);
23
- if (this.props.flow) {
24
- tooltip?.setAttribute('data-flow', this.props.flow);
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
- const TooltipAppended: React.FC<IProps> = ({children, flow, text}) => {
43
- const triggerId = `uif-tooltip-${Math.random().toString().slice(2)}`;
44
- const position = flow === "down" ? "bottom" : flow;
27
+ export class Tooltip extends React.PureComponent<IProps> {
28
+ private id: string;
29
+ private instance: Instance | null;
30
+
31
+ constructor(props: IProps) {
32
+ super(props);
45
33
 
46
- return (
47
- <React.Fragment>
48
- <PRTooltip target={"#" + triggerId} content={text} position={position ?? 'top'}/>
49
- { React.isValidElement(children)
50
- ? (() => {
51
- const attrs = {id: triggerId};
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];
52
46
 
53
- return React.cloneElement(children, attrs);
54
- })()
55
- : <React.Fragment />
47
+ if (this.instance == null) {
48
+ // prevent crashing in unit tests
49
+ return;
56
50
  }
57
- </React.Fragment>
58
- );
59
- };
51
+
52
+ if (content != null) {
53
+ this.instance.setContent(content);
54
+ } else {
55
+ this.instance.hide();
56
+ this.instance.disable();
57
+ }
58
+ }
59
+
60
+ const willBeEnabled = content != null;
61
+ const isEnabled = this.instance.state.isEnabled;
62
+
63
+ if (isEnabled && willBeEnabled) {
64
+ this.instance.setContent(content);
65
+ } else if (isEnabled) {
66
+ // enabled now, but needs to be disabled
67
+ this.instance.hide();
68
+ this.instance.disable();
69
+ } else if (willBeEnabled) {
70
+ // disabled now, but needs to be enabled
71
+ this.instance.setContent(content);
72
+ this.instance.enable();
73
+ this.instance.show();
74
+ }
75
+ }
76
+
77
+ componentDidMount(): void {
78
+ this.setupTooltip();
79
+ }
80
+
81
+ componentDidUpdate(): void {
82
+ this.setupTooltip();
83
+ }
84
+
85
+ render() {
86
+ return (
87
+ <div id={this.id} style={{display: 'inline-flex'}}>
88
+ {this.props.children}
89
+ </div>
90
+ );
91
+ }
92
+ }
@@ -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
  )