superdesk-ui-framework 3.0.36 → 3.0.39

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 (80) hide show
  1. package/.eslintignore +1 -0
  2. package/app/styles/_drag-handle.scss +24 -0
  3. package/app/styles/_sd-tag-input.scss +3 -5
  4. package/app/styles/_tag-labels.scss +0 -2
  5. package/app/styles/app.scss +1 -0
  6. package/app/styles/form-elements/_checkbox.scss +3 -0
  7. package/app/styles/form-elements/_input-preview.scss +70 -0
  8. package/app/styles/form-elements/_inputs.scss +10 -14
  9. package/app/styles/primereact/_pr-tag-input.scss +1 -1
  10. package/app-typescript/components/DatePicker.tsx +101 -101
  11. package/app-typescript/components/DragHandle.tsx +13 -0
  12. package/app-typescript/components/DurationInput.tsx +76 -76
  13. package/app-typescript/components/Form/InputNew.tsx +1 -1
  14. package/app-typescript/components/Form/InputWrapper.tsx +34 -18
  15. package/app-typescript/components/Input.tsx +38 -62
  16. package/app-typescript/components/MultiSelect.tsx +49 -47
  17. package/app-typescript/components/Select.tsx +13 -22
  18. package/app-typescript/components/SelectPreview.tsx +100 -0
  19. package/app-typescript/components/SelectWithTemplate.tsx +2 -12
  20. package/app-typescript/components/TagInput.tsx +25 -24
  21. package/app-typescript/components/TimePicker.tsx +13 -16
  22. package/app-typescript/components/TreeSelect.tsx +180 -131
  23. package/app-typescript/index.ts +1 -0
  24. package/dist/examples.bundle.css +20 -0
  25. package/dist/examples.bundle.js +2485 -2198
  26. package/dist/react/Autocomplete.tsx +32 -31
  27. package/dist/react/DatePicker.tsx +56 -73
  28. package/dist/react/DragHandleDocs.tsx +26 -0
  29. package/dist/react/DurationInput.tsx +36 -47
  30. package/dist/react/Index.tsx +6 -1
  31. package/dist/react/Inputs.tsx +86 -248
  32. package/dist/react/MultiSelect.tsx +30 -23
  33. package/dist/react/Selects.tsx +12 -44
  34. package/dist/react/TagInputDocs.tsx +15 -21
  35. package/dist/react/TimePicker.tsx +25 -32
  36. package/dist/react/TreeSelect.tsx +97 -90
  37. package/dist/superdesk-ui.bundle.css +105 -18
  38. package/dist/superdesk-ui.bundle.js +2118 -1888
  39. package/dist/vendor.bundle.js +14 -14
  40. package/examples/pages/react/Autocomplete.tsx +32 -31
  41. package/examples/pages/react/DatePicker.tsx +56 -73
  42. package/examples/pages/react/DragHandleDocs.tsx +26 -0
  43. package/examples/pages/react/DurationInput.tsx +36 -47
  44. package/examples/pages/react/Index.tsx +6 -1
  45. package/examples/pages/react/Inputs.tsx +86 -248
  46. package/examples/pages/react/MultiSelect.tsx +30 -23
  47. package/examples/pages/react/Selects.tsx +12 -44
  48. package/examples/pages/react/TagInputDocs.tsx +15 -21
  49. package/examples/pages/react/TimePicker.tsx +25 -32
  50. package/examples/pages/react/TreeSelect.tsx +97 -90
  51. package/globals.d.ts +4 -0
  52. package/package.json +1 -1
  53. package/react/components/DatePicker.d.ts +2 -12
  54. package/react/components/DatePicker.js +14 -8
  55. package/react/components/DragHandle.d.ts +5 -0
  56. package/react/components/DragHandle.js +59 -0
  57. package/react/components/DurationInput.d.ts +2 -11
  58. package/react/components/DurationInput.js +14 -4
  59. package/react/components/Form/InputNew.d.ts +1 -1
  60. package/react/components/Form/InputWrapper.d.ts +11 -5
  61. package/react/components/Form/InputWrapper.js +6 -9
  62. package/react/components/Input.d.ts +3 -19
  63. package/react/components/Input.js +8 -21
  64. package/react/components/MultiSelect.d.ts +4 -13
  65. package/react/components/MultiSelect.js +6 -2
  66. package/react/components/Select.d.ts +3 -15
  67. package/react/components/Select.js +7 -8
  68. package/react/components/SelectPreview.d.ts +17 -0
  69. package/react/components/SelectPreview.js +109 -0
  70. package/react/components/SelectWithTemplate.d.ts +2 -11
  71. package/react/components/SelectWithTemplate.js +0 -1
  72. package/react/components/TagInput.d.ts +3 -12
  73. package/react/components/TagInput.js +6 -2
  74. package/react/components/TimePicker.d.ts +2 -11
  75. package/react/components/TimePicker.js +6 -2
  76. package/react/components/TreeSelect.d.ts +2 -11
  77. package/react/components/TreeSelect.js +49 -26
  78. package/react/index.d.ts +1 -0
  79. package/react/index.js +3 -1
  80. package/tsconfig.json +1 -1
package/.eslintignore CHANGED
@@ -1,3 +1,4 @@
1
1
  *.generated.js
2
2
  missing-translations-strings.js
3
3
  language-mapping-list.js
4
+ globals.d.ts
@@ -0,0 +1,24 @@
1
+ .drag-handle {
2
+ height: 30px;
3
+ width: 8px;
4
+ opacity: 0.85;
5
+ }
6
+
7
+ .drag-handle-wrapper {
8
+ padding: 6px;
9
+ display: inline-flex;
10
+ justify-content: center;
11
+ align-items: center;
12
+ background-color: var(--sd-colour-line--medium);
13
+ border-start-start-radius: 3px;
14
+ border-end-start-radius: 3px;
15
+ &:hover {
16
+ background-color: var(--sd-colour-line--strong);
17
+ cursor: grab;
18
+ }
19
+ &:active {
20
+ background-color: var(--sd-colour-interactive);
21
+ cursor: grabbing;
22
+ opacity: 1;
23
+ }
24
+ }
@@ -134,9 +134,6 @@ tags-input,
134
134
  }
135
135
  }
136
136
  }
137
- .tags-input__tag-item--multi-select {
138
- margin: 0 !important;
139
- }
140
137
  .tags-input__tag-item--readonly {
141
138
  cursor: default !important;
142
139
  }
@@ -222,10 +219,11 @@ tags-input,
222
219
  i {
223
220
  color: inherit;
224
221
  }
225
- &:hover {
222
+
223
+ &:not(.tags-input__add-button--disabled):hover {
226
224
  opacity: 1;
227
225
  }
228
- &:focus {
226
+ &:not(.tags-input__add-button--disabled):focus {
229
227
  opacity: 1;
230
228
  }
231
229
  &[disabled], [disabled]:hover, [disabled]:active {
@@ -43,8 +43,6 @@ $tag-label-lineheight: 100% !default;
43
43
  text-align: center;
44
44
  font-weight: 400;
45
45
  transition: background-color .2s ease-out, opacity .1s ease-out;
46
- margin: 0.2rem 0;
47
- margin-right: 0.3rem;
48
46
  height: $sd-base-increment * 3;
49
47
  color: var(--color-text);
50
48
  }
@@ -87,6 +87,7 @@
87
87
  @import 'form-elements/autocomplete';
88
88
  @import 'form-elements/select-grid';
89
89
  @import 'form-elements/input-wrap';
90
+ @import 'form-elements/input-preview';
90
91
 
91
92
  // Menus
92
93
  @import 'menus/sd-sidebar-menu';
@@ -416,6 +416,9 @@ $checkButtonBorderRadius: $border-radius__base--small;
416
416
  &.sd-check-button__group--compact {
417
417
  gap: $sd-base-increment * 0.5;
418
418
  }
419
+ &.sd-check-button__group--no-wrap {
420
+ flex-wrap: nowrap;
421
+ }
419
422
  }
420
423
 
421
424
  .sd-check-new__wrapper {
@@ -0,0 +1,70 @@
1
+ .tags-preview {
2
+ display: flex;
3
+ align-items: flex-start;
4
+ word-wrap: break-word;
5
+ min-height: $form-input-height;
6
+ padding: 0.4rem 0.4rem 0.3rem 0.4rem;
7
+ overflow: hidden;
8
+ background-color: transparent;
9
+ .tags-preview__tag-list {
10
+ display: flex;
11
+ justify-content: flex-start;
12
+ align-items: center;
13
+ flex-wrap: wrap;
14
+ gap: $sd-base-increment / 2;
15
+ margin: 0;
16
+ padding: 0;
17
+ list-style-type: none;
18
+ }
19
+ .tags-preview__tag-item {
20
+ @include tag-label;
21
+ color: currentColor;
22
+ background: $tag-label-BG-default;
23
+
24
+ &--single-select {
25
+ border-radius: 2px;
26
+ padding-inline-start: 0.714em;
27
+ padding-inline-end: 0.857em;
28
+ }
29
+
30
+ &--border {
31
+ border-left: solid;
32
+ border-left-width: 5px;
33
+ }
34
+ }
35
+ .tags-input__helper-box {
36
+ display: flex;
37
+ align-items: center;
38
+ }
39
+ }
40
+
41
+ .sd-input__duration-input-preview {
42
+ display: flex;
43
+ gap: 2px;
44
+ grid-row: 2/3;
45
+ grid-column: 2/4;
46
+ &:focus-within {
47
+ box-shadow: 0 1px 0 0 var(--sd-colour-interactive);
48
+ border-color: var(--sd-colour-interactive);
49
+ background-color: var(--sd-colour-interactive--alpha-20);
50
+ }
51
+ .duration-input-preview {
52
+ display: inline-block;
53
+ text-align: end;
54
+ color: var(--color-text);
55
+ width: 2.5ch;
56
+ height: 3.2rem;
57
+ font-size: 1.4rem;
58
+ line-height: 3.2rem;
59
+ }
60
+ .sd-input__suffix {
61
+ height: 3.2rem;
62
+ line-height: 3.2rem;
63
+ font-size: 1.4rem;
64
+ color: var(--color-text-light);
65
+ display: inline-block;
66
+ pointer-events: none;
67
+ margin-inline-end: 2px;
68
+ text-align: center;
69
+ }
70
+ }
@@ -514,6 +514,7 @@
514
514
 
515
515
  ///////////////// -------------------- NEW INPUTS --------------------- /////////////////
516
516
 
517
+
517
518
  .sd-input__input {
518
519
  @include Line-input-base;
519
520
  &--invalid {
@@ -634,9 +635,6 @@
634
635
  }
635
636
  }
636
637
 
637
-
638
- //----
639
-
640
638
  .sd-input {
641
639
  padding-top: 0;
642
640
  margin: 0;
@@ -1069,15 +1067,13 @@
1069
1067
  }
1070
1068
  }
1071
1069
  }
1072
-
1070
+ &--disabled * {
1071
+ cursor: not-allowed !important;
1072
+ }
1073
1073
  }
1074
1074
 
1075
- ///////////////// -------------------- Duration & Time-Date input --------------------- /////////////////
1076
-
1077
-
1078
-
1079
-
1080
1075
 
1076
+ ///////////////// -------------------- Duration & Time-Date input --------------------- /////////////////
1081
1077
 
1082
1078
 
1083
1079
  .sd-input__duration-input,
@@ -1101,11 +1097,11 @@
1101
1097
  appearance: none;
1102
1098
  border: 0;
1103
1099
  background-color: transparent;
1104
- height: 3.2rem;
1105
1100
  display: inline-block;
1106
- color: var(--color-text);
1107
1101
  text-align: end;
1102
+ color: var(--color-text);
1108
1103
  width: 2.5ch;
1104
+ height: 3.2rem;
1109
1105
  font-size: 1.4rem;
1110
1106
  padding: 0 !important;
1111
1107
  line-height: 3.2rem;
@@ -1169,7 +1165,7 @@
1169
1165
  }
1170
1166
 
1171
1167
  @keyframes blinker {
1172
- 50% {
1173
- opacity: 0;
1174
- }
1168
+ 50% {
1169
+ opacity: 0;
1170
+ }
1175
1171
  }
@@ -41,7 +41,7 @@
41
41
  justify-content: flex-start;
42
42
  align-items: center;
43
43
  flex-wrap: wrap;
44
- gap: $sd-base-increment / 8;
44
+ gap: $sd-base-increment / 2;
45
45
  width: 100%;
46
46
  transition: all 0.3s cubic-bezier(0.55, 0, 0.55, 0.2);
47
47
  border-radius: 2px 2px 0 0;
@@ -1,15 +1,16 @@
1
1
  import * as React from 'react';
2
2
  import addDays from 'date-fns/addDays';
3
3
  import format from 'date-fns/format';
4
- import {Calendar, LocaleSettings, CalendarProps} from '@superdesk/primereact/calendar';
5
- import {throttle} from 'lodash';
6
- // import classNames from 'classnames';
4
+ import moment from 'moment';
5
+ import { Calendar, LocaleSettings, CalendarProps } from '@superdesk/primereact/calendar';
6
+ import { throttle } from 'lodash';
7
7
  import nextId from "react-id-generator";
8
8
  import { InputWrapper } from './Form';
9
+ import { IInputWrapper } from './Form/InputWrapper';
9
10
 
10
11
  export type DatePickerLocaleSettings = Omit<LocaleSettings, 'today' | 'clear'>;
11
12
 
12
- interface IDatePickerBase {
13
+ interface IDatePickerBase extends IInputWrapper {
13
14
  dateFormat: string; // a combination of YYYY, MM, and DD with a custom separator e.g. 'MM/DD/YYYY'
14
15
 
15
16
  // shortcuts can be used to jump to a date relative to today
@@ -31,18 +32,6 @@ interface IDatePickerBase {
31
32
  }}
32
33
  */
33
34
  locale?: DatePickerLocaleSettings;
34
-
35
- // label props
36
- disabled?: boolean;
37
- inlineLabel?: boolean;
38
- required?: boolean;
39
- fullWidth?: boolean;
40
- invalid?: boolean;
41
- labelHidden?: boolean;
42
- tabindex?: number;
43
- label?: string;
44
- info?: string;
45
- error?: string;
46
35
  }
47
36
 
48
37
  interface IDatePicker extends IDatePickerBase {
@@ -65,9 +54,7 @@ interface IState {
65
54
  value: CalendarProps['value'];
66
55
 
67
56
  // valid means it can be parsed
68
- // if a value is invalid on blur, it will be set to an empty string and `props.onChange` called with `null`
69
57
  valid: boolean;
70
- invalid: boolean;
71
58
  }
72
59
 
73
60
  // tries to parse primereact/calendar value format to IDatePicker['value']
@@ -98,7 +85,6 @@ export class DatePicker extends React.PureComponent<IDatePicker, IState> {
98
85
  this.state = {
99
86
  value: parseToPrimeReactCalendarFormat(this.props.value),
100
87
  valid: true,
101
- invalid: this.props.invalid ?? false,
102
88
  };
103
89
 
104
90
  this.hidePopupOnScroll = throttle(() => {
@@ -145,71 +131,85 @@ export class DatePicker extends React.PureComponent<IDatePicker, IState> {
145
131
  };
146
132
  }
147
133
 
134
+ if (this.props.preview) {
135
+ return (
136
+ // We have to do type assertion here because we wrap primereact's component using
137
+ // a narrower interface i.e. primereact supports an array of dates or a single date,
138
+ // and our wrapped component will only ever use a single date.
139
+ <div>
140
+ <span>{moment(this.state.value as Date).format(this.props.dateFormat)}</span>
141
+ </div>
142
+ );
143
+ }
144
+
148
145
  return (
149
146
  <InputWrapper
150
- label={this.props.label}
151
- error={this.props.error}
152
- required={this.props.required}
153
- disabled={this.props.disabled}
154
- invalid={this.state.invalid}
155
- info={this.props.info}
156
- inlineLabel={this.props.inlineLabel}
157
- labelHidden={this.props.labelHidden}
158
- fullWidth={this.props.fullWidth}
159
- htmlId={this.htmlId}
160
- tabindex={this.props.tabindex}>
161
- <Calendar
162
- inputId={this.htmlId}
163
- ariaLabelledBy={this.htmlId + 'label'}
164
- ref={(ref) => {
165
- this.instance = ref as unknown as IPrivatePrimeReactCalendarApi;
166
- }}
167
- value={this.state.value === null ? undefined : this.state.value}
168
- onChange={(event) => {
169
- const result = parseFromPrimeReactCalendarFormat(event.value);
170
-
171
- if (result !== 'failed-to-parse') {
172
- this.setState({value: event.value, valid: true});
173
- this.props.onChange(result);
174
- } else {
175
- // updating internal state so a user can continue typing and enter a valid value
176
- this.setState({value: event.value, valid: false});
177
- }
178
- }}
179
- locale={locale}
180
- dateFormat={this.props.dateFormat.replace('YYYY', 'yy').replace('MM', 'mm').replace('DD', 'dd')}
181
- showIcon={true}
182
- icon="icon-calendar"
183
- headerTemplate={() => this.props.headerButtonBar == null ? null : (
184
- <div
185
- className="datepicker-header-toolbar">
186
- {this.props.headerButtonBar.map(({label, days}, i) => (
187
- <button
188
- key={i}
189
- className="btn btn--small"
190
- onClick={() => {
191
- this.props.onChange(addDays(new Date(), days));
192
- if (this.instance != null && typeof this.instance.hideOverlay === 'function') {
193
- this.instance.hideOverlay();
194
- }
195
- }}>
196
- {label}
197
- </button>
198
- ))}
199
- </div>
200
- )}
201
- appendTo={document.body} // making it work inside `overflow:hidden`
147
+ label={this.props.label}
148
+ error={this.props.error}
149
+ required={this.props.required}
202
150
  disabled={this.props.disabled}
203
- onBlur={(event) => {
204
- // @ts-ignore: Object is possibly 'null'.
205
- if (!event?.target.value) {
151
+ info={this.props.info}
152
+ inlineLabel={this.props.inlineLabel}
153
+ labelHidden={this.props.labelHidden}
154
+ htmlId={this.htmlId}
155
+ tabindex={this.props.tabindex}
156
+ >
157
+ <Calendar
158
+ inputId={this.htmlId}
159
+ ariaLabelledBy={this.htmlId + 'label'}
160
+ ref={(ref) => {
161
+ this.instance = ref as unknown as IPrivatePrimeReactCalendarApi;
162
+ }}
163
+ value={this.state.value === null ? undefined : this.state.value}
164
+ onChange={(event) => {
165
+ const result = parseFromPrimeReactCalendarFormat(event.value);
166
+
167
+ if (result !== 'failed-to-parse') {
168
+ this.setState({value: event.value, valid: true});
169
+ this.props.onChange(result);
170
+ } else {
171
+ // updating internal state so a user can continue typing and enter a valid value
172
+ this.setState({value: event.value, valid: false});
173
+ }
174
+ }}
175
+ locale={locale}
176
+ dateFormat={this.props.dateFormat.replace('YYYY', 'yy').replace('MM', 'mm').replace('DD', 'dd')}
177
+ showIcon={true}
178
+ icon="icon-calendar"
179
+ headerTemplate={() => this.props.headerButtonBar == null ? null : (
180
+ <div className="datepicker-header-toolbar">
181
+ {this.props.headerButtonBar.map(({label, days}, i) => (
182
+ <button
183
+ key={i}
184
+ className="btn btn--small"
185
+ onClick={() => {
186
+ this.props.onChange(addDays(new Date(), days));
187
+ if (
188
+ this.instance != null
189
+ && typeof this.instance.hideOverlay === 'function'
190
+ ) {
191
+ this.instance.hideOverlay();
192
+ }
193
+ }}
194
+ >
195
+ {label}
196
+ </button>
197
+ ))}
198
+ </div>
199
+ )}
200
+ appendTo={document.body} // making it work inside `overflow:hidden`
201
+ disabled={this.props.disabled}
202
+ onBlur={(event) => {
206
203
  // @ts-ignore: Object is possibly 'null'.
207
- this.setState({valid: true, value: null});
208
- } else {
209
- // restoring internal state to current props value
210
- this.setState({valid: true, value: parseToPrimeReactCalendarFormat(this.props.value)});
211
- }
212
- }} />
204
+ if (!event?.target.value) {
205
+ // @ts-ignore: Object is possibly 'null'.
206
+ this.setState({valid: true, value: null});
207
+ } else {
208
+ // restoring internal state to current props value
209
+ this.setState({valid: true, value: parseToPrimeReactCalendarFormat(this.props.value)});
210
+ }
211
+ }}
212
+ />
213
213
  </InputWrapper>
214
214
  );
215
215
  }
@@ -224,27 +224,27 @@ export class DatePickerISO extends React.PureComponent<IDatePickerISO> {
224
224
  render() {
225
225
  return (
226
226
  <DatePicker
227
- value={new Date(this.props.value)}
228
- onChange={(value) => {
229
- if (value === null) {
230
- this.props.onChange('');
231
- } else {
232
- this.props.onChange(format(value, 'yyyy-MM-dd'));
233
- }
234
- }}
235
- disabled={this.props.disabled}
236
- headerButtonBar={this.props.headerButtonBar}
237
- dateFormat={this.props.dateFormat}
238
- locale={this.props.locale}
239
- inlineLabel={this.props.inlineLabel}
240
- required={this.props.required}
241
- fullWidth={this.props.fullWidth}
242
- invalid={this.props.invalid}
243
- labelHidden={this.props.labelHidden}
244
- tabindex={this.props.tabindex}
245
- label={this.props.label}
246
- info={this.props.info}
247
- error={this.props.error}
227
+ value={new Date(this.props.value)}
228
+ onChange={(value) => {
229
+ if (value === null) {
230
+ this.props.onChange('');
231
+ } else {
232
+ this.props.onChange(format(value, 'yyyy-MM-dd'));
233
+ }
234
+ }}
235
+ disabled={this.props.disabled}
236
+ preview={this.props.preview}
237
+ headerButtonBar={this.props.headerButtonBar}
238
+ dateFormat={this.props.dateFormat}
239
+ locale={this.props.locale}
240
+ inlineLabel={this.props.inlineLabel}
241
+ required={this.props.required}
242
+ fullWidth={this.props.fullWidth}
243
+ labelHidden={this.props.labelHidden}
244
+ tabindex={this.props.tabindex}
245
+ label={this.props.label}
246
+ info={this.props.info}
247
+ error={this.props.error}
248
248
  />
249
249
  );
250
250
  }
@@ -0,0 +1,13 @@
1
+ import * as React from 'react';
2
+ import '../../app/styles/_drag-handle.scss';
3
+ import dragHandleImg from '../../app/img/dots.svg';
4
+
5
+ export class DragHandle extends React.PureComponent {
6
+ render() {
7
+ return (
8
+ <div className="drag-handle-wrapper">
9
+ <img src={dragHandleImg} className="drag-handle" />
10
+ </div>
11
+ );
12
+ }
13
+ }