superdesk-ui-framework 3.0.1-beta.3 → 3.0.1-beta.4

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 (99) hide show
  1. package/app/styles/_sd-tag-input.scss +201 -296
  2. package/app/styles/components/_list-item.scss +13 -1
  3. package/app/styles/components/_sd-photo-preview.scss +1 -1
  4. package/app/styles/design-tokens/_new-colors.scss +1 -1
  5. package/app/styles/form-elements/_forms-general.scss +22 -7
  6. package/app/styles/form-elements/_inputs.scss +131 -54
  7. package/app-typescript/components/Badge.tsx +3 -2
  8. package/app-typescript/components/DatePicker.tsx +40 -52
  9. package/app-typescript/components/DurationInput.tsx +306 -0
  10. package/app-typescript/components/Form/InputBase.tsx +85 -0
  11. package/app-typescript/components/Form/InputNew.tsx +105 -0
  12. package/app-typescript/components/Form/InputWrapper.tsx +79 -0
  13. package/app-typescript/components/Form/index.tsx +3 -0
  14. package/app-typescript/components/Input.tsx +28 -45
  15. package/app-typescript/components/Label.tsx +49 -10
  16. package/app-typescript/components/Layouts/Layout.tsx +1 -1
  17. package/app-typescript/components/Lists/ContentList.tsx +4 -4
  18. package/app-typescript/components/MultiSelect.tsx +37 -50
  19. package/app-typescript/components/Navigation/BottomNav.tsx +3 -2
  20. package/app-typescript/components/Select.tsx +23 -41
  21. package/app-typescript/components/SelectWithTemplate.tsx +32 -7
  22. package/app-typescript/components/TimePicker.tsx +48 -16
  23. package/app-typescript/components/TreeSelect.tsx +423 -195
  24. package/app-typescript/index.ts +3 -1
  25. package/dist/examples.bundle.js +16398 -15334
  26. package/dist/playgrounds/react-playgrounds/CoreLayout.tsx +64 -54
  27. package/dist/playgrounds/react-playgrounds/RundownEditor.tsx +24 -16
  28. package/dist/playgrounds/react-playgrounds/TestGround.tsx +76 -1
  29. package/dist/playgrounds/react-playgrounds/components/Layout.tsx +1 -1
  30. package/dist/react/Badges.tsx +18 -0
  31. package/dist/react/ContentList.tsx +15 -9
  32. package/dist/react/DatePicker.tsx +21 -1
  33. package/dist/react/DurationInput.tsx +104 -0
  34. package/dist/react/Index.tsx +5 -0
  35. package/dist/react/Inputs.tsx +153 -2
  36. package/dist/react/Labels.tsx +51 -1
  37. package/dist/react/MultiSelect.tsx +4 -1
  38. package/dist/react/SelectWithTemplate.tsx +6 -1
  39. package/dist/react/TableList.tsx +22 -44
  40. package/dist/react/TimePicker.tsx +16 -8
  41. package/dist/react/TreeSelect.tsx +301 -48
  42. package/dist/react/tree-select/TreeSelect.tsx +273 -0
  43. package/dist/react/tree-select/example-1.tsx +71 -0
  44. package/dist/react/tree-select/example-2.tsx +59 -0
  45. package/dist/superdesk-ui.bundle.css +411 -370
  46. package/dist/superdesk-ui.bundle.js +15554 -14493
  47. package/dist/vendor.bundle.js +27 -27
  48. package/examples/pages/playgrounds/react-playgrounds/CoreLayout.tsx +64 -54
  49. package/examples/pages/playgrounds/react-playgrounds/RundownEditor.tsx +24 -16
  50. package/examples/pages/playgrounds/react-playgrounds/TestGround.tsx +76 -1
  51. package/examples/pages/playgrounds/react-playgrounds/components/Layout.tsx +1 -1
  52. package/examples/pages/react/Badges.tsx +18 -0
  53. package/examples/pages/react/ContentList.tsx +15 -9
  54. package/examples/pages/react/DatePicker.tsx +21 -1
  55. package/examples/pages/react/DurationInput.tsx +104 -0
  56. package/examples/pages/react/Index.tsx +5 -0
  57. package/examples/pages/react/Inputs.tsx +153 -2
  58. package/examples/pages/react/Labels.tsx +51 -1
  59. package/examples/pages/react/MultiSelect.tsx +4 -1
  60. package/examples/pages/react/SelectWithTemplate.tsx +6 -1
  61. package/examples/pages/react/TableList.tsx +22 -44
  62. package/examples/pages/react/TimePicker.tsx +16 -8
  63. package/examples/pages/react/TreeSelect.tsx +301 -48
  64. package/examples/pages/react/tree-select/TreeSelect.tsx +273 -0
  65. package/examples/pages/react/tree-select/example-1.tsx +71 -0
  66. package/examples/pages/react/tree-select/example-2.tsx +59 -0
  67. package/package.json +2 -1
  68. package/react/components/Badge.d.ts +1 -0
  69. package/react/components/Badge.js +2 -2
  70. package/react/components/DatePicker.d.ts +1 -0
  71. package/react/components/DatePicker.js +6 -22
  72. package/react/components/DurationInput.d.ts +38 -0
  73. package/react/components/DurationInput.js +271 -0
  74. package/react/components/Form/InputBase.d.ts +42 -0
  75. package/react/components/Form/InputBase.js +72 -0
  76. package/react/components/Form/InputNew.d.ts +45 -0
  77. package/react/components/Form/InputNew.js +73 -0
  78. package/react/components/Form/InputWrapper.d.ts +28 -0
  79. package/react/components/Form/InputWrapper.js +91 -0
  80. package/react/components/Form/index.d.ts +3 -0
  81. package/react/components/Form/index.js +7 -1
  82. package/react/components/Input.js +5 -34
  83. package/react/components/Label.d.ts +1 -0
  84. package/react/components/Label.js +18 -2
  85. package/react/components/Layouts/Layout.js +1 -1
  86. package/react/components/Lists/ContentList.d.ts +45 -0
  87. package/react/components/Lists/ContentList.js +85 -0
  88. package/react/components/Navigation/BottomNav.d.ts +1 -0
  89. package/react/components/Navigation/BottomNav.js +2 -2
  90. package/react/components/Select.d.ts +1 -1
  91. package/react/components/Select.js +4 -26
  92. package/react/components/SelectWithTemplate.d.ts +11 -1
  93. package/react/components/SelectWithTemplate.js +19 -10
  94. package/react/components/TimePicker.d.ts +15 -2
  95. package/react/components/TimePicker.js +15 -4
  96. package/react/components/TreeSelect.d.ts +75 -0
  97. package/react/components/TreeSelect.js +448 -0
  98. package/react/index.d.ts +3 -0
  99. package/react/index.js +8 -3
@@ -8,6 +8,7 @@ interface IProps {
8
8
  size?: 'small' | 'normal' | 'large'; // defaults to 'normal'
9
9
  onClick?(): void;
10
10
  noTransform?: boolean;
11
+ hexColor?: string;
11
12
  style?: 'filled' | 'hollow' | 'translucent'; // defaults to 'filled'
12
13
  }
13
14
  export class Label extends React.PureComponent<IProps> {
@@ -21,17 +22,55 @@ export class Label extends React.PureComponent<IProps> {
21
22
  [`hollow-${this.props.color}`]: this.props.color && this.props.style === 'hollow',
22
23
  });
23
24
  if (this.props.link || this.props.onClick) {
24
- return (
25
- <a href={this.props.link} className={classes} onClick={this.props.onClick}>
26
- {this.props.text}
27
- </a>
28
- );
25
+ if (this.props.style === 'hollow') {
26
+ return (
27
+ <a className={classes}
28
+ href={this.props.link}
29
+ onClick={this.props.onClick}
30
+ style={{color: this.props.hexColor, borderColor: this.props.hexColor}}>
31
+ {this.props.text}
32
+ </a>
33
+ );
34
+ } else if (this.props.style === 'translucent') {
35
+ return (
36
+ <a className={classes}
37
+ href={this.props.link}
38
+ onClick={this.props.onClick}
39
+ style={{color: this.props.hexColor, backgroundColor: `${this.props.hexColor}33`}}>
40
+ {this.props.text}
41
+ </a>
42
+ );
43
+ } else {
44
+ return (
45
+ <a className={classes}
46
+ href={this.props.link}
47
+ onClick={this.props.onClick} style={{backgroundColor: this.props.hexColor}}>
48
+ {this.props.text}
49
+ </a>
50
+ );
51
+ }
29
52
  } else {
30
- return (
31
- <span className={classes}>
32
- {this.props.text}
33
- </span>
34
- );
53
+ if (this.props.style === 'hollow') {
54
+ return (
55
+ <span className={classes}
56
+ style={{color: this.props.hexColor, borderColor: this.props.hexColor}}>
57
+ {this.props.text}
58
+ </span>
59
+ );
60
+ } else if (this.props.style === 'translucent') {
61
+ return (
62
+ <span className={classes}
63
+ style={{color: this.props.hexColor, backgroundColor: `${this.props.hexColor}33`}}>
64
+ {this.props.text}
65
+ </span>
66
+ );
67
+ } else {
68
+ return (
69
+ <span className={classes} style={{backgroundColor: this.props.hexColor}}>
70
+ {this.props.text}
71
+ </span>
72
+ );
73
+ }
35
74
  }
36
75
  }
37
76
  }
@@ -26,7 +26,7 @@ export const Layout = ({
26
26
  {children}
27
27
  </section>
28
28
  <footer className='sd-bottom-bar'>
29
- This is the footer.
29
+ Footer
30
30
  </footer>
31
31
  </div>
32
32
  );
@@ -7,7 +7,7 @@ interface IPropsItem {
7
7
  itemColum: Array<{itemRow: Array<{content: any}>, border?: boolean, fullwidth?: boolean}>;
8
8
  activated?: boolean;
9
9
  selected?: boolean;
10
- fetched?: boolean;
10
+ archived?: boolean;
11
11
  loading?: boolean;
12
12
  onClick?(): void;
13
13
  onDoubleClick?(): void;
@@ -18,7 +18,7 @@ class ContentListItem extends React.PureComponent<IPropsItem> {
18
18
  let classes = classNames('sd-list-item sd-list-item-group sd-list-item-group--space-between-items', {
19
19
  'sd-list-item--activated': this.props.activated,
20
20
  'sd-list-item--selected': this.props.selected,
21
- 'fetched': this.props.fetched,
21
+ 'fetched': this.props.archived,
22
22
  'actioning': this.props.loading,
23
23
  });
24
24
 
@@ -60,7 +60,7 @@ interface IProps {
60
60
  loading?: boolean,
61
61
  activated?: boolean,
62
62
  selected?: boolean,
63
- fetched?: boolean,
63
+ archived?: boolean,
64
64
  onClick?(): void,
65
65
  onDoubleClick?(): void;
66
66
  }>;
@@ -86,7 +86,7 @@ class ContentList extends React.PureComponent<IProps> {
86
86
  loading={item.loading}
87
87
  activated={item.activated}
88
88
  selected={item.selected}
89
- fetched={item.fetched}
89
+ archived={item.archived}
90
90
  onClick={item.onClick}
91
91
  onDoubleClick={item.onDoubleClick} />;
92
92
  })}
@@ -2,6 +2,7 @@ import * as React from "react";
2
2
  import { MultiSelect as PrimeMultiSelect } from "@superdesk/primereact/multiselect";
3
3
  import classNames from 'classnames';
4
4
  import nextId from "react-id-generator";
5
+ import { InputWrapper } from "./Form";
5
6
 
6
7
  interface IProps<T> {
7
8
  value: Array<T>;
@@ -39,6 +40,8 @@ interface IState<T> {
39
40
  }
40
41
 
41
42
  export class MultiSelect<T> extends React.Component<IProps<T>, IState<T>> {
43
+ private htmlId = nextId();
44
+
42
45
  constructor(props: IProps<T>) {
43
46
  super(props);
44
47
  this.state = {
@@ -55,58 +58,42 @@ export class MultiSelect<T> extends React.Component<IProps<T>, IState<T>> {
55
58
  'showFilter': this.props.filter,
56
59
  });
57
60
 
58
- const labelClasses = classNames('sd-input__label', {
59
- 'a11y-only': this.props.labelHidden,
60
- });
61
-
62
- const classesLabel = classNames('sd-input', {
63
- 'sd-input--inline-label': this.props.inlineLabel,
64
- 'sd-input--required': this.props.required,
65
- 'sd-input--disabled': this.props.disabled,
66
- 'sd-input--full-width': this.props.fullWidth,
67
- 'sd-input--invalid': this.props.invalid || this.state.invalid,
68
- });
69
-
70
- const htmlId = nextId();
71
-
72
61
  return (
73
- <div className={classesLabel}>
74
- <label className={labelClasses} htmlFor={htmlId} id={htmlId + 'label'}
75
- tabIndex={this.props.tabindex === undefined ? undefined : -1}>
76
- {this.props.label}
77
- </label>
78
-
62
+ <InputWrapper
63
+ label={this.props.label}
64
+ error={this.props.error}
65
+ required={this.props.required}
66
+ disabled={this.props.disabled}
67
+ invalid={this.state.invalid}
68
+ info={this.props.info}
69
+ inlineLabel={this.props.inlineLabel}
70
+ labelHidden={this.props.labelHidden}
71
+ fullWidth={this.props.fullWidth}
72
+ htmlId={this.htmlId}
73
+ tabindex={this.props.tabindex}>
79
74
  <PrimeMultiSelect
80
- panelClassName={classes}
81
- value={this.props.value}
82
- options={this.props.options}
83
- onChange={(e: any) => this.props.onChange(e)}
84
- display="chip"
85
- filter={this.props.filter}
86
- filterBy={this.props.optionLabel}
87
- appendTo={document.body}
88
- placeholder={this.props.placeholder}
89
- optionLabel={this.props.optionLabel}
90
- emptyFilterMessage={this.props.emptyFilterMessage}
91
- filterPlaceholder={this.props.filterPlaceholder}
92
- itemTemplate={this.props.itemTemplate}
93
- selectedItemTemplate={this.props.selectedItemTemplate}
94
- maxSelectedLabels={this.props.maxSelectedLabels ?? 4}
95
- selectedItemsLabel={this.props.selectedItemsLabel}
96
- ariaLabelledBy={this.props.ariaLabelledBy}
97
- tabIndex={this.props.tabIndex ? this.props.tabIndex : '0'}
98
- showClear={this.props.showClear}
99
- disabled={this.props.disabled}
100
- />
101
-
102
- <div className='sd-input__message-box'>
103
- {this.props.info && !this.props.invalid && !this.state.invalid ?
104
- <div className='sd-input__hint'>{this.props.info}</div> : null}
105
- {this.props.invalid || this.state.invalid ?
106
- <div className='sd-input__message'>{this.props.error}</div>
107
- : null}
108
- </div>
109
- </div>
75
+ panelClassName={classes}
76
+ value={this.props.value}
77
+ options={this.props.options}
78
+ onChange={(e: any) => this.props.onChange(e)}
79
+ display="chip"
80
+ filter={this.props.filter}
81
+ filterBy={this.props.optionLabel}
82
+ appendTo={document.body}
83
+ placeholder={this.props.placeholder}
84
+ optionLabel={this.props.optionLabel}
85
+ emptyFilterMessage={this.props.emptyFilterMessage}
86
+ filterPlaceholder={this.props.filterPlaceholder}
87
+ itemTemplate={this.props.itemTemplate}
88
+ selectedItemTemplate={this.props.selectedItemTemplate}
89
+ maxSelectedLabels={this.props.maxSelectedLabels ?? 4}
90
+ selectedItemsLabel={this.props.selectedItemsLabel}
91
+ ariaLabelledBy={this.htmlId + 'label'}
92
+ tabIndex={this.props.tabIndex ? this.props.tabIndex : '0'}
93
+ showClear={this.props.showClear}
94
+ disabled={this.props.disabled}
95
+ inputId={this.htmlId} />
96
+ </InputWrapper>
110
97
  );
111
98
  }
112
99
  }
@@ -13,6 +13,7 @@ interface IItem {
13
13
  active?: boolean;
14
14
  title: string;
15
15
  onClick(event: any): void;
16
+ onRemove(event: any): void;
16
17
  }
17
18
 
18
19
  interface IState {
@@ -55,7 +56,7 @@ export class BottomNav extends React.PureComponent<IProps, IState> {
55
56
  render() {
56
57
  return (
57
58
  <ul className='sd-bottom-nav-list'>
58
- {this.state.items.map((item, index) => {
59
+ {this.props.items.map((item, index) => {
59
60
  return (
60
61
  <li key={index}
61
62
  className={'sd-bottom-nav-list__item' + (item['active'] ? ' sd-bottom-nav-list__item--active' : (index === this.state.index ? ' sd-bottom-nav-list__item--active' : ''))}>
@@ -72,7 +73,7 @@ export class BottomNav extends React.PureComponent<IProps, IState> {
72
73
  size='small'
73
74
  icon="close-small"
74
75
  ariaValue='Delete'
75
- onClick={() => this.handleDelete(index)} />
76
+ onClick={() => item.onRemove(index)} />
76
77
  </li>
77
78
  );
78
79
  })}
@@ -1,6 +1,7 @@
1
1
  import * as React from 'react';
2
- import classNames from 'classnames';
2
+ // import classNames from 'classnames';
3
3
  import nextId from "react-id-generator";
4
+ import { InputWrapper } from './Form';
4
5
 
5
6
  interface ISelect {
6
7
  value?: string;
@@ -27,6 +28,7 @@ interface IState {
27
28
  }
28
29
 
29
30
  class Select extends React.Component<ISelect, IState> {
31
+ private htmlId = nextId();
30
32
  constructor(props: ISelect) {
31
33
  super(props);
32
34
 
@@ -38,55 +40,35 @@ class Select extends React.Component<ISelect, IState> {
38
40
  this.handleChange = this.handleChange.bind(this);
39
41
  }
40
42
 
41
- htmlId = nextId();
42
-
43
43
  handleChange(event: React.ChangeEvent<HTMLSelectElement>) {
44
44
  this.setState({ value: event.target.value });
45
45
  this.props.onChange(event.target.value);
46
46
  }
47
47
 
48
48
  render() {
49
- const classes = classNames('sd-input sd-input--is-select', {
50
- 'sd-input--inline-label': this.props.inlineLabel,
51
- 'sd-input--required': this.props.required,
52
- 'sd-input--disabled': this.props.disabled,
53
- 'sd-input--full-width': this.props.fullWidth,
54
- 'sd-input--invalid': this.props.invalid || this.state.invalid,
55
- 'sd-input--medium': this.props.size === undefined,
56
- [`sd-input--${this.props.size}`]: this.props.size || this.props.size !== undefined,
57
- 'sd-input--boxed-style': this.props.boxedStyle,
58
- 'sd-input--boxed-label': this.props.boxedLable,
59
- });
60
- const labelClasses = classNames('sd-input__label', {
61
- 'a11y-only': this.props.labelHidden,
62
- });
63
-
64
49
  return (
65
- <div className={classes}>
66
- <label className={labelClasses}
67
- htmlFor={this.htmlId}
68
- tabIndex={this.props.tabindex === undefined ? undefined : -1}>
69
- {this.props.label}
70
- </label>
71
-
50
+ <InputWrapper
51
+ label={this.props.label}
52
+ error={this.props.error}
53
+ required={this.props.required}
54
+ disabled={this.props.disabled}
55
+ invalid={this.state.invalid}
56
+ info={this.props.info}
57
+ inlineLabel={this.props.inlineLabel}
58
+ labelHidden={this.props.labelHidden}
59
+ fullWidth={this.props.fullWidth}
60
+ htmlId={this.htmlId}
61
+ tabindex={this.props.tabindex}>
72
62
  <select className='sd-input__select'
73
- id={this.htmlId}
74
- value={this.state.value}
75
- aria-describedby={this.htmlId}
76
- tabIndex={this.props.tabindex}
77
- onChange={this.handleChange}
78
- disabled={this.props.disabled}>
79
- {this.props.children}
63
+ id={this.htmlId}
64
+ value={this.state.value}
65
+ aria-describedby={this.htmlId}
66
+ tabIndex={this.props.tabindex}
67
+ onChange={this.handleChange}
68
+ disabled={this.props.disabled}>
69
+ {this.props.children}
80
70
  </select>
81
-
82
- <div className='sd-input__message-box'>
83
- {this.props.info && !this.props.invalid && !this.state.invalid ?
84
- <div className='sd-input__hint'>{this.props.info}</div> : null}
85
- {this.props.invalid || this.state.invalid ?
86
- <div className='sd-input__message'>{this.props.error}</div>
87
- : null}
88
- </div>
89
- </div>
71
+ </InputWrapper>
90
72
  );
91
73
  }
92
74
  }
@@ -1,5 +1,8 @@
1
1
  import * as React from 'react';
2
2
  import {Dropdown} from '@superdesk/primereact/dropdown';
3
+ // import classNames from 'classnames';
4
+ import nextId from "react-id-generator";
5
+ import { InputWrapper } from './Form';
3
6
 
4
7
  interface IProps<T> {
5
8
  // Don't forget to cancel unfinished requests every the prop is called.
@@ -11,32 +14,41 @@ interface IProps<T> {
11
14
  itemTemplate: React.ComponentType<{option: T | null}>;
12
15
  noResultsFoundMessage: string;
13
16
  filterPlaceholder?: string;
14
-
15
17
  disabled?: boolean;
16
- required?: boolean;
17
18
  autoFocus?: boolean;
18
19
  autoOpen?: boolean; // Avoid using this - the dropdown may cover important elements.
19
20
  width?: 'min' | '100%'; // defaults to min
20
21
  zIndex?: number;
21
22
  'data-test-id'?: string;
23
+ inlineLabel?: boolean;
24
+ required?: boolean;
25
+ fullWidth?: boolean;
26
+ invalid?: boolean;
27
+ labelHidden?: boolean;
28
+ tabindex?: number;
29
+ label?: string;
30
+ info?: string;
31
+ error?: string;
22
32
  }
23
33
 
24
34
  interface IState<T> {
25
35
  options: Array<T>;
26
36
  loading: boolean;
37
+ invalid: boolean;
27
38
  }
28
39
 
29
40
  const labelKey = 'label';
30
41
 
31
42
  export class SelectWithTemplate<T> extends React.Component<IProps<T>, IState<T>> {
32
43
  componentRef: Dropdown | null;
33
-
44
+ private htmlId = nextId();
34
45
  constructor(props: IProps<T>) {
35
46
  super(props);
36
47
 
37
48
  this.state = {
38
49
  options: [],
39
50
  loading: false,
51
+ invalid: this.props.invalid ? this.props.invalid : false,
40
52
  };
41
53
 
42
54
  this.componentRef = null;
@@ -87,7 +99,21 @@ export class SelectWithTemplate<T> extends React.Component<IProps<T>, IState<T>>
87
99
  const fakePlaceholderWithNonBreakingSpace = ' ';
88
100
 
89
101
  return (
90
- <Dropdown
102
+ <InputWrapper
103
+ label={this.props.label}
104
+ error={this.props.error}
105
+ required={this.props.required}
106
+ disabled={this.props.disabled}
107
+ invalid={this.state.invalid}
108
+ info={this.props.info}
109
+ inlineLabel={this.props.inlineLabel}
110
+ labelHidden={this.props.labelHidden}
111
+ fullWidth={this.props.fullWidth}
112
+ htmlId={this.htmlId}
113
+ tabindex={this.props.tabindex}>
114
+ <Dropdown
115
+ inputId={this.htmlId}
116
+ ariaLabelledBy={this.htmlId + 'label'}
91
117
  value={valueInternal}
92
118
  options={optionsInternal}
93
119
  onChange={(e) => {
@@ -108,7 +134,6 @@ export class SelectWithTemplate<T> extends React.Component<IProps<T>, IState<T>>
108
134
  loading={loading}
109
135
  onFilterInputChange={(searchString) => {
110
136
  this.setState({loading: true});
111
-
112
137
  getItems(searchString).then((_options) => {
113
138
  this.setState({options: _options, loading: false});
114
139
  });
@@ -117,8 +142,8 @@ export class SelectWithTemplate<T> extends React.Component<IProps<T>, IState<T>>
117
142
  style={width === '100%' ? {display: 'flex', width: '100%'} : {}}
118
143
  ref={(componentRef) => {
119
144
  this.componentRef = componentRef;
120
- }}
121
- />
145
+ }}/>
146
+ </InputWrapper>
122
147
  );
123
148
  }
124
149
  }
@@ -1,30 +1,62 @@
1
1
  import * as React from 'react';
2
+ // import classNames from 'classnames';
3
+ import nextId from "react-id-generator";
4
+ import { InputWrapper } from './Form';
2
5
 
3
6
  interface IProps {
4
7
  value: string; // will output time as ISO8601 time string(e.g. 16:55) or an empty string if there's no value
5
8
  onChange(valueNext: string): void;
6
- required?: boolean; // displays a button to reset time input
7
9
  disabled?: boolean;
10
+ inlineLabel?: boolean;
11
+ required?: boolean;
12
+ fullWidth?: boolean;
13
+ invalid?: boolean;
14
+ labelHidden?: boolean;
15
+ tabindex?: number;
16
+ label?: string;
17
+ info?: string;
18
+ error?: string;
8
19
  }
9
20
 
10
- export class TimePicker extends React.PureComponent<IProps> {
21
+ interface IState {
22
+ invalid: boolean;
23
+ }
24
+
25
+ export class TimePicker extends React.PureComponent<IProps, IState> {
26
+ private htmlId = nextId();
27
+ constructor(props: IProps) {
28
+ super(props);
29
+ this.state = {
30
+ invalid: this.props.invalid ? this.props.invalid : false,
31
+ };
32
+ }
33
+
11
34
  render() {
12
35
  return (
13
- <div
14
- className="sd-input sd-input--no-label sd-input--no-margin"
15
- style={{display: 'inline-flex'}}
16
- >
36
+ <InputWrapper
37
+ label={this.props.label}
38
+ error={this.props.error}
39
+ required={this.props.required}
40
+ disabled={this.props.disabled}
41
+ invalid={this.state.invalid}
42
+ info={this.props.info}
43
+ inlineLabel={this.props.inlineLabel}
44
+ labelHidden={this.props.labelHidden}
45
+ fullWidth={this.props.fullWidth}
46
+ htmlId={this.htmlId}
47
+ tabindex={this.props.tabindex}>
17
48
  <input
18
- type="time"
19
- className="sd-input__input"
20
- value={this.props.value}
21
- required={this.props.required}
22
- disabled={this.props.disabled}
23
- onChange={(event) => {
24
- this.props.onChange(event.target.value);
25
- }}
26
- />
27
- </div>
49
+ id={this.htmlId}
50
+ aria-labelledby={this.htmlId + 'label'}
51
+ type="time"
52
+ className="sd-input__input"
53
+ value={this.props.value}
54
+ required={this.props.required}
55
+ disabled={this.props.disabled}
56
+ onChange={(event) => {
57
+ this.props.onChange(event.target.value);
58
+ }}/>
59
+ </InputWrapper>
28
60
  );
29
61
  }
30
62
  }