superdesk-ui-framework 3.1.9 → 3.1.13
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/app/styles/_helpers.scss +926 -776
- package/app/styles/_master-desk.scss +2 -2
- package/app/styles/_toggle-box.scss +45 -28
- package/app/styles/components/_sd-collapse-box.scss +113 -0
- package/app/styles/components/_subnav.scss +0 -1
- package/app/styles/design-tokens/_design-tokens-general.scss +19 -5
- package/app/styles/design-tokens/_new-colors.scss +11 -1
- package/app/styles/form-elements/_inputs.scss +14 -0
- package/app/styles/grids/_grid-layout.scss +3 -0
- package/app-typescript/components/DatePicker.tsx +6 -0
- package/app-typescript/components/Layouts/LayoutContainer.tsx +7 -1
- package/app-typescript/components/Layouts/PageLayout.tsx +2 -1
- package/app-typescript/components/TimePickerV2.tsx +222 -0
- package/app-typescript/components/ToggleBox/CustomHeaderToggleBox.tsx +61 -0
- package/app-typescript/components/{Togglebox.tsx → ToggleBox/SimpleToggleBox.tsx} +13 -34
- package/app-typescript/components/ToggleBox/index.tsx +43 -0
- package/app-typescript/components/TreeMenu.tsx +12 -7
- package/app-typescript/components/TreeSelect/TreeSelect.tsx +13 -12
- package/app-typescript/components/TreeSelect/TreeSelectItem.tsx +11 -1
- package/app-typescript/index.ts +2 -1
- package/dist/components/Alerts.tsx +1 -1
- package/dist/components/ContentDivider.tsx +1 -1
- package/dist/components/DragHandleDocs.tsx +2 -2
- package/dist/components/Index.tsx +105 -50
- package/dist/components/Panel.tsx +13 -13
- package/dist/components/Tags.tsx +2 -2
- package/dist/components/TimePicker.tsx +43 -1
- package/dist/components/Togglebox.tsx +171 -17
- package/dist/components/TreeMenu.tsx +2 -0
- package/dist/components/utilities/BorderRadiusUtilities.tsx +56 -0
- package/dist/components/utilities/BorderUtilities.tsx +170 -0
- package/dist/components/utilities/DisplayUtilities.tsx +116 -0
- package/dist/components/utilities/FlexAndGridUtilities.tsx +551 -0
- package/dist/components/utilities/ObjectFitUtilities.tsx +53 -0
- package/dist/components/utilities/ObjectPositionUtilities.tsx +68 -0
- package/dist/components/utilities/OpacityUtilities.tsx +64 -0
- package/dist/components/utilities/OverflowUtilities.tsx +93 -0
- package/dist/components/utilities/PositionUtilities.tsx +52 -0
- package/dist/components/utilities/ShadowUtilities.tsx +123 -0
- package/dist/components/utilities/SpacingUtilities.tsx +2 -2
- package/dist/components/utilities/TextUtilities.tsx +83 -4
- package/dist/components.html +2 -4
- package/dist/components_deprecated/modals.html +2 -2
- package/dist/components_deprecated.html +1 -0
- package/dist/design-patterns/Index.tsx +1 -42
- package/dist/design-patterns/ThreePaneLayoutPattern.tsx +1 -1
- package/dist/design-patterns.html +2 -4
- package/dist/design.html +1 -0
- package/dist/examples.bundle.css +15 -7
- package/dist/examples.bundle.js +4283 -2189
- package/dist/main.html +1 -0
- package/dist/playgrounds/react-playgrounds/Rundowns.tsx +1 -1
- package/dist/playgrounds/react-playgrounds/TestGround.tsx +214 -2
- package/dist/playgrounds.html +1 -0
- package/dist/superdesk-ui.bundle.css +1397 -1019
- package/dist/superdesk-ui.bundle.js +2039 -1653
- package/dist/vendor.bundle.js +16 -16
- package/examples/css/docs-page.css +15 -7
- package/examples/js/doc.js +13 -1
- package/examples/pages/components/Alerts.tsx +1 -1
- package/examples/pages/components/ContentDivider.tsx +1 -1
- package/examples/pages/components/DragHandleDocs.tsx +2 -2
- package/examples/pages/components/Index.tsx +105 -50
- package/examples/pages/components/Panel.tsx +13 -13
- package/examples/pages/components/Tags.tsx +2 -2
- package/examples/pages/components/TimePicker.tsx +43 -1
- package/examples/pages/components/Togglebox.tsx +171 -17
- package/examples/pages/components/TreeMenu.tsx +2 -0
- package/examples/pages/components/utilities/BorderRadiusUtilities.tsx +56 -0
- package/examples/pages/components/utilities/BorderUtilities.tsx +170 -0
- package/examples/pages/components/utilities/DisplayUtilities.tsx +116 -0
- package/examples/pages/components/utilities/FlexAndGridUtilities.tsx +551 -0
- package/examples/pages/components/utilities/ObjectFitUtilities.tsx +53 -0
- package/examples/pages/components/utilities/ObjectPositionUtilities.tsx +68 -0
- package/examples/pages/components/utilities/OpacityUtilities.tsx +64 -0
- package/examples/pages/components/utilities/OverflowUtilities.tsx +93 -0
- package/examples/pages/components/utilities/PositionUtilities.tsx +52 -0
- package/examples/pages/components/utilities/ShadowUtilities.tsx +123 -0
- package/examples/pages/components/utilities/SpacingUtilities.tsx +2 -2
- package/examples/pages/components/utilities/TextUtilities.tsx +83 -4
- package/examples/pages/components.html +2 -4
- package/examples/pages/components_deprecated/modals.html +2 -2
- package/examples/pages/components_deprecated.html +1 -0
- package/examples/pages/design-patterns/Index.tsx +1 -42
- package/examples/pages/design-patterns/ThreePaneLayoutPattern.tsx +1 -1
- package/examples/pages/design-patterns.html +2 -4
- package/examples/pages/design.html +1 -0
- package/examples/pages/main.html +1 -0
- package/examples/pages/playgrounds/react-playgrounds/Rundowns.tsx +1 -1
- package/examples/pages/playgrounds/react-playgrounds/TestGround.tsx +214 -2
- package/examples/pages/playgrounds.html +1 -0
- package/package.json +1 -1
- package/react/components/DatePicker.d.ts +3 -0
- package/react/components/DatePicker.js +2 -2
- package/react/components/Layouts/LayoutContainer.d.ts +1 -0
- package/react/components/Layouts/LayoutContainer.js +8 -1
- package/react/components/Layouts/PageLayout.d.ts +1 -0
- package/react/components/Layouts/PageLayout.js +1 -1
- package/react/components/TimePickerV2.d.ts +28 -0
- package/react/components/TimePickerV2.js +189 -0
- package/react/components/ToggleBox/CustomHeaderToggleBox.d.ts +12 -0
- package/react/components/ToggleBox/CustomHeaderToggleBox.js +81 -0
- package/react/components/ToggleBox/SimpleToggleBox.d.ts +18 -0
- package/react/components/{Togglebox.js → ToggleBox/SimpleToggleBox.js} +15 -13
- package/react/components/ToggleBox/index.d.ts +27 -0
- package/react/components/ToggleBox/index.js +71 -0
- package/react/components/TreeMenu.js +9 -7
- package/react/components/TreeSelect/TreeSelect.js +9 -11
- package/react/components/TreeSelect/TreeSelectItem.d.ts +1 -0
- package/react/components/TreeSelect/TreeSelectItem.js +7 -4
- package/react/index.d.ts +2 -1
- package/react/index.js +7 -5
- package/react/components/Togglebox.d.ts +0 -28
@@ -0,0 +1,222 @@
|
|
1
|
+
import * as React from 'react';
|
2
|
+
import { InputWrapper } from './Form';
|
3
|
+
import {IInputWrapper} from './Form/InputWrapper';
|
4
|
+
import {padStart, range} from 'lodash';
|
5
|
+
|
6
|
+
interface IProps extends IInputWrapper {
|
7
|
+
value: string; // ISO 8601, 13:59:01
|
8
|
+
allowSeconds?: boolean;
|
9
|
+
disabledOptions: {
|
10
|
+
hours?: Array<number>;
|
11
|
+
minutes?: Array<number>;
|
12
|
+
seconds?: Array<number>;
|
13
|
+
};
|
14
|
+
'data-test-id'?: string;
|
15
|
+
onChange(valueNext: string): void;
|
16
|
+
}
|
17
|
+
|
18
|
+
type ITimeUnit = 'hours' | 'minutes' | 'seconds';
|
19
|
+
|
20
|
+
export class TimePickerV2 extends React.PureComponent<IProps> {
|
21
|
+
private is12HourFormat: boolean;
|
22
|
+
|
23
|
+
constructor(props: IProps) {
|
24
|
+
super(props);
|
25
|
+
|
26
|
+
this.handleTimeChange = this.handleTimeChange.bind(this);
|
27
|
+
this.getCorrectedTime = this.getCorrectedTime.bind(this);
|
28
|
+
this.getOptionsForTimeUnit = this.getOptionsForTimeUnit.bind(this);
|
29
|
+
this.padValue = this.padValue.bind(this);
|
30
|
+
|
31
|
+
const hour = new Date().toLocaleTimeString([], { hour: 'numeric' });
|
32
|
+
this.is12HourFormat = hour.includes('AM') || hour.includes('PM');
|
33
|
+
}
|
34
|
+
|
35
|
+
/**
|
36
|
+
* in case initial time is not valid according to disabled options, we return first valid option
|
37
|
+
*/
|
38
|
+
private getCorrectedTime(timeUnit: ITimeUnit, timeStringArray: Array<string>): string {
|
39
|
+
const dividedValue = this.props.value.split(':');
|
40
|
+
const value = (() => {
|
41
|
+
if (timeUnit === 'hours') {
|
42
|
+
return dividedValue[0];
|
43
|
+
} else if (timeUnit === 'minutes') {
|
44
|
+
return dividedValue[1];
|
45
|
+
}
|
46
|
+
|
47
|
+
return dividedValue[2];
|
48
|
+
})();
|
49
|
+
|
50
|
+
if (!(this.props.disabledOptions[timeUnit] ?? []).includes(parseInt(value, 10)) && value != null) {
|
51
|
+
return value;
|
52
|
+
}
|
53
|
+
|
54
|
+
return timeStringArray[0];
|
55
|
+
}
|
56
|
+
|
57
|
+
private getOptionsForTimeUnit(timeUnit: ITimeUnit): Array<string> {
|
58
|
+
let format12HourArr = range(1, 13);
|
59
|
+
format12HourArr.unshift(format12HourArr.pop() as number);
|
60
|
+
|
61
|
+
const timeUnitArray = (() => {
|
62
|
+
if (timeUnit === 'hours') {
|
63
|
+
if (this.is12HourFormat) {
|
64
|
+
return format12HourArr;
|
65
|
+
} else {
|
66
|
+
return range(24);
|
67
|
+
}
|
68
|
+
} else {
|
69
|
+
return range(60);
|
70
|
+
}
|
71
|
+
})();
|
72
|
+
|
73
|
+
return timeUnitArray
|
74
|
+
.filter((item) => !(this.props.disabledOptions[timeUnit] ?? []).includes(item))
|
75
|
+
.map((value) => padStart(value.toString(), 2, '0'));
|
76
|
+
}
|
77
|
+
|
78
|
+
private handleTimeChange(index: number, newValue: string) {
|
79
|
+
let current = this.props.value.split(':');
|
80
|
+
|
81
|
+
const updated12HourValue = (() => {
|
82
|
+
if (parseInt(current[0], 10) >= 12) {
|
83
|
+
if (newValue === '12') {
|
84
|
+
return newValue;
|
85
|
+
} else {
|
86
|
+
return (parseInt(newValue, 10) + 12).toString();
|
87
|
+
}
|
88
|
+
} else {
|
89
|
+
if (newValue === '12') {
|
90
|
+
return '00';
|
91
|
+
} else {
|
92
|
+
return newValue;
|
93
|
+
}
|
94
|
+
}
|
95
|
+
})();
|
96
|
+
|
97
|
+
current[index] = this.is12HourFormat ? updated12HourValue : newValue;
|
98
|
+
|
99
|
+
this.props.onChange(current.join(':'));
|
100
|
+
}
|
101
|
+
|
102
|
+
componentDidMount(): void {
|
103
|
+
const correctedTime = [
|
104
|
+
this.getCorrectedTime('hours', this.getOptionsForTimeUnit('hours')),
|
105
|
+
':',
|
106
|
+
this.getCorrectedTime('minutes', this.getOptionsForTimeUnit('minutes')),
|
107
|
+
this.props.allowSeconds
|
108
|
+
? `:${this.getCorrectedTime('seconds', this.getOptionsForTimeUnit('seconds'))}`
|
109
|
+
: '',
|
110
|
+
].join('');
|
111
|
+
|
112
|
+
if (this.props.value !== correctedTime) {
|
113
|
+
this.props.onChange(correctedTime);
|
114
|
+
}
|
115
|
+
}
|
116
|
+
|
117
|
+
padValue(value: number) {
|
118
|
+
return padStart((value).toString(), 2, '0');
|
119
|
+
}
|
120
|
+
|
121
|
+
updatedTimeUnit() {
|
122
|
+
const timeUnitValuesArray = this.props.value.split(':');
|
123
|
+
|
124
|
+
/**
|
125
|
+
* updating the initial value from props
|
126
|
+
*/
|
127
|
+
if (this.is12HourFormat) {
|
128
|
+
if (parseInt(timeUnitValuesArray[0], 10) > 12) {
|
129
|
+
timeUnitValuesArray[0] = this.padValue(parseInt(timeUnitValuesArray[0], 10) - 12);
|
130
|
+
}
|
131
|
+
}
|
132
|
+
|
133
|
+
return timeUnitValuesArray;
|
134
|
+
}
|
135
|
+
|
136
|
+
render() {
|
137
|
+
const timeUnitValuesArray = this.updatedTimeUnit();
|
138
|
+
|
139
|
+
return (
|
140
|
+
<InputWrapper
|
141
|
+
label={this.props.label}
|
142
|
+
error={this.props.error}
|
143
|
+
invalid={this.props.error != null}
|
144
|
+
required={this.props.required}
|
145
|
+
disabled={this.props.disabled}
|
146
|
+
info={this.props.info}
|
147
|
+
inlineLabel={this.props.inlineLabel}
|
148
|
+
labelHidden={this.props.labelHidden}
|
149
|
+
tabindex={this.props.tabindex}
|
150
|
+
>
|
151
|
+
<div className='sd__input__time-picker-v2' data-test-id={this.props['data-test-id']}>
|
152
|
+
<div className='input-wrapper__time-picker-v2'>
|
153
|
+
<select
|
154
|
+
className='sd-input__select'
|
155
|
+
value={timeUnitValuesArray[0]}
|
156
|
+
onChange={({target}) => {
|
157
|
+
this.handleTimeChange(0, target.value);
|
158
|
+
}}
|
159
|
+
>
|
160
|
+
{this.getOptionsForTimeUnit('hours').map((hour) => (
|
161
|
+
<option value={hour} label={hour} key={hour} />
|
162
|
+
))}
|
163
|
+
</select>
|
164
|
+
<span className='time-picker-v2-suffix'>:</span>
|
165
|
+
</div>
|
166
|
+
<div className='input-wrapper__time-picker-v2'>
|
167
|
+
<select
|
168
|
+
className='sd-input__select'
|
169
|
+
value={timeUnitValuesArray[1]}
|
170
|
+
onChange={({target}) => {
|
171
|
+
this.handleTimeChange(1, target.value);
|
172
|
+
}}
|
173
|
+
>
|
174
|
+
{this.getOptionsForTimeUnit('minutes').map((minute) => (
|
175
|
+
<option value={minute} label={minute} key={minute} />
|
176
|
+
))}
|
177
|
+
</select>
|
178
|
+
{this.props.allowSeconds && (<span className='time-picker-v2-suffix'>:</span>)}
|
179
|
+
</div>
|
180
|
+
{this.props.allowSeconds && (
|
181
|
+
<div className='input-wrapper__time-picker-v2'>
|
182
|
+
<select
|
183
|
+
className='sd-input__select'
|
184
|
+
value={timeUnitValuesArray[2]}
|
185
|
+
onChange={({target}) => {
|
186
|
+
this.handleTimeChange(2, target.value);
|
187
|
+
}}
|
188
|
+
>
|
189
|
+
{this.getOptionsForTimeUnit('seconds').map((second) => (
|
190
|
+
<option value={second} label={second} key={second} />
|
191
|
+
))}
|
192
|
+
</select>
|
193
|
+
</div>
|
194
|
+
)}
|
195
|
+
{this.is12HourFormat && (
|
196
|
+
<div className='input-wrapper__time-picker-v2'>
|
197
|
+
<span className='time-picker-v2-suffix' />
|
198
|
+
<select
|
199
|
+
className='sd-input__select'
|
200
|
+
value={(parseInt(this.props.value.split(':')[0], 10) >= 12) ? 'PM' : 'AM'}
|
201
|
+
onChange={({target}) => {
|
202
|
+
let splitValue = this.props.value.split(':');
|
203
|
+
|
204
|
+
if (target.value === 'PM') {
|
205
|
+
splitValue[0] = this.padValue(parseInt(splitValue[0], 10) + 12);
|
206
|
+
} else {
|
207
|
+
splitValue[0] = this.padValue(parseInt(splitValue[0], 10) - 12);
|
208
|
+
}
|
209
|
+
|
210
|
+
this.props.onChange(splitValue.join(':'));
|
211
|
+
}}
|
212
|
+
>
|
213
|
+
<option value='AM' label='AM' />
|
214
|
+
<option value='PM' label='PM' />
|
215
|
+
</select>
|
216
|
+
</div>
|
217
|
+
)}
|
218
|
+
</div>
|
219
|
+
</InputWrapper>
|
220
|
+
);
|
221
|
+
}
|
222
|
+
}
|
@@ -0,0 +1,61 @@
|
|
1
|
+
import * as React from 'react';
|
2
|
+
import classNames from 'classnames';
|
3
|
+
import nextId from "react-id-generator";
|
4
|
+
import {IPropsCustomHeader} from "../ToggleBox/index";
|
5
|
+
|
6
|
+
interface IState {
|
7
|
+
isOpen: boolean;
|
8
|
+
}
|
9
|
+
|
10
|
+
export class CustomHeaderToggleBox extends React.PureComponent<IPropsCustomHeader, IState> {
|
11
|
+
htmlId = nextId('togglebox-');
|
12
|
+
constructor(props: IPropsCustomHeader) {
|
13
|
+
super(props);
|
14
|
+
this.state = {
|
15
|
+
isOpen: this.props.initiallyOpen ?? false,
|
16
|
+
};
|
17
|
+
}
|
18
|
+
|
19
|
+
toggle = (): void => {
|
20
|
+
this.setState({isOpen: !this.state.isOpen}, () => {
|
21
|
+
this.props.onToggle?.(this.state.isOpen);
|
22
|
+
});
|
23
|
+
}
|
24
|
+
|
25
|
+
render() {
|
26
|
+
let classes = classNames('sd-shadow--z1 new-collapse-box', {
|
27
|
+
'new-collapse-box--open': this.state.isOpen,
|
28
|
+
});
|
29
|
+
const { isOpen } = this.state;
|
30
|
+
|
31
|
+
return (
|
32
|
+
<div
|
33
|
+
className={classes}
|
34
|
+
aria-expanded={isOpen}
|
35
|
+
data-test-id='toggle-box'
|
36
|
+
>
|
37
|
+
<div className='new-collapse-box__header'>
|
38
|
+
<div className='new-collapse-box__header-inner'>
|
39
|
+
{this.props.header}
|
40
|
+
</div>
|
41
|
+
|
42
|
+
<button
|
43
|
+
className='new-collapse-box__divider'
|
44
|
+
onClick={this.toggle}
|
45
|
+
aria-controls={this.htmlId}
|
46
|
+
>
|
47
|
+
<span className='label label--translucent new-collapse-box__divider-label'>
|
48
|
+
{this.props.toggleButtonLabel}
|
49
|
+
</span>
|
50
|
+
</button>
|
51
|
+
</div>
|
52
|
+
|
53
|
+
<div className='new-collapse-box__content'>
|
54
|
+
<div id={this.htmlId} aria-hidden={!isOpen} className='new-collapse-box__content-inner p-2 pt-0-5'>
|
55
|
+
{this.props.children}
|
56
|
+
</div>
|
57
|
+
</div>
|
58
|
+
</div>
|
59
|
+
);
|
60
|
+
}
|
61
|
+
}
|
@@ -1,18 +1,7 @@
|
|
1
1
|
import * as React from 'react';
|
2
2
|
import classNames from 'classnames';
|
3
3
|
import nextId from "react-id-generator";
|
4
|
-
|
5
|
-
interface IProps {
|
6
|
-
title: string;
|
7
|
-
badge?: JSX.Element;
|
8
|
-
children: any;
|
9
|
-
hideUsingCSS?: boolean;
|
10
|
-
initiallyOpen?: boolean; // defaults to false
|
11
|
-
className?: string;
|
12
|
-
margin?: 'none' | 'small' | 'normal' | 'large';
|
13
|
-
onOpen?(): void;
|
14
|
-
onClose?(): void;
|
15
|
-
}
|
4
|
+
import {IPropsSimple} from "../ToggleBox/index";
|
16
5
|
|
17
6
|
interface IState {
|
18
7
|
isOpen: boolean;
|
@@ -24,9 +13,9 @@ interface IState {
|
|
24
13
|
* @description ToggleBox used to open/close a set of details
|
25
14
|
*/
|
26
15
|
|
27
|
-
export class
|
28
|
-
htmlId = nextId();
|
29
|
-
constructor(props:
|
16
|
+
export class SimpleToggleBox extends React.PureComponent<IPropsSimple, IState> {
|
17
|
+
htmlId = nextId('togglebox-');
|
18
|
+
constructor(props: IPropsSimple) {
|
30
19
|
super(props);
|
31
20
|
this.state = {
|
32
21
|
isOpen: this.props.initiallyOpen ?? false,
|
@@ -56,10 +45,13 @@ export class ToggleBox extends React.PureComponent<IProps, IState> {
|
|
56
45
|
render() {
|
57
46
|
let classes = classNames('toggle-box', {
|
58
47
|
'toggle-box--margin-normal': this.props.margin === undefined,
|
48
|
+
'toggle-box--large-title': this.props.largeTitle,
|
49
|
+
'toggle-box--circle': this.props.circledChevron,
|
59
50
|
[`toggle-box--margin-${this.props.margin}`]: this.props.margin,
|
60
51
|
'hidden': !this.state.isOpen,
|
52
|
+
'open': this.state.isOpen,
|
61
53
|
}, this.props.className);
|
62
|
-
const { title,
|
54
|
+
const { title, children, badge } = this.props;
|
63
55
|
const { isOpen } = this.state;
|
64
56
|
|
65
57
|
return (
|
@@ -72,7 +64,8 @@ export class ToggleBox extends React.PureComponent<IProps, IState> {
|
|
72
64
|
role="button"
|
73
65
|
tabIndex={0}
|
74
66
|
onKeyDown={this.handleKeyDown}
|
75
|
-
|
67
|
+
aria-expanded={isOpen}
|
68
|
+
aria-controls={this.htmlId}
|
76
69
|
>
|
77
70
|
<div className="toggle-box__chevron">
|
78
71
|
<i className="icon-chevron-right-thin" />
|
@@ -86,23 +79,9 @@ export class ToggleBox extends React.PureComponent<IProps, IState> {
|
|
86
79
|
{badge ? badge : null}
|
87
80
|
</a>
|
88
81
|
<div className="toggle-box__content-wraper">
|
89
|
-
{
|
90
|
-
|
91
|
-
|
92
|
-
</div>
|
93
|
-
)}
|
94
|
-
|
95
|
-
{hideUsingCSS && (
|
96
|
-
<div
|
97
|
-
className={classNames(
|
98
|
-
'toggle-box__content',
|
99
|
-
{ 'toggle-box__content--hidden': !isOpen },
|
100
|
-
)}
|
101
|
-
aria-describedby={`togglebox-${this.htmlId}`}
|
102
|
-
>
|
103
|
-
{children}
|
104
|
-
</div>
|
105
|
-
)}
|
82
|
+
<div id={this.htmlId} className="toggle-box__content" aria-hidden={!isOpen}>
|
83
|
+
{children}
|
84
|
+
</div>
|
106
85
|
</div>
|
107
86
|
</div>
|
108
87
|
);
|
@@ -0,0 +1,43 @@
|
|
1
|
+
import * as React from 'react';
|
2
|
+
import {SimpleToggleBox} from './SimpleToggleBox';
|
3
|
+
import {CustomHeaderToggleBox} from './CustomHeaderToggleBox';
|
4
|
+
|
5
|
+
export interface IPropsSimple {
|
6
|
+
variant: 'simple';
|
7
|
+
title: string;
|
8
|
+
badge?: JSX.Element;
|
9
|
+
children: React.ReactNode;
|
10
|
+
circledChevron?: boolean;
|
11
|
+
initiallyOpen?: boolean; // defaults to false
|
12
|
+
largeTitle?: boolean;
|
13
|
+
|
14
|
+
className?: string;
|
15
|
+
margin?: 'none' | 'small' | 'normal' | 'large';
|
16
|
+
onOpen?(): void;
|
17
|
+
onClose?(): void;
|
18
|
+
}
|
19
|
+
|
20
|
+
export interface IPropsCustomHeader {
|
21
|
+
variant: 'custom-header'; // always visible
|
22
|
+
header: React.ReactNode;
|
23
|
+
children: React.ReactNode;
|
24
|
+
toggleButtonLabel: string;
|
25
|
+
initiallyOpen?: boolean;
|
26
|
+
onToggle?(isOpen: boolean): void;
|
27
|
+
}
|
28
|
+
|
29
|
+
type IProps = IPropsSimple | IPropsCustomHeader;
|
30
|
+
|
31
|
+
export class ToggleBox extends React.PureComponent<IProps> {
|
32
|
+
render() {
|
33
|
+
if (this.props.variant === "simple") {
|
34
|
+
return (
|
35
|
+
<SimpleToggleBox {...this.props} />
|
36
|
+
);
|
37
|
+
} else {
|
38
|
+
return (
|
39
|
+
<CustomHeaderToggleBox {...this.props} />
|
40
|
+
);
|
41
|
+
}
|
42
|
+
}
|
43
|
+
}
|
@@ -57,7 +57,7 @@ function nodeCanBeSelected<T>(item: IParent<T> | IChildren<T>): item is IChildre
|
|
57
57
|
|
58
58
|
function onSelect<T>(item: ITreeMenuNode<T>) {
|
59
59
|
if (nodeCanBeSelected(item)) {
|
60
|
-
return item.onSelect;
|
60
|
+
return item.onSelect();
|
61
61
|
}
|
62
62
|
|
63
63
|
return undefined;
|
@@ -285,11 +285,9 @@ export class TreeMenu<T> extends React.Component<IProps<T>, IState<T>> {
|
|
285
285
|
|
286
286
|
const item = this.state.buttonTree.pop();
|
287
287
|
|
288
|
-
|
289
|
-
|
290
|
-
|
291
|
-
});
|
292
|
-
}
|
288
|
+
this.setState({
|
289
|
+
buttonValue: item ?? null,
|
290
|
+
});
|
293
291
|
}
|
294
292
|
|
295
293
|
recursion(arr: Array<ITreeMenuNode<T>>) {
|
@@ -414,15 +412,22 @@ export class TreeMenu<T> extends React.Component<IProps<T>, IState<T>> {
|
|
414
412
|
<ul
|
415
413
|
ref={this.ref}
|
416
414
|
className="suggestion-list suggestion-list--multi-select"
|
415
|
+
role='tree'
|
417
416
|
>
|
418
417
|
{this.state.options.map((option, i: React.Key | undefined) => (
|
419
418
|
<TreeSelectItem
|
420
419
|
key={i}
|
421
420
|
option={option}
|
422
421
|
handleTree={this.handleTree}
|
423
|
-
onClick={
|
422
|
+
onClick={() => {
|
423
|
+
onSelect(option);
|
424
|
+
}}
|
424
425
|
disabledItem={disabledItem(option)}
|
425
426
|
getBorderColor={this.props.getBorderColor}
|
427
|
+
parentCategory={this.state.buttonValue == null
|
428
|
+
? undefined
|
429
|
+
: this.props.getLabel(this.state.buttonValue.value)
|
430
|
+
}
|
426
431
|
getBackgroundColor={this.props.getBackgroundColor}
|
427
432
|
getId={this.props.getId}
|
428
433
|
optionTemplate={this.props.optionTemplate}
|
@@ -455,11 +455,9 @@ export class TreeSelect<T> extends React.Component<IProps<T>, IState<T>> {
|
|
455
455
|
|
456
456
|
const item = this.state.buttonTree.pop();
|
457
457
|
|
458
|
-
|
459
|
-
|
460
|
-
|
461
|
-
});
|
462
|
-
}
|
458
|
+
this.setState({
|
459
|
+
buttonValue: item ?? null,
|
460
|
+
});
|
463
461
|
}
|
464
462
|
|
465
463
|
recursion(arr: Array<ITreeNode<T>>) {
|
@@ -738,6 +736,8 @@ export class TreeSelect<T> extends React.Component<IProps<T>, IState<T>> {
|
|
738
736
|
}
|
739
737
|
}}
|
740
738
|
data-test-id="open-popover"
|
739
|
+
aria-haspopup="tree"
|
740
|
+
aria-expanded={this.state.openDropdown}
|
741
741
|
>
|
742
742
|
<i className="icon-plus-large"></i>
|
743
743
|
</button>
|
@@ -893,12 +893,7 @@ export class TreeSelect<T> extends React.Component<IProps<T>, IState<T>> {
|
|
893
893
|
ref={this.dropdownRef}
|
894
894
|
>
|
895
895
|
<div className='autocomplete__header'>
|
896
|
-
<div
|
897
|
-
className="autocomplete__icon"
|
898
|
-
onClick={() => {
|
899
|
-
this.backButton();
|
900
|
-
}}
|
901
|
-
>
|
896
|
+
<div className="autocomplete__icon">
|
902
897
|
<Icon name="search" className="search"></Icon>
|
903
898
|
</div>
|
904
899
|
|
@@ -968,6 +963,8 @@ export class TreeSelect<T> extends React.Component<IProps<T>, IState<T>> {
|
|
968
963
|
className="suggestion-list suggestion-list--multi-select"
|
969
964
|
ref={this.ref}
|
970
965
|
data-test-id="options"
|
966
|
+
role='tree'
|
967
|
+
aria-multiselectable={this.props.allowMultiple}
|
971
968
|
>
|
972
969
|
{this.state.options.map((option, i: React.Key | undefined) => {
|
973
970
|
let selectedItem = this.state.value.some((obj) =>
|
@@ -981,11 +978,15 @@ export class TreeSelect<T> extends React.Component<IProps<T>, IState<T>> {
|
|
981
978
|
handleTree={this.handleTree}
|
982
979
|
selectedItem={selectedItem}
|
983
980
|
allowMultiple={this.props.allowMultiple}
|
981
|
+
parentCategory={this.state.buttonValue == null
|
982
|
+
? undefined
|
983
|
+
: this.props.getLabel(this.state.buttonValue.value)
|
984
|
+
}
|
984
985
|
getBorderColor={this.props.getBorderColor}
|
985
986
|
getBackgroundColor={this.props.getBackgroundColor}
|
986
987
|
getId={this.props.getId}
|
987
|
-
optionTemplate={this.props.optionTemplate}
|
988
988
|
getLabel={this.props.getLabel}
|
989
|
+
optionTemplate={this.props.optionTemplate}
|
989
990
|
onKeyDown={() => this.setState({
|
990
991
|
buttonTarget: [
|
991
992
|
...this.state.buttonTarget,
|
@@ -12,6 +12,7 @@ interface IProps<T> {
|
|
12
12
|
selectedItem?: boolean;
|
13
13
|
disabledItem?: boolean;
|
14
14
|
allowMultiple?: boolean;
|
15
|
+
parentCategory?: string | undefined;
|
15
16
|
handleTree(event: React.MouseEvent<HTMLLIElement, MouseEvent>, option: ITreeNode<T>): any;
|
16
17
|
getLabel(item: T): string;
|
17
18
|
getId(item: T): string;
|
@@ -24,9 +25,14 @@ interface IProps<T> {
|
|
24
25
|
|
25
26
|
export class TreeSelectItem<T> extends React.Component<IProps<T>> {
|
26
27
|
render() {
|
28
|
+
const ariaLabel = this.props.parentCategory !== undefined
|
29
|
+
? `${this.props.getLabel(this.props.option.value)}, parent ${this.props.parentCategory}`
|
30
|
+
: this.props.getLabel(this.props.option.value);
|
31
|
+
|
27
32
|
return (
|
28
33
|
<li
|
29
34
|
className='suggestion-item suggestion-item--multi-select'
|
35
|
+
role='none'
|
30
36
|
onClick={(event) => {
|
31
37
|
if (!this.props.disabledItem) {
|
32
38
|
this.props.onClick?.();
|
@@ -49,6 +55,9 @@ export class TreeSelectItem<T> extends React.Component<IProps<T>> {
|
|
49
55
|
}}
|
50
56
|
disabled={this.props.disabledItem}
|
51
57
|
data-test-id="option"
|
58
|
+
role='treeItem'
|
59
|
+
aria-selected={this.props.selectedItem === true}
|
60
|
+
aria-disabled={this.props.disabledItem === true}
|
52
61
|
>
|
53
62
|
{(this.props.getBorderColor && !this.props.allowMultiple)
|
54
63
|
&& <div
|
@@ -74,6 +83,7 @@ export class TreeSelectItem<T> extends React.Component<IProps<T>> {
|
|
74
83
|
}
|
75
84
|
: undefined
|
76
85
|
}
|
86
|
+
aria-label={ariaLabel}
|
77
87
|
>
|
78
88
|
{this.props.optionTemplate
|
79
89
|
? this.props.optionTemplate(this.props.option.value)
|
@@ -82,7 +92,7 @@ export class TreeSelectItem<T> extends React.Component<IProps<T>> {
|
|
82
92
|
</span>
|
83
93
|
|
84
94
|
{this.props.option.children
|
85
|
-
&& <span className="suggestion-item__icon">
|
95
|
+
&& <span className="suggestion-item__icon" aria-hidden="true">
|
86
96
|
<Icon name="chevron-right-thin"></Icon>
|
87
97
|
</span>
|
88
98
|
}
|
package/app-typescript/index.ts
CHANGED
@@ -27,6 +27,7 @@ export { DatePicker } from './components/DatePicker';
|
|
27
27
|
export { DatePickerISO } from './components/DatePicker';
|
28
28
|
export { DatePickerLocaleSettings } from './components/DatePicker';
|
29
29
|
export { TimePicker } from './components/TimePicker';
|
30
|
+
export { TimePickerV2 } from './components/TimePickerV2';
|
30
31
|
export { FormLabel } from './components/FormLabel';
|
31
32
|
export { Switch } from './components/Switch';
|
32
33
|
export { SwitchGroup } from './components/SwitchGroup';
|
@@ -69,7 +70,7 @@ export { GridItem, GridItemContent, GridItemMedia, GridItemFooter, GridItemConte
|
|
69
70
|
} from './components/GridItem';
|
70
71
|
export { toasted } from './components/Toast';
|
71
72
|
export { Menu } from './components/Menu';
|
72
|
-
export { ToggleBox } from './components/
|
73
|
+
export { ToggleBox } from './components/ToggleBox/index';
|
73
74
|
export { SelectGrid } from './components/SelectGrid';
|
74
75
|
export { IconPicker } from './components/IconPicker';
|
75
76
|
export { ThemeSelector } from './components/ThemeSelector';
|
@@ -142,7 +142,7 @@ export default class AlertDoc extends React.Component {
|
|
142
142
|
This will strip all margins and the border-radius from the component. Hollow style is not recommended in this case, and small size is advised.</p>
|
143
143
|
<Markup.ReactMarkup>
|
144
144
|
<Markup.ReactMarkupPreview>
|
145
|
-
<div className='
|
145
|
+
<div className='d-flex' style={{border: '1px solid var(--sd-colour-line--medium)', backgroundColor: 'var(--sd-colour-panel-bg--100)', maxHeight: '360px'}}>
|
146
146
|
<PanelElements.Panel open={true} side='left' size='small'>
|
147
147
|
<PanelElements.PanelHeader title='Panel example' onClose={()=> false}>
|
148
148
|
<Alert type='warning' icon='exclamation-sign' banner={true} size='small'>
|
@@ -125,7 +125,7 @@ export default class ContentDividerDoc extends React.Component {
|
|
125
125
|
</div>
|
126
126
|
<p className="docs-page__paragraph ">// With text</p>
|
127
127
|
<p className="docs-page__paragraph--small sd-margin-b--3">Inside a flex container (flex-direction: column;).</p>
|
128
|
-
<div className='docs-page__content-row
|
128
|
+
<div className='docs-page__content-row d-flex'>
|
129
129
|
<div style={{width:'100%'}}>
|
130
130
|
Cras justo odio, dapibus ac facilisis in, egestas eget quam. Cum sociis natoque penatibus et
|
131
131
|
magnis dis parturient montes, nascetur ridiculus mus. Maecenas sed diam eget risus varius blandit
|
@@ -23,7 +23,7 @@ export default class DragHandleDocs extends React.Component {
|
|
23
23
|
offering a wide range of size options.
|
24
24
|
</p>
|
25
25
|
<div className="docs-page__content-row">
|
26
|
-
<div className='
|
26
|
+
<div className='d-flex items-start sd-gap--medium'>
|
27
27
|
<DragHandle dotsInRow='2' dotRows='5' />
|
28
28
|
<DragHandle dotsInRow='2' dotRows='8' />
|
29
29
|
<DragHandle dotsInRow='3' dotRows='6' />
|
@@ -39,7 +39,7 @@ export default class DragHandleDocs extends React.Component {
|
|
39
39
|
To be used within list items, draggable labels, and similar contexts.
|
40
40
|
</p>
|
41
41
|
<div className="docs-page__content-row">
|
42
|
-
<div className='
|
42
|
+
<div className='d-flex items-start sd-gap--medium'>
|
43
43
|
<DragHandle blank={true} />
|
44
44
|
<DragHandle dotsInRow='2' dotRows='10' blank={true} />
|
45
45
|
<DragHandle dotsInRow='4' dotRows='10' blank={true} />
|