@dvrd/dvr-controls 0.0.26 → 0.0.30

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/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@dvrd/dvr-controls",
3
- "version": "0.0.26",
3
+ "version": "0.0.30",
4
4
  "description": "Custom web controls",
5
5
  "main": "index.ts",
6
6
  "scripts": {},
@@ -10,98 +10,33 @@
10
10
  },
11
11
  "author": "Dave van Rijn",
12
12
  "license": "ISC",
13
- "dependencies": {
14
- "@sentry/browser": "^6.2.1",
15
- "@types/js-cookie": "^2.2.6",
16
- "@types/lodash": "^4.14.168",
17
- "@types/node": "14.14.32",
18
- "@types/react": "~17.0.2",
19
- "@types/react-dom": "17.0.1",
20
- "@types/react-router-dom": "~5.1.6",
21
- "@types/uuid": "^8.3.0",
22
- "@types/react-color": "^3.0.4",
23
- "@types/dompurify": "2.2.1",
24
- "awesome-typescript-loader": "^5.2.1",
25
- "classnames": "^2.2.6",
26
- "compression-webpack-plugin": "^7.1.2",
27
- "cross-env": "^7.0.3",
28
- "css-loader": "^5.1.1",
29
- "cssnano": "^4.1.10",
30
- "cssnano-preset-advanced": "^4.0.7",
31
- "file-loader": "^6.2.0",
32
- "html-webpack-plugin": "^5.3.0",
33
- "js-cookie": "^2.2.1",
34
- "lodash": "^4.17.21",
35
- "mini-css-extract-plugin": "^1.3.9",
36
- "moment": "^2.29.1",
37
- "optimize-css-assets-webpack-plugin": "^5.0.4",
38
- "prerender-spa-plugin": "^3.4.0",
39
- "query-string": "^6.14.1",
40
- "react": "^17.0.1",
41
- "react-color": "^2.19.3",
42
- "react-dom": "^17.0.1",
43
- "react-router-dom": "^5.2.0",
44
- "sass-loader": "^11.0.1",
45
- "seamless-scroll-polyfill": "^1.2.3",
46
- "style-loader": "^2.0.0",
47
- "terser-webpack-plugin": "^5.1.1",
48
- "typescript": "^4.2.3",
49
- "uglifyjs-webpack-plugin": "^2.2.0",
50
- "uuid": "^8.3.2",
51
- "webpack": "^5.24.4",
52
- "webpack-cli": "^4.5.0",
53
- "source-map-loader": "^2.0.1",
54
- "@types/react-helmet": "^6.1.0",
55
- "react-helmet": "^6.1.0",
56
- "@sentry/react": "^6.2.1",
57
- "dompurify": "^2.2.6",
58
- "react-rnd": "^10.2.4"
59
- },
60
13
  "browserslist": {
61
14
  "0": ">0.2%",
62
15
  "1": "not dead",
63
16
  "2": "ie >= 11"
64
17
  },
65
18
  "devDependencies": {
66
- "@sentry/react": "^6.2.2",
67
19
  "@types/js-cookie": "^2.2.6",
68
20
  "@types/lodash": "^4.14.168",
69
21
  "@types/node": "^14.14.34",
70
22
  "@types/react": "^17.0.3",
71
23
  "@types/react-dom": "^17.0.2",
72
- "@types/react-helmet": "^6.1.0",
73
24
  "@types/react-router-dom": "^5.1.7",
74
25
  "@types/uuid": "^8.3.0",
75
- "awesome-typescript-loader": "^5.2.1",
26
+ "@types/react-color": "^3.0.6",
27
+ "@types/dompurify": "^2.2.3",
76
28
  "classnames": "^2.2.6",
77
- "compression-webpack-plugin": "^7.1.2",
78
29
  "cross-env": "^7.0.3",
79
- "css-loader": "^5.1.2",
80
- "cssnano": "^4.1.10",
81
- "cssnano-preset-advanced": "^4.0.7",
82
- "file-loader": "^6.2.0",
83
- "html-webpack-plugin": "^5.3.1",
84
30
  "js-cookie": "^2.2.1",
85
31
  "lodash": "^4.17.21",
86
- "mini-css-extract-plugin": "^1.3.9",
87
32
  "moment": "^2.29.1",
88
- "optimize-css-assets-webpack-plugin": "^5.0.4",
89
- "prerender-spa-plugin-next": "^4.1.5",
90
- "query-string": "^6.14.1",
91
33
  "react": "^17.0.1",
92
34
  "react-dom": "^17.0.1",
93
- "react-helmet": "^6.1.0",
35
+ "react-color": "^2.19.3",
94
36
  "react-router-dom": "^5.2.0",
95
- "sass-loader": "^11.1.0",
96
- "seamless-scroll-polyfill": "^1.2.3",
97
- "source-map-loader": "^2.0.1",
98
- "style-loader": "^2.0.0",
99
- "terser-webpack-plugin": "^5.1.1",
37
+ "react-rnd": "^10.3.5",
100
38
  "typescript": "^4.2.3",
101
- "uglifyjs-webpack-plugin": "^2.2.0",
102
39
  "uuid": "^8.3.2",
103
- "webpack": "^5.25.1",
104
- "webpack-cli": "^4.5.0",
105
- "webpack-dev-server": "^4.3.1"
40
+ "dompurify": "^2.3.3"
106
41
  }
107
42
  }
@@ -31,37 +31,91 @@ function getBottomItems(items: SidebarItem[]): SidebarItem[] {
31
31
  return items.filter((item: SidebarItem) => item.onBottom)
32
32
  }
33
33
 
34
+ function getActiveItem(items: SidebarItem[], pathname: string): SidebarItem | null {
35
+ for (const item of items) {
36
+ if (itemIsActive(item, pathname)) return item;
37
+ if (Array.isArray(item.children)) {
38
+ const activeItem = getActiveItem(item.children, pathname);
39
+ if (activeItem) return activeItem;
40
+ }
41
+ }
42
+ return null;
43
+ }
44
+
45
+ function itemIsActive(item: SidebarItem, pathname: string): boolean {
46
+ if (Array.isArray(item.route) && item.route.includes(pathname)) return true;
47
+ else if (item.route === pathname) return true;
48
+ else if (typeof item.route === 'string' && item.exactRoute === false && pathname.includes(item.route)) return true;
49
+ return false;
50
+ }
51
+
52
+ function itemHasActiveId(item: SidebarItem, activeId: string): boolean {
53
+ if (item.id === activeId) return true;
54
+ else if (Array.isArray(item.children) && item.children.find((child: SidebarItem) => itemHasActiveId(child, activeId))) return true;
55
+ return false;
56
+ }
57
+
34
58
  export default function SidebarMenu(props: Props) {
35
59
  const context = useContext(ControlContext),
36
60
  location = useLocation(),
37
- {className, mode, contrastColor, baseColor, items, onClickItem} = props,
61
+ {className, contrastColor, baseColor, items, onClickItem} = props,
62
+ mode = props.mode ?? SideMenuMode.COMPACT,
38
63
  [activeItem, setActiveItem] = useState(props.activeItem ?? ''),
39
64
  sideBar = useRef<HTMLDivElement>(null),
40
65
  componentId = useRef(generateComponentId(props.id));
41
66
 
42
67
  function _onClickItem(item: SidebarItem) {
43
68
  return function (evt: React.MouseEvent) {
69
+ evt.stopPropagation();
44
70
  setActiveItem(item.id);
45
71
  onClickItem(item)(evt);
46
72
  }
47
73
  }
48
74
 
49
- function renderItem(item: SidebarItem) {
50
- const {className, icon, id, label} = item,
51
- cls = classNames(className, mode === SideMenuMode.COMPACT ? 'side-bar-item' : 'side-bar-item-full',
52
- activeItem === id && 'active');
53
- return (
54
- <div key={id} className={cls} onClick={_onClickItem(item)}>
55
- {renderIcon(label, icon)}
56
- {mode === SideMenuMode.COMPACT && <div className='active-indicator'/>}
57
- <span className='item-label'>{label}</span>
58
- </div>
59
- )
75
+ function renderItem(isChild: boolean = false) {
76
+ return function (item: SidebarItem) {
77
+ const {className, icon, id, label, children} = item,
78
+ isActive = itemHasActiveId(item, activeItem),
79
+ cls = classNames(className, mode === SideMenuMode.COMPACT ? 'side-bar-item' : 'side-bar-item-full',
80
+ isChild && 'child', children !== undefined && 'with-children');
81
+ return (
82
+ <div key={id} className={cls} onClick={_onClickItem(item)}>
83
+ {renderIcon(isActive, isChild, label, icon)}
84
+ {mode === SideMenuMode.COMPACT && <div className='active-indicator'/>}
85
+ <span className={classNames('item-label', isActive && 'active')}>{label}</span>
86
+ {children !== undefined && (
87
+ <>
88
+ {isActive && <div className='line'/>}
89
+ {renderChildren(isActive)(children)}
90
+ </>
91
+ )}
92
+ </div>
93
+ )
94
+ }
60
95
  }
61
96
 
62
- function renderIcon(label: string, icon?: string | ReactNode): ReactNode {
63
- if (icon) return typeof icon === 'string' ? <AwesomeIcon name={icon} className='item-icon'/> : icon;
64
- if (label.length) return <span className='item-icon letter'>{label[0]}</span>
97
+ function renderChildren(isActive: boolean) {
98
+ return function (children: SidebarItem[]) {
99
+ const display = isActive ? 'block' : 'none';
100
+ return (
101
+ <div className='children-container' style={{display}}>
102
+ {children.map(renderItem(true))}
103
+ </div>
104
+ )
105
+ }
106
+ }
107
+
108
+ function renderIcon(isActive: boolean, isChild: boolean, label: string, icon?: string | ReactNode): ReactNode {
109
+ const className = classNames('item-icon', isActive && 'active');
110
+ if (icon) {
111
+ if (typeof icon === 'string') return <AwesomeIcon name={icon} className={className}/>;
112
+ else if (React.isValidElement(icon))
113
+ return React.cloneElement(icon, {className: classNames(className, icon.props.className)});
114
+ }
115
+ if (label.length) {
116
+ if (isChild) return <span/>;
117
+ return <span className={classNames(className, 'letter')}>{label[0]}</span>
118
+ }
65
119
  return null;
66
120
  }
67
121
 
@@ -77,26 +131,10 @@ export default function SidebarMenu(props: Props) {
77
131
 
78
132
  function _setActiveItem() {
79
133
  const {pathname} = location;
80
- console.log(pathname);
81
- for (const item of items) {
82
- let found: boolean = false;
83
- if (item.route) {
84
- if (Array.isArray(item.route) && item.route.includes(pathname)) found = true;
85
- else if (item.route === pathname) found = true;
86
- else if (typeof item.route === 'string' && item.exactRoute === false && pathname.includes(item.route)) found = true;
87
- if (found) {
88
- setActiveItem(item.id);
89
- return;
90
- }
91
- }
92
- }
134
+ const activeItem = getActiveItem(items, pathname);
135
+ if (activeItem) setActiveItem(activeItem.id);
93
136
  }
94
137
 
95
- // function getBarWidth(): number {
96
- // if (sideBar.current) return sideBar.current.getBoundingClientRect().width;
97
- // return 0;
98
- // }
99
-
100
138
  useEffect(() => {
101
139
  setColors();
102
140
  defer(_setActiveItem);
@@ -110,112 +148,11 @@ export default function SidebarMenu(props: Props) {
110
148
  <div className={classNames(className, 'dvr-side-bar-menu', mode === SideMenuMode.FULL && 'full')}
111
149
  ref={sideBar} id={componentId.current}>
112
150
  <div>
113
- {getTopItems(items).map(renderItem)}
151
+ {getTopItems(items).map(renderItem())}
114
152
  </div>
115
153
  <div>
116
- {getBottomItems(items).map(renderItem)}
154
+ {getBottomItems(items).map(renderItem())}
117
155
  </div>
118
156
  </div>
119
157
  )
120
- }
121
-
122
- // class SidebarMenu extends PureComponent<Props, State> {
123
- // static contextType = ControlContext;
124
- // static defaultProps = {
125
- // controlled: false,
126
- // mode: SideMenuMode.COMPACT,
127
- // }
128
- //
129
- // private bar: HTMLDivElement;
130
- // private readonly id = generateComponentId(this.props.id);
131
- // state: State = {
132
- // activeItem: this.props.activeItem || '',
133
- // };
134
- //
135
- // getTopItems = (): SidebarItem[] => this.props.items.filter((item: SidebarItem) => !item.onBottom)
136
- // getBottomItems = (): SidebarItem[] => this.props.items.filter((item: SidebarItem) => item.onBottom)
137
- //
138
- // renderItem = (item: SidebarItem) => {
139
- // const {className, icon, id, label} = item, {onClickItem, mode} = this.props, {activeItem} = this.state;
140
- // return (
141
- // <div key={id}
142
- // className={classNames(className, mode === SideMenuMode.COMPACT ? 'side-bar-item' : 'side-bar-item-full', activeItem === id && 'active')}
143
- // onClick={onClickItem(item)}>
144
- // {this.renderIcon(label, icon)}
145
- // {mode === SideMenuMode.COMPACT && <div className='active-indicator'/>}
146
- // <span className='item-label'>{label}</span>
147
- // </div>
148
- // )
149
- // };
150
- //
151
- // renderIcon = (label: string, icon?: string | React.ReactNode): React.ReactNode => {
152
- // if (icon) return typeof icon === 'string' ? <AwesomeIcon name={icon} className='item-icon'/> : icon;
153
- // if (label.length) return <span className='item-icon letter'>{label[0]}</span>
154
- // return null;
155
- // };
156
- //
157
- // setColorVars = () => {
158
- // const {baseColor, contrastColor} = this.props;
159
- // if (this.bar) {
160
- // const base: string = baseColor || this.context.baseColor,
161
- // contrast: string = contrastColor || this.context.contrastColor;
162
- // this.bar.style.setProperty('--base-color', base);
163
- // this.bar.style.setProperty('--contrast-color', contrast);
164
- // }
165
- // };
166
- //
167
- // setActiveItem = () => {
168
- // const route = this.props.location.pathname, {items} = this.props;
169
- // for (const item of items) {
170
- // let found: boolean = false;
171
- // if (item.route) {
172
- // if (Array.isArray(item.route) && item.route.includes(route)) found = true;
173
- // else if (item.route === route) found = true;
174
- // else if (typeof item.route === 'string' && item.exactRoute === false && route.includes(item.route)) found = true;
175
- // if (found) {
176
- // this.setState({activeItem: item.id});
177
- // return;
178
- // }
179
- // }
180
- // }
181
- // }
182
- //
183
- // getWidth = (): number => {
184
- // if (this.bar) return this.bar.getBoundingClientRect().width;
185
- // return 0;
186
- // };
187
- //
188
- // componentDidMount = () => {
189
- // this.setColorVars();
190
- // directTimeout(this.setActiveItem);
191
- // };
192
- //
193
- // componentDidUpdate = (prevProps: Props) => {
194
- // const {activeItem, controlled, location} = this.props, prevItem = prevProps.activeItem,
195
- // prevLocation = prevProps.location;
196
- // if (controlled) {
197
- // if (activeItem !== prevItem) this.setState({activeItem: activeItem || ''});
198
- // } else {
199
- // if (location.pathname !== prevLocation.pathname) this.setActiveItem();
200
- // }
201
- // }
202
- //
203
- // render = () => {
204
- // const {className, mode} = this.props;
205
- // return (
206
- // <div className={classNames(className, 'dvr-side-bar-menu', mode === SideMenuMode.FULL && 'full')}
207
- // ref={(ref: HTMLDivElement) => {
208
- // this.bar = ref
209
- // }} id={this.id}>
210
- // <div>
211
- // {this.getTopItems().map(this.renderItem)}
212
- // </div>
213
- // <div>
214
- // {this.getBottomItems().map(this.renderItem)}
215
- // </div>
216
- // </div>
217
- // )
218
- // };
219
- // }
220
- //
221
- // export default withRouter(SidebarMenu);
158
+ }
@@ -98,6 +98,7 @@
98
98
  margin: 2rem 1rem;
99
99
  align-items: center;
100
100
  cursor: pointer;
101
+ position: relative;
101
102
 
102
103
  .item-icon {
103
104
  color: #686869;
@@ -105,23 +106,44 @@
105
106
  transition: color .2s ease-in-out;
106
107
  justify-self: center;
107
108
  opacity: .5;
109
+
110
+ &.active {
111
+ color: var(--contrast-color);
112
+ opacity: 1;
113
+ }
108
114
  }
109
115
 
110
116
  .item-label {
111
117
  color: #686869;
112
118
  transition: color .2s ease-in-out;
113
119
  white-space: nowrap;
114
- }
115
120
 
116
- &.active {
117
- .item-icon {
118
- color: var(--contrast-color);
119
- opacity: 1;
121
+ &.active {
122
+ font-weight: 600;
123
+ color: black;
120
124
  }
125
+ }
121
126
 
127
+ .line {
128
+ width: 2px;
129
+ position: absolute;
130
+ height: calc(100% - 1.5rem);
131
+ top: 2rem;
132
+ left: 1rem;
133
+ background-color: var(--contrast-color);
134
+ }
135
+
136
+ &.child {
122
137
  .item-label {
123
- font-weight: 600;
124
- color: black;
138
+ padding-left: 1rem;
139
+ }
140
+ }
141
+
142
+ .children-container {
143
+ padding-top: 1rem;
144
+
145
+ .side-bar-item-full {
146
+ margin: 0;
125
147
  }
126
148
  }
127
149
 
@@ -130,6 +152,10 @@
130
152
  color: black;
131
153
  }
132
154
  }
155
+
156
+ &.with-children {
157
+ margin-bottom: -.5rem;
158
+ }
133
159
  }
134
160
  }
135
161
  }
@@ -6,6 +6,7 @@ import React from 'react';
6
6
  import {Snackbar} from "./snackbar";
7
7
  import {CustomAppEvent, DialogConfig, Snack} from "../util/interfaces";
8
8
  import WithEvents from '../events/withEvents';
9
+ import { delay } from 'lodash';
9
10
 
10
11
  interface Props {
11
12
  containerClass: string;
@@ -13,6 +14,8 @@ interface Props {
13
14
  activeTime: number;
14
15
  backgroundColor?: string;
15
16
  textColor?: string;
17
+ maxSnacks?: number;
18
+ noDuplicates?: boolean;
16
19
  }
17
20
 
18
21
  interface State {
@@ -28,7 +31,7 @@ export default class SnackbarController extends React.Component<Props, State> {
28
31
  textClass: '',
29
32
  };
30
33
 
31
- state = {
34
+ state: State = {
32
35
  active: false,
33
36
  snack: null,
34
37
  config: {}
@@ -38,7 +41,12 @@ export default class SnackbarController extends React.Component<Props, State> {
38
41
  timeout: number | null = null;
39
42
 
40
43
  onAddSnack = (snack: Snack) => {
44
+ const {maxSnacks, noDuplicates} = this.props;
45
+ if (noDuplicates && this.isDuplicate(snack)) return;
41
46
  this.snackQueue.push(snack);
47
+ if (maxSnacks !== undefined)
48
+ while (this.snackQueue.length > maxSnacks - 1)
49
+ this.snackQueue.shift();
42
50
  if (!this.state.active)
43
51
  this.activate();
44
52
  };
@@ -49,10 +57,19 @@ export default class SnackbarController extends React.Component<Props, State> {
49
57
  this.deactivate();
50
58
  };
51
59
 
60
+ isDuplicate = (snack: Snack): boolean => {
61
+ return this.state.snack?.text === snack.text || this.snackQueue.pop()?.text === snack.text;
62
+ }
63
+
52
64
  deactivate = () => {
53
65
  this.setState({active: false}, () => {
54
- if (this.snackQueue.length > 0)
55
- this.timeout = window.setTimeout(this.activate, 500);
66
+ delay(() => {
67
+ // Clear snack after 200ms (css transition)
68
+ this.setState({snack: null}, () => {
69
+ if (this.snackQueue.length > 0)
70
+ this.timeout = window.setTimeout(this.activate, 500);
71
+ })
72
+ }, 200);
56
73
  })
57
74
  };
58
75
 
@@ -8,14 +8,14 @@ import React, {
8
8
  PureComponent
9
9
  } from 'react';
10
10
  import classNames from "classnames";
11
- import {ElementPosition, ErrorType, OrnamentShape } from '../util/interfaces';
11
+ import {ElementPosition, ErrorType, OrnamentShape} from '../util/interfaces';
12
12
  import AwesomeIcon from '../icon/awesomeIcon';
13
- import { directTimeout } from '../util/componentUtil';
13
+ import {directTimeout} from '../util/componentUtil';
14
14
 
15
15
  interface Props {
16
16
  onChange: ChangeEventHandler;
17
- onFocus: FocusEventHandler;
18
- onBlur: FocusEventHandler;
17
+ onFocus?: FocusEventHandler;
18
+ onBlur?: FocusEventHandler;
19
19
  onKeyDown: KeyboardEventHandler;
20
20
  onClearInput?: MouseEventHandler;
21
21
  value: string | number;
@@ -62,13 +62,15 @@ export default class DvrdInput extends PureComponent<Props, State> {
62
62
  this.input.selectionEnd = value.toString().length;
63
63
  }
64
64
  }
65
- onFocus(evt);
65
+ if (onFocus)
66
+ onFocus(evt);
66
67
  };
67
68
 
68
69
  onBlurInput = (evt: React.FocusEvent) => {
69
70
  const {disabled, onBlur} = this.props;
70
71
  if (!disabled) this.setState({active: false});
71
- onBlur(evt);
72
+ if (onBlur)
73
+ onBlur(evt);
72
74
  };
73
75
 
74
76
  hasError = (): boolean => this.props.error !== undefined && this.props.error !== null;
@@ -3,8 +3,14 @@
3
3
  */
4
4
 
5
5
  import React, {
6
- FocusEventHandler, InputHTMLAttributes, KeyboardEventHandler, MouseEventHandler, PureComponent,
7
- TextareaHTMLAttributes
6
+ FocusEventHandler,
7
+ InputHTMLAttributes,
8
+ KeyboardEventHandler,
9
+ MouseEventHandler,
10
+ TextareaHTMLAttributes,
11
+ useEffect,
12
+ useRef,
13
+ useState
8
14
  } from 'react';
9
15
  import {generateComponentId} from '../util/componentUtil';
10
16
  import {enterPressed} from '../util/controlUtil';
@@ -40,62 +46,52 @@ export interface InputControllerProps {
40
46
  step?: number;
41
47
  area?: boolean;
42
48
  noResize?: boolean;
49
+ unControlled?: boolean;
43
50
  }
44
51
 
45
- export default class DvrdInputController extends PureComponent<InputControllerProps> {
46
- private readonly id: string = generateComponentId(this.props.id);
52
+ export default function DvrdInputController(props: InputControllerProps) {
53
+ const {
54
+ disabled, onChange, onEnter, onKeyDown, inputProps, placeholder, type, max, min, step, onFocus, onBlur,
55
+ autoFocus, error, label, ornaments, className, inputClassName, labelClassName, ornamentClassName, fullWidth,
56
+ errorClassName, autoSelect, area, noResize, onClearInput, unControlled
57
+ } = props,
58
+ componentId = useRef(generateComponentId(props.id)),
59
+ [value, setValue] = useState(props.value);
47
60
 
48
- // noinspection JSUnusedGlobalSymbols
49
- public getInput = (): HTMLInputElement | null =>
50
- document.getElementById(`${this.id}-input`) as HTMLInputElement | null;
51
-
52
- onChange = (evt: React.ChangeEvent<HTMLInputElement>) => {
53
- const {value} = evt.target, {disabled, onChange} = this.props;
54
- if (!disabled) onChange(value, evt);
55
- };
56
-
57
- onKeyDown = (evt: React.KeyboardEvent) => {
58
- const {onEnter, disabled, onKeyDown} = this.props;
59
- if (!disabled) {
60
- if (enterPressed(evt) && onEnter) onEnter(evt);
61
- else if (onKeyDown) onKeyDown(evt);
62
- }
63
- };
64
-
65
- onFocus = (evt: React.FocusEvent) => {
66
- const {onFocus} = this.props;
67
- if (onFocus) onFocus(evt);
68
- };
61
+ function _onChange(evt: React.ChangeEvent<HTMLInputElement | HTMLTextAreaElement>) {
62
+ if (disabled) return;
63
+ const {value} = evt.target;
64
+ setValue(value);
65
+ onChange(value, evt);
66
+ }
69
67
 
70
- onBlur = (evt: React.FocusEvent) => {
71
- const {onBlur} = this.props;
72
- if (onBlur) onBlur(evt);
73
- };
68
+ function _onKeyDown(evt: React.KeyboardEvent<HTMLInputElement | HTMLTextAreaElement>) {
69
+ if (disabled) return;
70
+ if (onEnter && enterPressed(evt)) onEnter(evt);
71
+ else if (onKeyDown) onKeyDown(evt);
72
+ }
74
73
 
75
- getInputProps = (): InputHTMLAttributes<any> | undefined => {
76
- const {inputProps, placeholder, type, max, min, step} = this.props;
74
+ function getInputProps(): InputHTMLAttributes<any> | undefined {
77
75
  if (!inputProps && !placeholder && !type) return undefined;
78
76
  const props: InputHTMLAttributes<any> = inputProps ?? {};
79
- props.placeholder = placeholder ?? props.placeholder;
80
- props.type = type ?? props.type;
81
- props.max = max ?? props.max;
82
- props.min = min ?? props.min;
83
- props.step = step ?? props.step;
77
+ if (placeholder !== undefined) props.placeholder = placeholder;
78
+ if (type !== undefined) props.type = type;
79
+ if (max !== undefined) props.max = max;
80
+ if (min !== undefined) props.min = min;
81
+ if (step !== undefined) props.step = step;
84
82
  return props;
85
- };
86
-
87
- render = () => {
88
- const {
89
- value, label, ornaments, disabled, autoFocus, className, inputClassName, labelClassName,
90
- ornamentClassName, error, errorClassName, autoSelect, fullWidth, area, noResize, onClearInput
91
- } = this.props;
92
- return (
93
- <DvrdInput onChange={this.onChange} onFocus={this.onFocus} onKeyDown={this.onKeyDown} value={value}
94
- disabled={disabled} autoFocus={autoFocus} error={error} label={label} ornaments={ornaments}
95
- inputProps={this.getInputProps()} className={className} inputClassName={inputClassName}
96
- labelClassName={labelClassName} ornamentClassName={ornamentClassName} fullWidth={fullWidth}
97
- errorClassName={errorClassName} id={this.id} onBlur={this.onBlur} autoSelect={autoSelect}
98
- area={area} noResize={noResize} onClearInput={onClearInput}/>
99
- )
100
83
  }
84
+
85
+ useEffect(() => {
86
+ if(!unControlled) setValue(props.value);
87
+ }, [props.value])
88
+
89
+ return (
90
+ <DvrdInput onChange={_onChange} onFocus={onFocus} onKeyDown={_onKeyDown} value={value}
91
+ disabled={disabled} autoFocus={autoFocus} error={error} label={label} ornaments={ornaments}
92
+ inputProps={getInputProps()} className={className} inputClassName={inputClassName}
93
+ labelClassName={labelClassName} ornamentClassName={ornamentClassName} fullWidth={fullWidth}
94
+ errorClassName={errorClassName} id={componentId.current} onBlur={onBlur} autoSelect={autoSelect}
95
+ area={area} noResize={noResize} onClearInput={onClearInput}/>
96
+ );
101
97
  }
@@ -26,16 +26,21 @@ let abortController: AbortController;
26
26
  let signal: AbortSignal;
27
27
  let defaultHeaders: OutgoingHttpHeaders = {};
28
28
 
29
- const getSignal = (): AbortSignal | null => {
30
- if ("AbortController" in window) {
31
- if (!abortController)
32
- abortController = new AbortController;
33
- if (!signal)
34
- signal = abortController.signal;
35
- return signal;
36
- }
37
- return null;
38
- };
29
+ // const getSignal = (): AbortSignal | null => {
30
+ // if ("AbortController" in window) {
31
+ // if (!abortController)
32
+ // abortController = new AbortController;
33
+ // if (!signal)
34
+ // signal = abortController.signal;
35
+ // return signal;
36
+ // }
37
+ // return null;
38
+ // };
39
+
40
+ function getAbortController(): AbortController | null {
41
+ if (!('AbortController' in window)) return null;
42
+ return new AbortController();
43
+ }
39
44
 
40
45
  const responseDataIsSuccess = (data: ResponseData): boolean => data.status === 'success';
41
46
 
@@ -54,7 +59,7 @@ export const cancelAllFetch = () => {
54
59
  }
55
60
  };
56
61
 
57
- export const sendFetch = (config: FetchOptions, legacySupport: boolean = false) => {
62
+ export const sendFetch = (config: FetchOptions, legacySupport: boolean = false): AbortController | null => {
58
63
  config = createFetchConfig(config, legacySupport);
59
64
  const {url, method, headers, data} = config, options: { [index: string]: any } = {
60
65
  headers,
@@ -63,7 +68,9 @@ export const sendFetch = (config: FetchOptions, legacySupport: boolean = false)
63
68
  cache: 'no-store',
64
69
  }, baseUrl = config.baseUrl || window.settings.platformUrl;
65
70
  if (!baseUrl) throw new Error('Base url is not set!');
66
- if (getSignal()) options['signal'] = getSignal();
71
+ const abortController = getAbortController();
72
+ if(abortController) options.signal = abortController.signal;
73
+ // if (getSignal()) options['signal'] = getSignal();
67
74
  options['mode'] = 'cors';
68
75
  fetch(baseUrl + url, options).then((response: Response) => {
69
76
  const {status} = response;
@@ -101,10 +108,12 @@ export const sendFetch = (config: FetchOptions, legacySupport: boolean = false)
101
108
  }
102
109
  }
103
110
  }).catch((reason: any) => {
104
- if (reason.code === DOMException.ABORT_ERR) {/*Request aborted*/} else if (config.errorCallback) {
111
+ if (reason.code === DOMException.ABORT_ERR) {/*Request aborted*/
112
+ } else if (config.errorCallback) {
105
113
  config.errorCallback(reason);
106
114
  }
107
115
  });
116
+ return abortController;
108
117
  };
109
118
 
110
119
  const createFetchConfig = (options: FetchOptions, legacySupport: boolean = true): FetchOptions => {