genesys-react-components 0.1.6 → 0.2.0-devengage-1376.132

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 (37) hide show
  1. package/README.md +4 -0
  2. package/build/index.d.ts +1 -2
  3. package/build/index.js +6 -6
  4. package/build/index.js.map +1 -1
  5. package/package.json +52 -47
  6. package/src/alertblock/AlertBlock.scss +108 -0
  7. package/src/alertblock/AlertBlock.tsx +80 -0
  8. package/src/copybutton/CopyButton.scss +8 -0
  9. package/src/copybutton/CopyButton.tsx +42 -0
  10. package/src/dxaccordion/DxAccordion.scss +41 -0
  11. package/src/dxaccordion/DxAccordion.tsx +49 -0
  12. package/src/dxaccordion/DxAccordionGroup.scss +3 -0
  13. package/src/dxaccordion/DxAccordionGroup.tsx +12 -0
  14. package/src/dxbutton/DxButton.scss +79 -0
  15. package/src/dxbutton/DxButton.tsx +31 -0
  16. package/src/dxitemgroup/DxCheckbox.scss +145 -0
  17. package/src/dxitemgroup/DxCheckbox.tsx +46 -0
  18. package/src/dxitemgroup/DxItemGroup.scss +6 -0
  19. package/src/dxitemgroup/DxItemGroup.tsx +133 -0
  20. package/src/dxitemgroup/dropdown.scss +53 -0
  21. package/src/dxitemgroup/multiselect.scss +74 -0
  22. package/src/dxitemgroup/radiobutton.scss +2 -0
  23. package/src/dxlabel/DxLabel.scss +31 -0
  24. package/src/dxlabel/DxLabel.tsx +39 -0
  25. package/src/dxtabbedcontent/DxTabPanel.scss +0 -0
  26. package/src/dxtabbedcontent/DxTabPanel.tsx +8 -0
  27. package/src/dxtabbedcontent/DxTabbedContent.scss +45 -0
  28. package/src/dxtabbedcontent/DxTabbedContent.tsx +28 -0
  29. package/src/dxtextbox/DxTextbox.scss +107 -0
  30. package/src/dxtextbox/DxTextbox.tsx +159 -0
  31. package/src/dxtoggle/DxToggle.scss +76 -0
  32. package/src/dxtoggle/DxToggle.tsx +51 -0
  33. package/src/index.ts +141 -0
  34. package/src/loadingplaceholder/LoadingPlaceholder.scss +58 -0
  35. package/src/loadingplaceholder/LoadingPlaceholder.tsx +17 -0
  36. package/src/tooltip/Tooltip.scss +108 -0
  37. package/src/tooltip/Tooltip.tsx +46 -0
@@ -0,0 +1,74 @@
1
+ .dx-multiselect-group {
2
+ appearance: none;
3
+ position: relative;
4
+
5
+ select {
6
+ border: 1px solid #8a96a3;
7
+ border-radius: 2px;
8
+ background-color: #ffffff;
9
+ font-style: normal;
10
+ font-weight: 300;
11
+ font-size: 12px;
12
+ line-height: 14px;
13
+ color: #75757a;
14
+ width: 100%;
15
+ appearance: none;
16
+
17
+ &:focus-visible {
18
+ outline: 2px solid #aac9ff;
19
+ }
20
+
21
+ option {
22
+ overflow: hidden;
23
+ white-space: pre;
24
+ text-overflow: ellipsis;
25
+ -webkit-appearance: none;
26
+ font-style: normal;
27
+ font-weight: 300;
28
+ font-size: 12px;
29
+ line-height: 31px;
30
+ padding: 8px 12px;
31
+ color: #75757a;
32
+
33
+ &:checked {
34
+ background: #aac9ff -webkit-linear-gradient(bottom, #aac9ff 0%, #aac9ff 100%);
35
+ }
36
+
37
+ &:disabled {
38
+ color: #8a9a9e;
39
+ cursor: not-allowed;
40
+ }
41
+ }
42
+
43
+ // Webkit scrollbars (Chrome, Opera, Safari, Edge... every browser but firefox
44
+ // https://developer.mozilla.org/en-US/docs/Web/CSS/::-webkit-scrollbar
45
+ &::-webkit-scrollbar {
46
+ -webkit-appearance: none;
47
+ width: 7px;
48
+ height: 7px;
49
+ }
50
+ &::-webkit-scrollbar-thumb {
51
+ border-radius: 4px;
52
+ background-color: #b0b2b5;
53
+ }
54
+ &::-webkit-scrollbar-corner {
55
+ background: transparent;
56
+ }
57
+
58
+ // Just firefox
59
+ // https://developer.mozilla.org/en-US/docs/Web/CSS/scrollbar-color
60
+ scrollbar-color: #b0b2b5 transparent;
61
+ }
62
+
63
+ &.disabled {
64
+ select:disabled {
65
+ background-color: #e6ebec;
66
+ border-color: #e8eaed;
67
+ cursor: not-allowed;
68
+
69
+ option {
70
+ color: #8a9a9e;
71
+ }
72
+ }
73
+ }
74
+ }
@@ -0,0 +1,2 @@
1
+ .dx-item-group {
2
+ }
@@ -0,0 +1,31 @@
1
+ .dx-label {
2
+ margin: 20px 0;
3
+ display: block;
4
+
5
+ .label-text,
6
+ .input-description {
7
+ display: block;
8
+ font-family: Roboto;
9
+ font-style: normal;
10
+ font-weight: 400;
11
+ font-size: 12px;
12
+ line-height: 14px;
13
+ color: #75757a;
14
+ }
15
+
16
+ .label-text {
17
+ margin: 0 0 4px 0;
18
+ }
19
+
20
+ .input-description {
21
+ padding: 6px 20px;
22
+ display: flex;
23
+ flex-flow: row nowrap;
24
+ gap: 8px;
25
+
26
+ .icon {
27
+ color: #597393;
28
+ line-height: 0;
29
+ }
30
+ }
31
+ }
@@ -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'>&nbsp;</div> : undefined}
44
+ <div className='slider'>{value !== undefined ? <GenesysDevIcon icon={value ? trueIcon : falseIcon} /> : undefined}</div>
45
+ {value === false && props.isTriState ? <div className='clear-placeholder'>&nbsp;</div> : undefined}
46
+ {value !== true ? <GenesysDevIcon icon={trueIcon} /> : undefined}
47
+ </div>
48
+ </div>
49
+ </DxLabel>
50
+ );
51
+ }