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.
- package/.eslintignore +1 -0
- package/app/styles/_drag-handle.scss +24 -0
- package/app/styles/_sd-tag-input.scss +3 -5
- package/app/styles/_tag-labels.scss +0 -2
- package/app/styles/app.scss +1 -0
- package/app/styles/form-elements/_checkbox.scss +3 -0
- package/app/styles/form-elements/_input-preview.scss +70 -0
- package/app/styles/form-elements/_inputs.scss +10 -14
- package/app/styles/primereact/_pr-tag-input.scss +1 -1
- package/app-typescript/components/DatePicker.tsx +101 -101
- package/app-typescript/components/DragHandle.tsx +13 -0
- package/app-typescript/components/DurationInput.tsx +76 -76
- package/app-typescript/components/Form/InputNew.tsx +1 -1
- package/app-typescript/components/Form/InputWrapper.tsx +34 -18
- package/app-typescript/components/Input.tsx +38 -62
- package/app-typescript/components/MultiSelect.tsx +49 -47
- package/app-typescript/components/Select.tsx +13 -22
- package/app-typescript/components/SelectPreview.tsx +100 -0
- package/app-typescript/components/SelectWithTemplate.tsx +2 -12
- package/app-typescript/components/TagInput.tsx +25 -24
- package/app-typescript/components/TimePicker.tsx +13 -16
- package/app-typescript/components/TreeSelect.tsx +180 -131
- package/app-typescript/index.ts +1 -0
- package/dist/examples.bundle.css +20 -0
- package/dist/examples.bundle.js +2485 -2198
- package/dist/react/Autocomplete.tsx +32 -31
- package/dist/react/DatePicker.tsx +56 -73
- package/dist/react/DragHandleDocs.tsx +26 -0
- package/dist/react/DurationInput.tsx +36 -47
- package/dist/react/Index.tsx +6 -1
- package/dist/react/Inputs.tsx +86 -248
- package/dist/react/MultiSelect.tsx +30 -23
- package/dist/react/Selects.tsx +12 -44
- package/dist/react/TagInputDocs.tsx +15 -21
- package/dist/react/TimePicker.tsx +25 -32
- package/dist/react/TreeSelect.tsx +97 -90
- package/dist/superdesk-ui.bundle.css +105 -18
- package/dist/superdesk-ui.bundle.js +2118 -1888
- package/dist/vendor.bundle.js +14 -14
- package/examples/pages/react/Autocomplete.tsx +32 -31
- package/examples/pages/react/DatePicker.tsx +56 -73
- package/examples/pages/react/DragHandleDocs.tsx +26 -0
- package/examples/pages/react/DurationInput.tsx +36 -47
- package/examples/pages/react/Index.tsx +6 -1
- package/examples/pages/react/Inputs.tsx +86 -248
- package/examples/pages/react/MultiSelect.tsx +30 -23
- package/examples/pages/react/Selects.tsx +12 -44
- package/examples/pages/react/TagInputDocs.tsx +15 -21
- package/examples/pages/react/TimePicker.tsx +25 -32
- package/examples/pages/react/TreeSelect.tsx +97 -90
- package/globals.d.ts +4 -0
- package/package.json +1 -1
- package/react/components/DatePicker.d.ts +2 -12
- package/react/components/DatePicker.js +14 -8
- package/react/components/DragHandle.d.ts +5 -0
- package/react/components/DragHandle.js +59 -0
- package/react/components/DurationInput.d.ts +2 -11
- package/react/components/DurationInput.js +14 -4
- package/react/components/Form/InputNew.d.ts +1 -1
- package/react/components/Form/InputWrapper.d.ts +11 -5
- package/react/components/Form/InputWrapper.js +6 -9
- package/react/components/Input.d.ts +3 -19
- package/react/components/Input.js +8 -21
- package/react/components/MultiSelect.d.ts +4 -13
- package/react/components/MultiSelect.js +6 -2
- package/react/components/Select.d.ts +3 -15
- package/react/components/Select.js +7 -8
- package/react/components/SelectPreview.d.ts +17 -0
- package/react/components/SelectPreview.js +109 -0
- package/react/components/SelectWithTemplate.d.ts +2 -11
- package/react/components/SelectWithTemplate.js +0 -1
- package/react/components/TagInput.d.ts +3 -12
- package/react/components/TagInput.js +6 -2
- package/react/components/TimePicker.d.ts +2 -11
- package/react/components/TimePicker.js +6 -2
- package/react/components/TreeSelect.d.ts +2 -11
- package/react/components/TreeSelect.js +49 -26
- package/react/index.d.ts +1 -0
- package/react/index.js +3 -1
- package/tsconfig.json +1 -1
package/.eslintignore
CHANGED
@@ -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
|
-
|
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
|
}
|
package/app/styles/app.scss
CHANGED
@@ -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
|
-
|
1174
|
-
}
|
1168
|
+
50% {
|
1169
|
+
opacity: 0;
|
1170
|
+
}
|
1175
1171
|
}
|
@@ -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
|
5
|
-
import {
|
6
|
-
|
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
|
-
|
151
|
-
|
152
|
-
|
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
|
-
|
204
|
-
|
205
|
-
|
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
|
-
|
208
|
-
|
209
|
-
|
210
|
-
|
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
|
-
|
228
|
-
|
229
|
-
|
230
|
-
|
231
|
-
|
232
|
-
|
233
|
-
|
234
|
-
|
235
|
-
|
236
|
-
|
237
|
-
|
238
|
-
|
239
|
-
|
240
|
-
|
241
|
-
|
242
|
-
|
243
|
-
|
244
|
-
|
245
|
-
|
246
|
-
|
247
|
-
|
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
|
+
}
|