superdesk-ui-framework 4.0.67 → 4.0.68

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.
@@ -242,9 +242,17 @@ $new-button-active-shadow-hollow: inset 0 0 0 1px;
242
242
  }
243
243
 
244
244
  &.btn--icon-only {
245
+ padding-inline: var(--space--1);
245
246
  [class^="icon-"], [class*=" icon-"] {
246
247
  margin: 0;
247
248
  }
249
+ &.btn--small {
250
+ padding-inline: var(--space--0-5);
251
+ }
252
+
253
+ &.btn--large {
254
+ padding-inline: var(--space--1-5);
255
+ }
248
256
 
249
257
  &.btn--icon-only-circle {
250
258
  border-radius: $border-radius__base--full;
@@ -1,9 +1,93 @@
1
- .time-unit-highlight {
2
- background-color: var(--sd-colour-interactive);
3
- color: $white;
1
+ .time-picker__input {
2
+ input[type="time"] {
3
+ -webkit-appearance: none;
4
+ -moz-appearance: textfield;
5
+ appearance: textfield;
6
+ &::-webkit-calendar-picker-indicator {
7
+ display: none;
8
+ }
9
+ }
10
+ position: relative;
11
+ &:has(.time-picker__icon-wrapper) {
12
+ .sd-input__input:not(.p-calendar) {
13
+ padding-inline-end: var(--space--4);
14
+ }
15
+ }
16
+ .time-picker__icon-wrapper {
17
+ position: relative;
18
+ height: 2.4rem;
19
+ width: 2.4rem;
20
+ position: absolute;
21
+ inset-block-start: var(--space--0-5);
22
+ inset-inline-end: var(--space--0-5);
23
+ display: flex;
24
+ align-items: center;
25
+ justify-content: center;
26
+ z-index: 1;
27
+ pointer-events: none;
28
+
29
+ .clear-time-picker {
30
+ position: absolute;
31
+ inset-block-start: 0;
32
+ inset-inline-end: 0;
33
+ transition: opacity 0.2s ease;
34
+ z-index: 2;
35
+ opacity: 0;
36
+ }
37
+ }
38
+ &:has(.sd-input__input--has-value) {
39
+ .icon-time {
40
+ opacity: 1;
41
+ transition: opacity 0.2s ease;
42
+ }
43
+ .time-picker__icon-wrapper {
44
+ pointer-events: all;
45
+ }
46
+ &:hover {
47
+ .icon-time {
48
+ opacity: 0;
49
+ }
50
+ .clear-time-picker {
51
+ opacity: 1;
52
+ }
53
+ }
54
+ &:focus-within {
55
+ .icon-time {
56
+ opacity: 0;
57
+ }
58
+ .clear-time-picker {
59
+ opacity: 1;
60
+ }
61
+ }
62
+ }
63
+ }
64
+ .time-picker--date-time { // only for the DateTimePicker component. Disable the clearing of the time input only.
65
+ .time-picker__input,
66
+ .time-picker__input:hover,
67
+ .time-picker__input:focus-within {
68
+ .time-picker__icon-wrapper {
69
+ pointer-events: none;
70
+ }
71
+ .clear-time-picker {
72
+ display: none;
73
+ }
74
+ .icon-time, {
75
+ opacity: 1;
76
+ }
77
+ }
4
78
  }
5
79
 
80
+
6
81
  .time-unit {
82
+ display: flex;
83
+ justify-content: center;
84
+ width: 32px;
85
+ height: 32px;
86
+ border-radius: var(--b-radius--x-small);
87
+ font-weight: normal;
88
+ margin-inline-start: var(--gap--x-small);
89
+ margin-inline-end: var(--gap--x-small);
90
+ transition: var(--transition__menu-item);
7
91
  transition: all ease 0.2s;
8
92
 
9
93
  &:hover {
@@ -14,15 +98,16 @@
14
98
 
15
99
  &:active {
16
100
  background-color: var(--sd-colour-interactive--alpha-20);
101
+
17
102
  }
18
103
 
19
- display: flex;
20
- justify-content: center;
21
- width: 32px;
22
- height: 32px;
23
- border-radius: var(--b-radius--x-small);
24
- font-weight: normal;
25
- margin-inline-start: var(--gap--x-small);
26
- margin-inline-end: var(--gap--x-small);
27
- transition: var(--transition__menu-item);
104
+ &:focus-visible {
105
+ outline: 2px solid var(--sd-colour-interactive--alpha-40);
106
+ }
107
+
108
+ &.time-unit-highlight,
109
+ &.time-unit-highlight:hover {
110
+ background-color: var(--sd-colour-interactive);
111
+ color: var(--color-text-ondark);
112
+ }
28
113
  }
@@ -124,7 +124,7 @@
124
124
  &.form-label--required {
125
125
  &::after {
126
126
  margin-inline-start: 0.2rem;
127
- color: #e41b21;
127
+ color: var(--color-warning-default);
128
128
  content: "*";
129
129
  vertical-align: top;
130
130
  font-size: 1.2rem;
@@ -762,7 +762,7 @@
762
762
  }
763
763
 
764
764
  .sd-input__input-container:has(input[type="time"]) {
765
- min-width: 110px;
765
+ min-width: min-content;
766
766
  }
767
767
 
768
768
  textarea {
@@ -783,23 +783,24 @@
783
783
  }
784
784
  }
785
785
  }
786
+ input[type="time"] {
787
+ &.sd-input__input {
788
+ -webkit-appearance: none;
789
+ -moz-appearance: textfield;
790
+ appearance: textfield;
791
+ &::-webkit-calendar-picker-indicator {
792
+ display: none;
793
+ }
794
+ }
795
+ }
796
+
797
+
798
+
799
+
786
800
 
787
801
  .sd-input__select {
788
- // display: block;
789
- // position: relative;
790
- // @include Line-input-base;
791
- // padding-inline-end: 2rem;
792
802
  grid-row: 2/3;
793
803
  grid-column: 2/4;
794
- // min-width: 5rem;
795
- // cursor: pointer;
796
- // option {
797
- // color:inherit;
798
- // font-size: 1.4rem;
799
- // line-height: 2rem;
800
- // background-color: var(--color-dropdown-menu-Bg);
801
- // color: var(--color-dropdown-menu-text);
802
- // }
803
804
  }
804
805
 
805
806
  &.sd-input--is-select {
@@ -872,7 +873,6 @@
872
873
  }
873
874
  }
874
875
 
875
-
876
876
  .sd-input__message-box {
877
877
  grid-row: 3/4;
878
878
  grid-column: 2/3;
@@ -887,25 +887,12 @@
887
887
  .sd-input__hint,
888
888
  .sd-input__message,
889
889
  .sd-input__char-count {
890
- // font-size: 1.2rem;
891
- // line-height: 1.4rem;
892
- // transition: all 0.3s cubic-bezier(0.55, 0, 0.55, 0.2);
893
- // color: var(--color-text-light);
894
- // font-weight: 300;
895
890
  margin: 0.5rem 0;
896
- // letter-spacing: 0.03em;
897
- // display: block;
898
891
  }
899
892
 
900
893
  .sd-input__char-count {
901
- // font-size: 1.1rem;
902
- // font-weight: 400;
903
- // font-style: italic;
904
894
  grid-row: 3/4;
905
895
  grid-column: 3/4;
906
- // &--error {
907
- // color: $red;
908
- // }
909
896
  }
910
897
 
911
898
  .sd-input__label {
@@ -109,6 +109,13 @@
109
109
  }
110
110
  }
111
111
  }
112
+ .p-datepicker table td > span {
113
+ &:not(.p-disabled) {
114
+ &:focus-visible {
115
+ outline: 2px solid var(--sd-colour-interactive--alpha-40);
116
+ }
117
+ }
118
+ }
112
119
 
113
120
  // styles for a day box
114
121
  .p-datepicker table td > span {
@@ -181,6 +188,9 @@
181
188
  background-color: var(--color-input-bg);
182
189
  }
183
190
  }
191
+ &.sd-input__input {
192
+ padding-inline: 0;
193
+ }
184
194
  }
185
195
 
186
196
  .p-calendar-w-btn {
@@ -238,6 +238,7 @@ export class DatePicker extends React.PureComponent<IDatePicker, IState> {
238
238
  }
239
239
  }}
240
240
  locale={locale}
241
+ placeholder={this.props.dateFormat.replace('YYYY', 'yyyy').replace('MM', 'mm').replace('DD', 'dd')}
241
242
  dateFormat={this.props.dateFormat.replace('YYYY', 'yy').replace('MM', 'mm').replace('DD', 'dd')}
242
243
  showIcon={true}
243
244
  icon="icon-calendar"
@@ -3,12 +3,12 @@ import {DatePicker} from '../components/DatePicker';
3
3
  import {Spacer} from '@sourcefabric/common';
4
4
  import {defaultTo} from 'lodash';
5
5
  import {TimePicker} from './TimePicker';
6
- import {IconButton} from './IconButton';
7
6
  import {InputWrapper} from './Form';
8
7
  import {IInputWrapper} from './Form/InputWrapper';
9
8
  import nextId from 'react-id-generator';
10
9
  import {format} from 'date-fns';
11
10
  import {assertNever} from '../helpers';
11
+ import {Button} from './Button';
12
12
 
13
13
  interface IPropsValueDate extends IInputWrapper {
14
14
  valueType: 'date';
@@ -157,7 +157,7 @@ export class DateTimePicker extends React.PureComponent<IProps> {
157
157
  data-test-id={this.props['data-test-id']}
158
158
  ref={this.props.ref}
159
159
  >
160
- <Spacer h gap="8" alignItems="end" noWrap>
160
+ <Spacer h gap="8" alignItems="center" noWrap>
161
161
  <div style={{flexGrow: 1}}>
162
162
  <DatePicker
163
163
  disabled={this.props.disabled}
@@ -173,7 +173,8 @@ export class DateTimePicker extends React.PureComponent<IProps> {
173
173
  data-test-id="date-input"
174
174
  />
175
175
  </div>
176
- <div style={{flexGrow: 1}}>
176
+ <div style={{flexGrow: 0, color: 'var(--color-text-muted)'}}>@</div>
177
+ <div className="time-picker--date-time" style={{flexGrow: 1}}>
177
178
  <TimePicker
178
179
  disabled={this.props.disabled || (timeRequiresDate && dateValue == null)}
179
180
  preview={this.props.preview}
@@ -190,11 +191,15 @@ export class DateTimePicker extends React.PureComponent<IProps> {
190
191
  />
191
192
  </div>
192
193
  {this.props.preview !== true && (
193
- <IconButton
194
- disabled={this.props.disabled}
194
+ <Button
195
195
  icon="remove-sign"
196
+ text="Clear"
197
+ tooltip="Clear"
196
198
  onClick={this.handleClear}
197
- ariaValue="Clear"
199
+ type="default"
200
+ style="hollow"
201
+ iconOnly={true}
202
+ disabled={this.props.disabled}
198
203
  />
199
204
  )}
200
205
  </Spacer>
@@ -1,13 +1,16 @@
1
1
  import * as React from 'react';
2
2
  import nextId from 'react-id-generator';
3
+ import classNames from 'classnames';
3
4
  import {InputWrapper} from './Form';
4
5
  import {IInputWrapper} from './Form/InputWrapper';
5
6
  import {TimePickerPopover} from './TimePickerPopover';
6
7
  import {PopupPositioner} from './ShowPopup';
8
+ import {Icon} from './Icon';
9
+ import {IconButton} from './IconButton';
7
10
 
8
11
  interface IProps extends IInputWrapper {
9
12
  value: string | null; // ISO8601 time string(e.g. 16:55) or null if there's no value
10
- onChange(valueNext: string): void;
13
+ onChange(valueNext: string | null): void;
11
14
  allowSeconds?: boolean;
12
15
  headerTemplate?: React.ReactNode;
13
16
  footerTemplate?: React.ReactNode;
@@ -52,6 +55,7 @@ export class TimePicker extends React.PureComponent<IProps, IState> {
52
55
  labelHidden={this.props.labelHidden}
53
56
  htmlId={this.htmlId}
54
57
  tabindex={this.props.tabindex}
58
+ inputWrapper={this.props.inputWrapper}
55
59
  >
56
60
  {this.state.popupOpen && (
57
61
  <PopupPositioner
@@ -78,32 +82,62 @@ export class TimePicker extends React.PureComponent<IProps, IState> {
78
82
  />
79
83
  </PopupPositioner>
80
84
  )}
81
- <input
82
- style={{
83
- cursor: 'pointer',
84
- }}
85
- ref={this.timeInputRef}
86
- value={this.props.value ?? ''}
87
- type="time"
88
- onClick={(e) => {
89
- // don't show default popup
90
- e.preventDefault();
85
+ <div className="time-picker__input">
86
+ <input
87
+ style={{
88
+ cursor: 'pointer',
89
+ }}
90
+ ref={this.timeInputRef}
91
+ value={this.props.value ?? ''}
92
+ type="time"
93
+ onClick={(e) => {
94
+ // don't show default popup
95
+ e.preventDefault();
91
96
 
92
- this.setState({
93
- popupOpen: true,
94
- });
95
- }}
96
- className="sd-input__input"
97
- id={this.htmlId}
98
- aria-labelledby={this.htmlId + 'label'}
99
- step={this.props.allowSeconds ? 1 : undefined}
100
- required={this.props.required}
101
- disabled={this.props.disabled}
102
- onChange={(event) => {
103
- this.props.onChange(event.target.value);
104
- }}
105
- data-test-id={this.props['data-test-id']}
106
- />
97
+ this.setState({
98
+ popupOpen: true,
99
+ });
100
+ }}
101
+ onKeyDown={(event) => {
102
+ // don't show default popup
103
+ event.preventDefault();
104
+
105
+ if (event.key === ' ') {
106
+ this.setState({
107
+ popupOpen: !this.state.popupOpen,
108
+ });
109
+ } else if ((event.key === 'Enter' || event.key === 'Escape') && this.state.popupOpen) {
110
+ this.setState({
111
+ popupOpen: false,
112
+ });
113
+ }
114
+ }}
115
+ className={classNames('sd-input__input', {
116
+ 'sd-input__input--has-value': this.props.value != null,
117
+ })}
118
+ id={this.htmlId}
119
+ aria-labelledby={this.htmlId + 'label'}
120
+ step={this.props.allowSeconds ? 1 : undefined}
121
+ required={this.props.required}
122
+ disabled={this.props.disabled}
123
+ onChange={(event) => {
124
+ this.props.onChange(event.target.value);
125
+ }}
126
+ data-test-id={this.props['data-test-id']}
127
+ />
128
+ <div className="time-picker__icon-wrapper">
129
+ <Icon name="time" />
130
+ <div className="clear-time-picker">
131
+ <IconButton
132
+ icon="remove-sign"
133
+ size="small"
134
+ ariaValue="Clear"
135
+ toolTipFlow="left"
136
+ onClick={() => this.props.onChange(null)}
137
+ />
138
+ </div>
139
+ </div>
140
+ </div>
107
141
  </InputWrapper>
108
142
  );
109
143
  }
@@ -30,7 +30,7 @@ class TimeValueHolder extends React.PureComponent<IPropsTimeValueHolder> {
30
30
  }
31
31
 
32
32
  public scrollToValue() {
33
- this.spanEl.current?.scrollIntoView();
33
+ this.spanEl.current?.scrollIntoView({block: 'start', behavior: 'smooth'});
34
34
  }
35
35
 
36
36
  render() {
@@ -133,27 +133,45 @@ export class TimePickerPopover extends React.PureComponent<IProps> {
133
133
  overflowY: 'auto',
134
134
  scrollbarWidth: 'none',
135
135
  marginTop: 'var(--gap-1)',
136
+ scrollBehavior: 'smooth',
136
137
  };
137
138
 
138
139
  return (
139
- <div className="sd-shadow--z2 radius-md" onBlur={this.props.closePopup}>
140
+ <div
141
+ className="sd-shadow--z2 radius-md"
142
+ onBlur={this.props.closePopup}
143
+ onKeyDown={(event) => {
144
+ if (event.key === 'Enter' || event.key === 'Escape') {
145
+ event.preventDefault();
146
+ this.props.closePopup();
147
+ }
148
+ }}
149
+ tabIndex={0}
150
+ >
140
151
  <Spacer
141
152
  v
142
153
  gap="0"
143
154
  style={{
144
- width: 200,
145
- padding: 'var(--gap-1)',
146
- backgroundColor: 'var(--color-bg-00)',
155
+ minWidth: 200,
156
+ maxWidth: 'max-content',
157
+ backgroundColor: 'var(--color-dropdown-menu-Bg)',
147
158
  borderRadius: 'var(--b-radius--small)',
148
159
  }}
149
160
  >
150
161
  {this.props.headerTemplate && (
151
- <>
162
+ <div className="px-1-5 py-1" style={{borderBottom: '1px solid var(--color-line-x-light)'}}>
152
163
  {this.props.headerTemplate}
153
- <ContentDivider border type="solid" orientation="horizontal" margin="none" />
154
- </>
164
+ </div>
155
165
  )}
156
- <Spacer h gap="4" noWrap justifyContent="center" alignItems="start">
166
+
167
+ <Spacer
168
+ h
169
+ gap="4"
170
+ noWrap
171
+ justifyContent="center"
172
+ alignItems="start"
173
+ style={{paddingInline: 'var(--gap-1)'}}
174
+ >
157
175
  <Spacer v gap="4" style={styleForColumnOfUnit} alignItems="center" noWrap>
158
176
  {getOptionsForTimeUnit('hours', this.is12HourFormat).map((hour) => {
159
177
  const isActiveHour =
@@ -265,10 +283,9 @@ export class TimePickerPopover extends React.PureComponent<IProps> {
265
283
  )}
266
284
  </Spacer>
267
285
  {this.props.footerTemplate && (
268
- <>
269
- <ContentDivider border type="solid" orientation="horizontal" margin="none" />
286
+ <div className="px-1-5 py-1" style={{borderTop: '1px solid var(--color-line-x-light)'}}>
270
287
  {this.props.footerTemplate}
271
- </>
288
+ </div>
272
289
  )}
273
290
  </Spacer>
274
291
  </div>
@@ -15,7 +15,7 @@ class DatePickerExample extends React.PureComponent<{}, {date: Date | null}> {
15
15
  return (
16
16
  <DatePicker
17
17
  value={this.state.date}
18
- dateFormat="YYYY-MM-DD"
18
+ dateFormat="DD.MM.YYYY"
19
19
  onChange={(date) => {
20
20
  this.setState({date});
21
21
  }}
@@ -15,13 +15,11 @@ class DateTimePickerExample extends React.PureComponent<{}, {dateTime: Date | nu
15
15
  return (
16
16
  <DateTimePicker
17
17
  label="Planning date"
18
- labelHidden
19
18
  inlineLabel
20
19
  fullWidth
21
20
  valueType="date"
22
21
  value={this.state.dateTime}
23
22
  dateFormat="YYYY-MM-DD"
24
- fullWidth
25
23
  onChange={(val) => {
26
24
  const parsedVal = val != null ? new Date(val) : null;
27
25
 
@@ -3,10 +3,22 @@ import * as Markup from '../../js/react';
3
3
  import {PropsList, Prop} from '../../../app-typescript';
4
4
  import {TimePicker} from '../../../app-typescript/components/TimePicker';
5
5
  import {TimePickerV2} from '../../../app-typescript/components/TimePickerV2';
6
+ import {ButtonGroup} from '../../../app-typescript/components/ButtonGroup';
7
+ import {Button} from '../../../app-typescript/components/Button';
6
8
 
7
9
  let minutes = Array.from(Array(60).keys());
8
10
  let changedMinutes = minutes.filter((num) => num % 15 !== 0);
9
11
 
12
+ const inputWrapper: React.ComponentProps<typeof TimePicker>['inputWrapper'] = {
13
+ kind: 'custom',
14
+ component: ({input}) => (
15
+ <div>
16
+ <div style={{border: '1px solid red'}}>custom label</div>
17
+ <div>{input}</div>
18
+ </div>
19
+ ),
20
+ };
21
+
10
22
  class TimePickerExample extends React.PureComponent<{}, {time: string | null}> {
11
23
  constructor(props) {
12
24
  super(props);
@@ -19,6 +31,15 @@ class TimePickerExample extends React.PureComponent<{}, {time: string | null}> {
19
31
  render() {
20
32
  return (
21
33
  <TimePicker
34
+ headerTemplate={
35
+ <ButtonGroup spaces="compact" align="center">
36
+ <Button size="small" text="In 30 min" style="hollow" onClick={() => false} />
37
+ <Button size="small" text="In 1 hr" style="hollow" onClick={() => false} />
38
+ <Button size="small" text="In 2 hr" style="hollow" onClick={() => false} />
39
+ <Button size="small" text="In 5 hr" style="hollow" onClick={() => false} />
40
+ </ButtonGroup>
41
+ }
42
+ footerTemplate={<div>Footer</div>}
22
43
  value={this.state.time}
23
44
  onChange={(time) => {
24
45
  this.setState({time});
@@ -26,6 +47,7 @@ class TimePickerExample extends React.PureComponent<{}, {time: string | null}> {
26
47
  allowSeconds
27
48
  label="This is Label"
28
49
  info="This is info"
50
+ inputWrapper={inputWrapper}
29
51
  />
30
52
  );
31
53
  }