genesys-react-components 0.1.6-devengage-1377-autofocus.120 → 0.1.8-devengage-1376.128
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/README.md +4 -0
- package/build/index.d.ts +1 -2
- package/build/index.js +6 -6
- package/build/index.js.map +1 -1
- package/package.json +7 -5
- package/src/alertblock/AlertBlock.scss +108 -0
- package/src/alertblock/AlertBlock.tsx +80 -0
- package/src/copybutton/CopyButton.scss +8 -0
- package/src/copybutton/CopyButton.tsx +42 -0
- package/src/dxaccordion/DxAccordion.scss +41 -0
- package/src/dxaccordion/DxAccordion.tsx +49 -0
- package/src/dxaccordion/DxAccordionGroup.scss +3 -0
- package/src/dxaccordion/DxAccordionGroup.tsx +12 -0
- package/src/dxbutton/DxButton.scss +79 -0
- package/src/dxbutton/DxButton.tsx +31 -0
- package/src/dxitemgroup/DxCheckbox.scss +145 -0
- package/src/dxitemgroup/DxCheckbox.tsx +46 -0
- package/src/dxitemgroup/DxItemGroup.scss +6 -0
- package/src/dxitemgroup/DxItemGroup.tsx +133 -0
- package/src/dxitemgroup/dropdown.scss +53 -0
- package/src/dxitemgroup/multiselect.scss +74 -0
- package/src/dxitemgroup/radiobutton.scss +2 -0
- package/src/dxlabel/DxLabel.scss +31 -0
- package/src/dxlabel/DxLabel.tsx +39 -0
- package/src/dxtabbedcontent/DxTabPanel.scss +0 -0
- package/src/dxtabbedcontent/DxTabPanel.tsx +8 -0
- package/src/dxtabbedcontent/DxTabbedContent.scss +45 -0
- package/src/dxtabbedcontent/DxTabbedContent.tsx +28 -0
- package/src/dxtextbox/DxTextbox.scss +107 -0
- package/src/dxtextbox/DxTextbox.tsx +159 -0
- package/src/dxtoggle/DxToggle.scss +76 -0
- package/src/dxtoggle/DxToggle.tsx +51 -0
- package/src/index.ts +141 -0
- package/src/loadingplaceholder/LoadingPlaceholder.scss +58 -0
- package/src/loadingplaceholder/LoadingPlaceholder.tsx +17 -0
- package/src/tooltip/Tooltip.scss +108 -0
- package/src/tooltip/Tooltip.tsx +46 -0
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
import { GenesysDevIcon, GenesysDevIcons } from 'genesys-dev-icons';
|
|
2
|
+
import React from 'react';
|
|
3
|
+
|
|
4
|
+
import './DxLabel.scss';
|
|
5
|
+
|
|
6
|
+
interface IProps {
|
|
7
|
+
label?: string;
|
|
8
|
+
description?: string;
|
|
9
|
+
useFieldset?: boolean;
|
|
10
|
+
className?: string;
|
|
11
|
+
children: React.ReactNode;
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
export default function DxLabel(props: IProps) {
|
|
15
|
+
const hasLabel = props.label && props.label !== '';
|
|
16
|
+
|
|
17
|
+
const description = props.description ? (
|
|
18
|
+
<div className='input-description'>
|
|
19
|
+
<GenesysDevIcon icon={GenesysDevIcons.AppInfoSolid} />
|
|
20
|
+
<span>{props.description}</span>
|
|
21
|
+
</div>
|
|
22
|
+
) : undefined;
|
|
23
|
+
|
|
24
|
+
const contents = (
|
|
25
|
+
<React.Fragment>
|
|
26
|
+
{' '}
|
|
27
|
+
{hasLabel ? <span className='label-text'>{props.label}</span> : undefined}
|
|
28
|
+
{props.children}
|
|
29
|
+
{description}
|
|
30
|
+
</React.Fragment>
|
|
31
|
+
);
|
|
32
|
+
|
|
33
|
+
const className = `dx-label${props.className ? ' ' + props.className : ''}`;
|
|
34
|
+
|
|
35
|
+
if (props.useFieldset) {
|
|
36
|
+
return <fieldset className={className}>{contents}</fieldset>;
|
|
37
|
+
}
|
|
38
|
+
return <label className={className}>{contents}</label>;
|
|
39
|
+
}
|
|
File without changes
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
import React from 'react';
|
|
2
|
+
import { DxTabPanelProps } from '..';
|
|
3
|
+
|
|
4
|
+
import './DxTabPanel.scss';
|
|
5
|
+
|
|
6
|
+
export default function DxTabPanel(props: DxTabPanelProps) {
|
|
7
|
+
return <div className={`dx-tab-panel${props.className ? ' ' + props.className : ''}`}>{props.children}</div>;
|
|
8
|
+
}
|
|
@@ -0,0 +1,45 @@
|
|
|
1
|
+
.dx-tabbed-content {
|
|
2
|
+
margin: 40px 0;
|
|
3
|
+
|
|
4
|
+
.tab-titles {
|
|
5
|
+
border-bottom: 1px solid #bfd4e4;
|
|
6
|
+
font-weight: normal;
|
|
7
|
+
font-size: 14px;
|
|
8
|
+
line-height: 20px;
|
|
9
|
+
|
|
10
|
+
.tab-title {
|
|
11
|
+
display: inline-block;
|
|
12
|
+
padding: 5px 20px;
|
|
13
|
+
border-bottom: 1px solid transparent;
|
|
14
|
+
cursor: pointer;
|
|
15
|
+
|
|
16
|
+
&:hover {
|
|
17
|
+
border-color: #bfd4e4;
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
&.active {
|
|
21
|
+
border-bottom-color: #597393;
|
|
22
|
+
font-weight: bold;
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
// Make markdown-parsed paragraphs look normal
|
|
26
|
+
& p {
|
|
27
|
+
margin: 0;
|
|
28
|
+
display: inline;
|
|
29
|
+
}
|
|
30
|
+
}
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
.tab-content {
|
|
34
|
+
padding: 13px 20px 20px 20px;
|
|
35
|
+
border-bottom: 1px solid #bfd4e4;
|
|
36
|
+
|
|
37
|
+
// Clear excess margins from content, we provide the padding
|
|
38
|
+
& > *:first-child {
|
|
39
|
+
margin-top: 0;
|
|
40
|
+
}
|
|
41
|
+
& > *:last-child {
|
|
42
|
+
margin-bottom: 0;
|
|
43
|
+
}
|
|
44
|
+
}
|
|
45
|
+
}
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
import React, { useState } from 'react';
|
|
2
|
+
import { DxTabbedContentProps } from '..';
|
|
3
|
+
|
|
4
|
+
import './DxTabbedContent.scss';
|
|
5
|
+
|
|
6
|
+
export default function DxTabbedContent(props: DxTabbedContentProps) {
|
|
7
|
+
const [activeTab, setActiveTab] = useState(props.initialTabId || 0);
|
|
8
|
+
const [titles] = useState<React.ReactNode[]>(
|
|
9
|
+
// Scrape titles from child elements
|
|
10
|
+
React.Children.toArray(props.children).map((child: any) => {
|
|
11
|
+
if (!child || !child.props || !child.props.title) return 'Unknown title';
|
|
12
|
+
return child.props.title;
|
|
13
|
+
})
|
|
14
|
+
);
|
|
15
|
+
|
|
16
|
+
return (
|
|
17
|
+
<div className={`dx-tabbed-content${props.className ? ' ' + props.className : ''}`}>
|
|
18
|
+
<div className='tab-titles'>
|
|
19
|
+
{titles.map((title, i) => (
|
|
20
|
+
<span key={i} className={`tab-title${i === activeTab ? ' active' : ''}`} onClick={() => setActiveTab(i)}>
|
|
21
|
+
{title}
|
|
22
|
+
</span>
|
|
23
|
+
))}
|
|
24
|
+
</div>
|
|
25
|
+
<div className='tab-content'>{React.Children.toArray(props.children)[activeTab]}</div>
|
|
26
|
+
</div>
|
|
27
|
+
);
|
|
28
|
+
}
|
|
@@ -0,0 +1,107 @@
|
|
|
1
|
+
.dx-textbox {
|
|
2
|
+
display: flex;
|
|
3
|
+
flex-flow: row nowrap;
|
|
4
|
+
justify-content: space-between;
|
|
5
|
+
align-items: center;
|
|
6
|
+
gap: 10px;
|
|
7
|
+
border: 1px solid #c6cbd1;
|
|
8
|
+
border-radius: 2px;
|
|
9
|
+
margin: 0;
|
|
10
|
+
padding: 0 10px;
|
|
11
|
+
height: 32px;
|
|
12
|
+
background-color: #ffffff;
|
|
13
|
+
|
|
14
|
+
&.with-label {
|
|
15
|
+
margin-top: 0;
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
&:focus-within {
|
|
19
|
+
outline: #aac9ff solid 2px;
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
.icon {
|
|
23
|
+
display: block;
|
|
24
|
+
flex: none;
|
|
25
|
+
color: #75757a;
|
|
26
|
+
|
|
27
|
+
&.input-icon {
|
|
28
|
+
font-size: 14px;
|
|
29
|
+
line-height: 0;
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
&.clear-icon {
|
|
33
|
+
font-size: 11px;
|
|
34
|
+
line-height: 0;
|
|
35
|
+
cursor: pointer;
|
|
36
|
+
padding: 4px;
|
|
37
|
+
margin-right: -4px;
|
|
38
|
+
}
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
.dx-input {
|
|
42
|
+
flex-grow: 1;
|
|
43
|
+
border: 0;
|
|
44
|
+
background: transparent;
|
|
45
|
+
box-sizing: border-box;
|
|
46
|
+
height: 32px;
|
|
47
|
+
width: 100%;
|
|
48
|
+
padding: 0;
|
|
49
|
+
margin: 0;
|
|
50
|
+
font-family: Roboto;
|
|
51
|
+
font-style: normal;
|
|
52
|
+
font-weight: normal;
|
|
53
|
+
font-size: 14px;
|
|
54
|
+
line-height: 16px;
|
|
55
|
+
color: #272d2d;
|
|
56
|
+
|
|
57
|
+
&:focus-visible {
|
|
58
|
+
outline: 0;
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
&::placeholder {
|
|
62
|
+
font-style: normal;
|
|
63
|
+
font-weight: 300;
|
|
64
|
+
font-size: 14px;
|
|
65
|
+
line-height: 16px;
|
|
66
|
+
color: #757576;
|
|
67
|
+
}
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
&.disabled {
|
|
71
|
+
background-color: #e6ebec;
|
|
72
|
+
border-color: #e8eaed;
|
|
73
|
+
cursor: not-allowed;
|
|
74
|
+
|
|
75
|
+
input {
|
|
76
|
+
cursor: not-allowed;
|
|
77
|
+
color: #75757a;
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
.icon,
|
|
81
|
+
input::placeholder {
|
|
82
|
+
color: #ffffff;
|
|
83
|
+
}
|
|
84
|
+
}
|
|
85
|
+
}
|
|
86
|
+
|
|
87
|
+
.dx-textarea {
|
|
88
|
+
padding: 10px;
|
|
89
|
+
border: 1px solid #c6cbd1;
|
|
90
|
+
border-radius: 2px;
|
|
91
|
+
width: 100%;
|
|
92
|
+
font-family: 'Roboto', sans-serif;
|
|
93
|
+
box-sizing: border-box;
|
|
94
|
+
|
|
95
|
+
&:focus-within {
|
|
96
|
+
outline: #aac9ff solid 2px;
|
|
97
|
+
}
|
|
98
|
+
|
|
99
|
+
&::placeholder {
|
|
100
|
+
font-family: 'Roboto', sans-serif;
|
|
101
|
+
font-style: normal;
|
|
102
|
+
font-weight: 300;
|
|
103
|
+
font-size: 14px;
|
|
104
|
+
line-height: 16px;
|
|
105
|
+
color: #757576;
|
|
106
|
+
}
|
|
107
|
+
}
|
|
@@ -0,0 +1,159 @@
|
|
|
1
|
+
import { GenesysDevIcon, GenesysDevIcons } from 'genesys-dev-icons';
|
|
2
|
+
import React, { useEffect, useRef, useState } from 'react';
|
|
3
|
+
import DxLabel from '../dxlabel/DxLabel';
|
|
4
|
+
import { DxTextboxProps } from '..';
|
|
5
|
+
|
|
6
|
+
import './DxTextbox.scss';
|
|
7
|
+
|
|
8
|
+
export default function DxTextbox(props: DxTextboxProps) {
|
|
9
|
+
const [debounceMs, setDebounceMs] = useState(props.changeDebounceMs || 300);
|
|
10
|
+
const [value, setValue] = useState(props.initialValue || props.value || '');
|
|
11
|
+
const [isFocused, setIsFocused] = useState(false);
|
|
12
|
+
const [escapePressed, setEscapePressed] = useState(Date.now());
|
|
13
|
+
const [step, setStep] = useState<string | number | undefined>(undefined);
|
|
14
|
+
let [timer, setTimer] = useState(undefined as unknown as ReturnType<typeof setTimeout>);
|
|
15
|
+
|
|
16
|
+
// Constructor
|
|
17
|
+
useEffect(() => {
|
|
18
|
+
// Register global key bindings
|
|
19
|
+
document.addEventListener('keydown', globalKeyBindings, false);
|
|
20
|
+
|
|
21
|
+
return () => {
|
|
22
|
+
document.removeEventListener('keydown', globalKeyBindings, false);
|
|
23
|
+
};
|
|
24
|
+
}, []);
|
|
25
|
+
|
|
26
|
+
// Value prop updated
|
|
27
|
+
useEffect(() => {
|
|
28
|
+
// Ignore value changed if initial value was set; they're mutually exclusive
|
|
29
|
+
if (!props.initialValue) {
|
|
30
|
+
setValue(props.value || '');
|
|
31
|
+
}
|
|
32
|
+
}, [props.value]);
|
|
33
|
+
|
|
34
|
+
// Escape pressed
|
|
35
|
+
useEffect(() => {
|
|
36
|
+
if (!isFocused) return;
|
|
37
|
+
setValue('');
|
|
38
|
+
inputRef.current?.blur();
|
|
39
|
+
// eslint-disable-next-line react-hooks/exhaustive-deps
|
|
40
|
+
}, [escapePressed]);
|
|
41
|
+
|
|
42
|
+
// Value changed
|
|
43
|
+
useEffect(() => {
|
|
44
|
+
if (props.inputType === 'decimal') {
|
|
45
|
+
// Normalize step setting
|
|
46
|
+
if (!isNaN(parseFloat(value))) {
|
|
47
|
+
const match = /\.(.+)/.exec(value);
|
|
48
|
+
console.log(match);
|
|
49
|
+
if (match) {
|
|
50
|
+
const s = `0.${Array.apply(null, Array(match[1].length - 1))
|
|
51
|
+
.map(() => '0')
|
|
52
|
+
.join('')}1`;
|
|
53
|
+
console.log(s);
|
|
54
|
+
setStep(s);
|
|
55
|
+
}
|
|
56
|
+
}
|
|
57
|
+
} else if (props.inputType === 'integer') {
|
|
58
|
+
// Overwrite value as integer to forcibly truncate floating point numbers
|
|
59
|
+
setValue(parseInt(value).toString());
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
// Debounce onChange notification
|
|
63
|
+
if (!props.onChange) return;
|
|
64
|
+
clearTimeout(timer);
|
|
65
|
+
setTimer(setTimeout(() => (props.onChange ? props.onChange(value) : undefined), debounceMs));
|
|
66
|
+
// eslint-disable-next-line react-hooks/exhaustive-deps
|
|
67
|
+
}, [value]);
|
|
68
|
+
|
|
69
|
+
// Update state from props
|
|
70
|
+
useEffect(() => {
|
|
71
|
+
setDebounceMs(props.changeDebounceMs || 300);
|
|
72
|
+
}, [props.changeDebounceMs]);
|
|
73
|
+
|
|
74
|
+
// Normalize inputRef
|
|
75
|
+
let inputRef; // = useRef<HTMLInputElement>(null);
|
|
76
|
+
if (props.inputRef) inputRef = props.inputRef;
|
|
77
|
+
else if (props.inputType === 'textarea') inputRef = useRef<HTMLTextAreaElement>(null);
|
|
78
|
+
else inputRef = useRef<HTMLInputElement>(null);
|
|
79
|
+
|
|
80
|
+
const hasLabel = props.label && props.label !== '';
|
|
81
|
+
|
|
82
|
+
// Global key bindings
|
|
83
|
+
function globalKeyBindings(event: KeyboardEvent) {
|
|
84
|
+
// Escape - cancel search
|
|
85
|
+
if (event.key === 'Escape') {
|
|
86
|
+
event.stopPropagation();
|
|
87
|
+
event.preventDefault();
|
|
88
|
+
setEscapePressed(Date.now());
|
|
89
|
+
return;
|
|
90
|
+
}
|
|
91
|
+
}
|
|
92
|
+
|
|
93
|
+
// Normalize input type
|
|
94
|
+
let inputType: React.HTMLInputTypeAttribute | undefined = props.inputType;
|
|
95
|
+
if (inputType === 'integer' || inputType === 'decimal') inputType = 'number';
|
|
96
|
+
|
|
97
|
+
let component;
|
|
98
|
+
switch (inputType) {
|
|
99
|
+
case 'textarea': {
|
|
100
|
+
component = (
|
|
101
|
+
<textarea
|
|
102
|
+
className="dx-textarea"
|
|
103
|
+
placeholder={props.placeholder}
|
|
104
|
+
ref={inputRef}
|
|
105
|
+
value={value}
|
|
106
|
+
onChange={(e) => setValue(e.target.value)}
|
|
107
|
+
onFocus={() => {
|
|
108
|
+
setIsFocused(true);
|
|
109
|
+
if (props.onFocus) props.onFocus();
|
|
110
|
+
}}
|
|
111
|
+
onBlur={() => {
|
|
112
|
+
setIsFocused(false);
|
|
113
|
+
if (props.onBlur) props.onBlur();
|
|
114
|
+
}}
|
|
115
|
+
disabled={props.disabled === true}
|
|
116
|
+
autoFocus={props.autoFocus}
|
|
117
|
+
/>
|
|
118
|
+
);
|
|
119
|
+
break;
|
|
120
|
+
}
|
|
121
|
+
// TODO: special handling for other inputType values
|
|
122
|
+
default: {
|
|
123
|
+
component = (
|
|
124
|
+
<div className={`dx-textbox${hasLabel ? ' with-label' : ''}${props.disabled ? ' disabled' : ''}`}>
|
|
125
|
+
{props.icon ? <GenesysDevIcon icon={props.icon} className="input-icon" /> : undefined}
|
|
126
|
+
<input
|
|
127
|
+
className="dx-input"
|
|
128
|
+
type={inputType}
|
|
129
|
+
step={step}
|
|
130
|
+
value={value}
|
|
131
|
+
placeholder={props.placeholder}
|
|
132
|
+
onChange={(e) => setValue(e.target.value)}
|
|
133
|
+
ref={inputRef}
|
|
134
|
+
onFocus={() => {
|
|
135
|
+
setIsFocused(true);
|
|
136
|
+
if (props.onFocus) props.onFocus();
|
|
137
|
+
}}
|
|
138
|
+
onBlur={() => {
|
|
139
|
+
setIsFocused(false);
|
|
140
|
+
if (props.onBlur) props.onBlur();
|
|
141
|
+
}}
|
|
142
|
+
disabled={props.disabled === true}
|
|
143
|
+
autoFocus={props.autoFocus}
|
|
144
|
+
/>
|
|
145
|
+
{props.clearButton && (value || isFocused) && !props.disabled ? (
|
|
146
|
+
<GenesysDevIcon icon={GenesysDevIcons.AppTimes} className="clear-icon" onClick={() => setValue('')} />
|
|
147
|
+
) : undefined}
|
|
148
|
+
</div>
|
|
149
|
+
);
|
|
150
|
+
}
|
|
151
|
+
}
|
|
152
|
+
|
|
153
|
+
// Render
|
|
154
|
+
return (
|
|
155
|
+
<DxLabel label={props.label} description={props.description} className={props.className}>
|
|
156
|
+
{component}
|
|
157
|
+
</DxLabel>
|
|
158
|
+
);
|
|
159
|
+
}
|
|
@@ -0,0 +1,76 @@
|
|
|
1
|
+
.dx-toggle-container {
|
|
2
|
+
display: inline-block;
|
|
3
|
+
.dx-toggle {
|
|
4
|
+
background: #f5f8fb;
|
|
5
|
+
border: 1px solid #c6cbd1;
|
|
6
|
+
border-radius: 6px;
|
|
7
|
+
height: 26px;
|
|
8
|
+
// width: 72px;
|
|
9
|
+
padding: 0px 4px;
|
|
10
|
+
display: flex;
|
|
11
|
+
flex-flow: row nowrap;
|
|
12
|
+
justify-content: space-between;
|
|
13
|
+
align-items: center;
|
|
14
|
+
gap: 2px;
|
|
15
|
+
cursor: pointer;
|
|
16
|
+
|
|
17
|
+
&:hover {
|
|
18
|
+
.slider {
|
|
19
|
+
border-color: #aac9ff;
|
|
20
|
+
}
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
.icon {
|
|
24
|
+
font-size: 10px;
|
|
25
|
+
line-height: 0;
|
|
26
|
+
margin: 0 5px;
|
|
27
|
+
color: #c4c4c4;
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
.clear-placeholder {
|
|
31
|
+
width: 19px;
|
|
32
|
+
padding: 0 1px 0 0;
|
|
33
|
+
margin: 0;
|
|
34
|
+
display: block;
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
.slider {
|
|
38
|
+
height: 22px;
|
|
39
|
+
width: 22px;
|
|
40
|
+
border-radius: 22px;
|
|
41
|
+
background-color: #419bb2;
|
|
42
|
+
box-shadow: 0px 1px 2px rgba(0, 0, 0, 0.25);
|
|
43
|
+
display: flex;
|
|
44
|
+
align-items: center;
|
|
45
|
+
justify-content: center;
|
|
46
|
+
border: 1px solid transparent;
|
|
47
|
+
|
|
48
|
+
.icon {
|
|
49
|
+
font-size: 10px;
|
|
50
|
+
line-height: 0;
|
|
51
|
+
color: #ffffff;
|
|
52
|
+
padding: 0;
|
|
53
|
+
margin: 0;
|
|
54
|
+
}
|
|
55
|
+
}
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
&.disabled {
|
|
59
|
+
.dx-toggle {
|
|
60
|
+
border-color: #e8eaed;
|
|
61
|
+
color: #ffffff;
|
|
62
|
+
cursor: not-allowed;
|
|
63
|
+
|
|
64
|
+
&:hover {
|
|
65
|
+
.slider {
|
|
66
|
+
border-color: transparent;
|
|
67
|
+
}
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
.slider {
|
|
71
|
+
color: #8a9a9e;
|
|
72
|
+
background-color: #e0e6e8;
|
|
73
|
+
}
|
|
74
|
+
}
|
|
75
|
+
}
|
|
76
|
+
}
|
|
@@ -0,0 +1,51 @@
|
|
|
1
|
+
import React, { useEffect, useState } from 'react';
|
|
2
|
+
import { GenesysDevIcon, GenesysDevIcons } from 'genesys-dev-icons';
|
|
3
|
+
import { BooleanChangedCallback, DxToggleProps } from '..';
|
|
4
|
+
|
|
5
|
+
import './DxToggle.scss';
|
|
6
|
+
import DxLabel from '../dxlabel/DxLabel';
|
|
7
|
+
|
|
8
|
+
export default function DxToggle(props: DxToggleProps) {
|
|
9
|
+
let initialValue: boolean | undefined = props.value !== undefined ? props.value : props.initialValue;
|
|
10
|
+
if (!props.isTriState) initialValue = initialValue || false;
|
|
11
|
+
|
|
12
|
+
const [value, setValue] = useState<boolean | undefined>(initialValue);
|
|
13
|
+
|
|
14
|
+
const trueIcon = props.trueIcon || GenesysDevIcons.AppCheck;
|
|
15
|
+
const falseIcon = props.falseIcon || GenesysDevIcons.AppTimes;
|
|
16
|
+
|
|
17
|
+
useEffect(() => {
|
|
18
|
+
if (props.initialValue || props.value === value || (!props.isTriState && props.value === undefined)) return;
|
|
19
|
+
setValue(props.value);
|
|
20
|
+
}, [props.value]);
|
|
21
|
+
|
|
22
|
+
useEffect(() => {
|
|
23
|
+
if (props.onChange) props.onChange(value);
|
|
24
|
+
// eslint-disable-next-line react-hooks/exhaustive-deps
|
|
25
|
+
}, [value]);
|
|
26
|
+
|
|
27
|
+
const toggleValue = () => {
|
|
28
|
+
if (props.disabled) return;
|
|
29
|
+
if (props.isTriState) {
|
|
30
|
+
if (value === undefined) setValue(true);
|
|
31
|
+
else if (value === true) setValue(false);
|
|
32
|
+
else setValue(undefined);
|
|
33
|
+
} else {
|
|
34
|
+
setValue(!value);
|
|
35
|
+
}
|
|
36
|
+
};
|
|
37
|
+
|
|
38
|
+
return (
|
|
39
|
+
<DxLabel label={props.label} description={props.description} className={props.className}>
|
|
40
|
+
<div className={`dx-toggle-container${props.disabled ? ' disabled' : ''}`}>
|
|
41
|
+
<div className='dx-toggle' onClick={toggleValue}>
|
|
42
|
+
{value !== false ? <GenesysDevIcon icon={falseIcon} /> : undefined}
|
|
43
|
+
{value === true && props.isTriState ? <div className='clear-placeholder'> </div> : undefined}
|
|
44
|
+
<div className='slider'>{value !== undefined ? <GenesysDevIcon icon={value ? trueIcon : falseIcon} /> : undefined}</div>
|
|
45
|
+
{value === false && props.isTriState ? <div className='clear-placeholder'> </div> : undefined}
|
|
46
|
+
{value !== true ? <GenesysDevIcon icon={trueIcon} /> : undefined}
|
|
47
|
+
</div>
|
|
48
|
+
</div>
|
|
49
|
+
</DxLabel>
|
|
50
|
+
);
|
|
51
|
+
}
|
package/src/index.ts
ADDED
|
@@ -0,0 +1,141 @@
|
|
|
1
|
+
import { GenesysDevIcons } from 'genesys-dev-icons';
|
|
2
|
+
import DxAccordion from './dxaccordion/DxAccordion';
|
|
3
|
+
import DxAccordionGroup from './dxaccordion/DxAccordionGroup';
|
|
4
|
+
import DxButton from './dxbutton/DxButton';
|
|
5
|
+
import DxItemGroup from './dxitemgroup/DxItemGroup';
|
|
6
|
+
import DxCheckbox from './dxitemgroup/DxCheckbox';
|
|
7
|
+
import DxLabel from './dxlabel/DxLabel';
|
|
8
|
+
import DxTabbedContent from './dxtabbedcontent/DxTabbedContent';
|
|
9
|
+
import DxTabPanel from './dxtabbedcontent/DxTabPanel';
|
|
10
|
+
import DxTextbox from './dxtextbox/DxTextbox';
|
|
11
|
+
import DxToggle from './dxtoggle/DxToggle';
|
|
12
|
+
import AlertBlock from './alertblock/AlertBlock';
|
|
13
|
+
import LoadingPlaceholder from './loadingplaceholder/LoadingPlaceholder';
|
|
14
|
+
import Tooltip from './tooltip/Tooltip';
|
|
15
|
+
import CopyButton from './copybutton/CopyButton';
|
|
16
|
+
|
|
17
|
+
export {
|
|
18
|
+
DxAccordion,
|
|
19
|
+
DxAccordionGroup,
|
|
20
|
+
DxButton,
|
|
21
|
+
DxItemGroup,
|
|
22
|
+
DxCheckbox,
|
|
23
|
+
DxLabel,
|
|
24
|
+
DxTabbedContent,
|
|
25
|
+
DxTabPanel,
|
|
26
|
+
DxTextbox,
|
|
27
|
+
DxToggle,
|
|
28
|
+
Tooltip,
|
|
29
|
+
CopyButton,
|
|
30
|
+
LoadingPlaceholder,
|
|
31
|
+
AlertBlock,
|
|
32
|
+
};
|
|
33
|
+
|
|
34
|
+
export interface StringChangedCallback {
|
|
35
|
+
(value: string): void;
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
export interface BooleanChangedCallback {
|
|
39
|
+
(value?: boolean): void;
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
export interface CheckedChangedCallback {
|
|
43
|
+
(checked: boolean): void;
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
export interface VoidEventCallback {
|
|
47
|
+
(): void;
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
// Item in a DxItemGroup
|
|
51
|
+
export interface DxItemGroupItem {
|
|
52
|
+
label: string;
|
|
53
|
+
value: string;
|
|
54
|
+
disabled?: boolean;
|
|
55
|
+
isSelected?: boolean;
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
// Item value of a DxItemGroupItem in a DxItemGroup
|
|
59
|
+
export interface DxItemGroupItemValue {
|
|
60
|
+
item: DxItemGroupItem;
|
|
61
|
+
isSelected: boolean;
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
export interface ItemChangedCallback {
|
|
65
|
+
(item: DxItemGroupItem, isSelected: boolean): void;
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
export interface ItemGroupChangedCallback {
|
|
69
|
+
(items: DxItemGroupItemValue[]): void;
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
export interface DxToggleProps {
|
|
73
|
+
isTriState?: boolean;
|
|
74
|
+
initialValue?: boolean;
|
|
75
|
+
value?: boolean;
|
|
76
|
+
label?: string;
|
|
77
|
+
description?: string;
|
|
78
|
+
trueIcon?: GenesysDevIcons;
|
|
79
|
+
falseIcon?: GenesysDevIcons;
|
|
80
|
+
disabled?: boolean;
|
|
81
|
+
onChange?: BooleanChangedCallback;
|
|
82
|
+
className?: string;
|
|
83
|
+
}
|
|
84
|
+
|
|
85
|
+
export type DxTextboxType = 'text' | 'textarea' | 'password' | 'email' | 'date' | 'datetime-local' | 'time' | 'integer' | 'decimal';
|
|
86
|
+
|
|
87
|
+
export interface DxTextboxProps {
|
|
88
|
+
initialValue?: string;
|
|
89
|
+
value?: string;
|
|
90
|
+
inputType?: DxTextboxType;
|
|
91
|
+
label?: string;
|
|
92
|
+
description?: string;
|
|
93
|
+
placeholder?: string;
|
|
94
|
+
icon?: GenesysDevIcons;
|
|
95
|
+
clearButton?: boolean;
|
|
96
|
+
onChange?: StringChangedCallback;
|
|
97
|
+
changeDebounceMs?: number;
|
|
98
|
+
inputRef?: React.RefObject<HTMLInputElement>;
|
|
99
|
+
onFocus?: VoidEventCallback;
|
|
100
|
+
onBlur?: VoidEventCallback;
|
|
101
|
+
disabled?: boolean;
|
|
102
|
+
className?: string;
|
|
103
|
+
autoFocus?: boolean;
|
|
104
|
+
}
|
|
105
|
+
|
|
106
|
+
export interface DxAccordionProps {
|
|
107
|
+
title: React.ReactNode;
|
|
108
|
+
children: React.ReactNode;
|
|
109
|
+
showOpen?: boolean;
|
|
110
|
+
className?: string;
|
|
111
|
+
expandTrigger?: any;
|
|
112
|
+
showOpenTrigger?: any;
|
|
113
|
+
containerId?: string;
|
|
114
|
+
headingIcon?: any;
|
|
115
|
+
headingColor?: string;
|
|
116
|
+
}
|
|
117
|
+
|
|
118
|
+
export interface DxItemGroupProps {
|
|
119
|
+
title?: string;
|
|
120
|
+
description?: string;
|
|
121
|
+
format: DxItemGroupFormat;
|
|
122
|
+
items: DxItemGroupItem[];
|
|
123
|
+
disabled?: boolean;
|
|
124
|
+
className?: string;
|
|
125
|
+
onItemChanged?: ItemChangedCallback;
|
|
126
|
+
onItemsChanged?: ItemGroupChangedCallback;
|
|
127
|
+
}
|
|
128
|
+
|
|
129
|
+
export type DxItemGroupFormat = 'checkbox' | 'radio' | 'dropdown' | 'multiselect';
|
|
130
|
+
|
|
131
|
+
export interface DxTabbedContentProps {
|
|
132
|
+
children: React.ReactNode;
|
|
133
|
+
initialTabId?: number;
|
|
134
|
+
className?: string;
|
|
135
|
+
}
|
|
136
|
+
|
|
137
|
+
export interface DxTabPanelProps {
|
|
138
|
+
title: React.ReactNode;
|
|
139
|
+
children: React.ReactNode;
|
|
140
|
+
className?: string;
|
|
141
|
+
}
|