@dvrd/dvr-controls 1.0.14 → 1.0.16
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/index.ts +8 -1
- package/package.json +29 -23
- package/src/js/button/button.tsx +102 -0
- package/src/js/button/buttonController.tsx +179 -0
- package/src/js/button/closeButton.tsx +29 -0
- package/src/js/button/dvrdButton.tsx +128 -0
- package/src/js/button/outlinedButton.tsx +105 -0
- package/src/js/button/simpleButton.tsx +163 -0
- package/src/js/button/style/button.scss +95 -0
- package/src/js/button/style/closeButton.scss +15 -0
- package/src/js/button/style/dvrdButton.scss +30 -0
- package/src/js/button/style/outlinedButton.scss +84 -0
- package/src/js/button/style/simpleButton.scss +80 -0
- package/src/js/carousel/DVRCarousel.tsx +163 -0
- package/src/js/carousel/DVRCarouselController.tsx +95 -0
- package/src/js/carousel/style/DVRCarousel.scss +38 -0
- package/src/js/checkbox/checkbox.tsx +148 -0
- package/src/js/checkbox/checkboxController.tsx +131 -0
- package/src/js/checkbox/style/checkbox.scss +109 -0
- package/src/js/colorPicker/colorPicker.tsx +118 -0
- package/src/js/colorPicker/style/colorPicker.scss +20 -0
- package/src/js/date/dvrdDatePicker.tsx +357 -0
- package/src/js/date/style/dvrdDatePicker.scss +307 -0
- package/src/js/dialog/dialog.tsx +207 -0
- package/src/js/dialog/dialogController.tsx +70 -0
- package/src/js/dialog/inlineDialog.tsx +127 -0
- package/src/js/dialog/style/dialog.scss +61 -0
- package/src/js/events/withEvents.tsx +40 -0
- package/src/js/head/DVRHead.tsx +49 -0
- package/src/js/header/DVRHeader.tsx +417 -0
- package/src/js/header/style/header.scss +206 -0
- package/src/js/icon/awesomeIcon.tsx +20 -0
- package/src/js/image/imageUpload.tsx +69 -0
- package/src/js/image/style/imageUpload.scss +11 -0
- package/src/js/info/info.tsx +136 -0
- package/src/js/info/style/info.scss +39 -0
- package/src/js/input/animated/animatedTextField.tsx +159 -0
- package/src/js/input/date/dateField.tsx +360 -0
- package/src/js/input/date/dateFieldController.tsx +245 -0
- package/src/js/input/date/datePicker/datePicker.tsx +186 -0
- package/src/js/input/date/datePicker/style/datePicker.scss +102 -0
- package/src/js/input/date/input/dateInput.tsx +214 -0
- package/src/js/input/date/style/dateField.scss +40 -0
- package/src/js/input/date/timePicker/style/timePicker.scss +95 -0
- package/src/js/input/date/timePicker/timePicker.tsx +143 -0
- package/src/js/input/editor/DVREditor.tsx +21 -0
- package/src/js/input/number/numberInput.tsx +157 -0
- package/src/js/input/password/passwordInput.tsx +140 -0
- package/src/js/input/password/passwordRules.tsx +48 -0
- package/src/js/input/password/style/passwordInput.scss +39 -0
- package/src/js/input/password/style/passwordRules.scss +41 -0
- package/src/js/input/simple/style/simpleInput.scss +98 -0
- package/src/js/input/simple/v2/simpleInputV2.tsx +178 -0
- package/src/js/input/style/input.scss +138 -0
- package/src/js/input/v2/inputController_v2.tsx +250 -0
- package/src/js/input/v2/input_v2.tsx +7 -0
- package/src/js/label/label.tsx +196 -0
- package/src/js/label/style/label.scss +4 -0
- package/src/js/link/link.tsx +38 -0
- package/src/js/link/style/link.scss +30 -0
- package/src/js/loader/loader.tsx +79 -0
- package/src/js/loader/loaderController.tsx +61 -0
- package/src/js/loader/style/loader.scss +53 -0
- package/src/js/media/media.tsx +72 -0
- package/src/js/navigator/navigator.tsx +51 -0
- package/src/js/optionsList/dvrdOptionsList.tsx +112 -0
- package/src/js/optionsList/style/dvrdOptionsList.scss +84 -0
- package/src/js/optionsMenu/optionsMenu.tsx +187 -0
- package/src/js/optionsMenu/style/optionsMenu.scss +70 -0
- package/src/js/pdf/element/pdfElement.tsx +315 -0
- package/src/js/pdf/element/style/pdfElement.scss +111 -0
- package/src/js/pdf/history/pdfHistory.ts +57 -0
- package/src/js/pdf/image/pdfImage.tsx +175 -0
- package/src/js/pdf/image/style/pdfImage.scss +34 -0
- package/src/js/pdf/invoiceTable/pdfInvoiceTable.tsx +176 -0
- package/src/js/pdf/invoiceTable/style/pdfInvoiceTable.scss +32 -0
- package/src/js/pdf/pdfTemplateCreator.tsx +279 -0
- package/src/js/pdf/settings/buttons/iconButton.tsx +49 -0
- package/src/js/pdf/settings/buttons/style/iconButton.scss +50 -0
- package/src/js/pdf/settings/image/pdfImageSettings.tsx +82 -0
- package/src/js/pdf/settings/image/style/pdfImageSettings.scss +9 -0
- package/src/js/pdf/settings/invoiceTable/pdfInvoiceTableSettings.tsx +141 -0
- package/src/js/pdf/settings/invoiceTable/style/pdfInvoiceTableSettings.scss +38 -0
- package/src/js/pdf/settings/pdfElementSettings.tsx +86 -0
- package/src/js/pdf/settings/style/pdfElementSettings.scss +56 -0
- package/src/js/pdf/settings/text/pdfTextSettings.tsx +202 -0
- package/src/js/pdf/settings/text/style/pdfTextSettings.scss +94 -0
- package/src/js/pdf/style/pdfTemplateCreator.scss +118 -0
- package/src/js/pdf/text/pdfText.tsx +267 -0
- package/src/js/pdf/text/style/pdfText.scss +22 -0
- package/src/js/pdf/v2/pdfElement/pdfDraggableElement.tsx +193 -0
- package/src/js/pdf/v2/types/pdfTemplateTypes.ts +27 -0
- package/src/js/popup/style/withBackground.scss +29 -0
- package/src/js/popup/withBackground.tsx +92 -0
- package/src/js/select/async/asyncSelect.tsx +46 -0
- package/src/js/select/async/style/asyncSelect.scss +23 -0
- package/src/js/select/dvrdSelect.tsx +214 -0
- package/src/js/select/dvrdSelectController.tsx +81 -0
- package/src/js/select/select.tsx +310 -0
- package/src/js/select/selectController.tsx +341 -0
- package/src/js/select/style/dvrdSelect.scss +140 -0
- package/src/js/select/style/select.scss +199 -0
- package/src/js/sidebarMenu/sidebarMenu.tsx +167 -0
- package/src/js/sidebarMenu/style/sidebarMenu.scss +167 -0
- package/src/js/slider/DVRSlider.tsx +107 -0
- package/src/js/slider/style/DVRSlider.scss +88 -0
- package/src/js/snackbar/snackbar.tsx +72 -0
- package/src/js/snackbar/snackbarController.tsx +104 -0
- package/src/js/snackbar/style/snackbar.scss +46 -0
- package/src/js/switch/dvrdSwitch.tsx +53 -0
- package/src/js/switch/style/dvrdSwitch.scss +47 -0
- package/src/js/switch/style/switch.scss +84 -0
- package/src/js/switch/switch.tsx +115 -0
- package/src/js/switch/switchController.tsx +97 -0
- package/src/js/textField/dvrdInput.tsx +219 -0
- package/src/js/textField/dvrdInputController.tsx +97 -0
- package/src/js/textField/dvrdNumberInput.tsx +141 -0
- package/src/js/textField/dvrdPasswordInput.tsx +40 -0
- package/src/js/textField/style/dvrdInput.scss +114 -0
- package/src/js/textField/style/dvrdPassword.scss +15 -0
- package/src/js/topButton/style/topButton.scss +54 -0
- package/src/js/topButton/topButton.tsx +136 -0
- package/src/js/util/analyticsUtil.ts +41 -0
- package/src/js/util/colorUtil.ts +230 -0
- package/src/js/util/componentUtil.tsx +59 -0
- package/src/js/util/constants.ts +12 -0
- package/src/js/util/controlContext.tsx +46 -0
- package/src/js/util/controlUtil.ts +107 -0
- package/src/js/util/cookieUtil.ts +17 -0
- package/src/js/util/eventUtil.ts +65 -0
- package/src/js/util/googleUtil.ts +88 -0
- package/src/js/util/interfaces.ts +180 -0
- package/src/js/util/jwtUtil.ts +72 -0
- package/src/js/util/miscUtil.ts +170 -0
- package/src/js/util/momentUtil.ts +45 -0
- package/src/js/util/pdfUtil.ts +124 -0
- package/src/js/util/requestUtil.ts +145 -0
- package/src/js/util/responsiveUtil.ts +37 -0
- package/src/js/util/validationUtil.ts +13 -0
- package/src/res/img/lock-handle.png +0 -0
- package/src/res/img/lock-handle.webp +0 -0
- package/src/res/img/lock.png +0 -0
- package/src/res/img/lock.webp +0 -0
- package/src/style/common-icons-variables.scss +140 -0
- package/src/style/common-icons.scss +714 -0
- package/src/style/common-variables.scss +243 -0
- package/src/style/display-breakpoints.scss +141 -0
- package/src/style/fonts/common-icons.eot +0 -0
- package/src/style/fonts/common-icons.svg +150 -0
- package/src/style/fonts/common-icons.ttf +0 -0
- package/src/style/fonts/common-icons.woff +0 -0
- package/src/style/fonts/common-icons.woff2 +0 -0
- package/src/style/fonts/fontAwesome/css/all.css +7003 -0
- package/src/style/fonts/fontAwesome/css/all.min.css +6 -0
- package/src/style/fonts/fontAwesome/css/brands.css +1423 -0
- package/src/style/fonts/fontAwesome/css/brands.min.css +6 -0
- package/src/style/fonts/fontAwesome/css/fontawesome.css +5519 -0
- package/src/style/fonts/fontAwesome/css/fontawesome.min.css +6 -0
- package/src/style/fonts/fontAwesome/css/regular.css +19 -0
- package/src/style/fonts/fontAwesome/css/regular.min.css +6 -0
- package/src/style/fonts/fontAwesome/css/solid.css +19 -0
- package/src/style/fonts/fontAwesome/css/solid.min.css +6 -0
- package/src/style/fonts/fontAwesome/css/svg-with-js.css +634 -0
- package/src/style/fonts/fontAwesome/css/svg-with-js.min.css +6 -0
- package/src/style/fonts/fontAwesome/css/v4-font-face.css +26 -0
- package/src/style/fonts/fontAwesome/css/v4-font-face.min.css +6 -0
- package/src/style/fonts/fontAwesome/css/v4-shims.css +2146 -0
- package/src/style/fonts/fontAwesome/css/v4-shims.min.css +6 -0
- package/src/style/fonts/fontAwesome/css/v5-font-face.css +22 -0
- package/src/style/fonts/fontAwesome/css/v5-font-face.min.css +6 -0
- package/src/style/fonts/fontAwesome/webfonts/fa-brands-400.ttf +0 -0
- package/src/style/fonts/fontAwesome/webfonts/fa-brands-400.woff2 +0 -0
- package/src/style/fonts/fontAwesome/webfonts/fa-regular-400.ttf +0 -0
- package/src/style/fonts/fontAwesome/webfonts/fa-regular-400.woff2 +0 -0
- package/src/style/fonts/fontAwesome/webfonts/fa-solid-900.ttf +0 -0
- package/src/style/fonts/fontAwesome/webfonts/fa-solid-900.woff2 +0 -0
- package/src/style/fonts/fontAwesome/webfonts/fa-v4compatibility.ttf +0 -0
- package/src/style/fonts/fontAwesome/webfonts/fa-v4compatibility.woff2 +0 -0
- package/src/style/variables.scss +11 -0
- package/.gitignore +0 -31
|
@@ -0,0 +1,196 @@
|
|
|
1
|
+
/*
|
|
2
|
+
* Copyright (c) 2021. Dave van Rijn Development
|
|
3
|
+
*/
|
|
4
|
+
|
|
5
|
+
import React from 'react';
|
|
6
|
+
import classNames from 'classnames';
|
|
7
|
+
|
|
8
|
+
import {ControlContext} from "../util/controlContext";
|
|
9
|
+
import {convertColor} from "../util/colorUtil";
|
|
10
|
+
import {calculateTextWidth, getComputedProperty, remToPx} from "../util/controlUtil";
|
|
11
|
+
|
|
12
|
+
export enum LabelType {
|
|
13
|
+
LABEL, SPAN, PAR,
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
export enum BreakType {
|
|
17
|
+
CHAR, WORD
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
interface Props {
|
|
21
|
+
labelType: LabelType,
|
|
22
|
+
className: string,
|
|
23
|
+
text: string,
|
|
24
|
+
color?: string,
|
|
25
|
+
maxLines: number,
|
|
26
|
+
width?: string | number,
|
|
27
|
+
labelProps: object,
|
|
28
|
+
breakMode: BreakType,
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
interface State {
|
|
32
|
+
text: string,
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
/**
|
|
36
|
+
* Label component which breaks its contents automatically. If maxLines is specified, the label will only break the
|
|
37
|
+
* text until the number of lines is reached. Remaining text will be shown in the title.
|
|
38
|
+
*/
|
|
39
|
+
export default class Label extends React.Component<Props, State> {
|
|
40
|
+
declare context: React.ContextType<typeof ControlContext>;
|
|
41
|
+
static contextType = ControlContext;
|
|
42
|
+
|
|
43
|
+
static defaultProps = {
|
|
44
|
+
labelType: LabelType.LABEL,
|
|
45
|
+
className: '',
|
|
46
|
+
labelProps: {},
|
|
47
|
+
breakMode: BreakType.CHAR,
|
|
48
|
+
maxLines: 0,
|
|
49
|
+
};
|
|
50
|
+
|
|
51
|
+
label: HTMLElement | null = null;
|
|
52
|
+
|
|
53
|
+
state = {
|
|
54
|
+
text: '',
|
|
55
|
+
};
|
|
56
|
+
|
|
57
|
+
getColor = (): string => {
|
|
58
|
+
const {contrastColor} = this.context, {color} = this.props, finalColor: string = color ? color : contrastColor;
|
|
59
|
+
return convertColor(finalColor);
|
|
60
|
+
};
|
|
61
|
+
|
|
62
|
+
getWidth = (): string => {
|
|
63
|
+
const {width} = this.props;
|
|
64
|
+
let finalWidth: string = 'initial';
|
|
65
|
+
if (width !== undefined && width !== null) {
|
|
66
|
+
if (typeof width === 'string') finalWidth = width;
|
|
67
|
+
else finalWidth = width + 'px';
|
|
68
|
+
}
|
|
69
|
+
return finalWidth;
|
|
70
|
+
};
|
|
71
|
+
|
|
72
|
+
getLabelProps = () => {
|
|
73
|
+
const {className, labelProps, text} = this.props;
|
|
74
|
+
return {
|
|
75
|
+
className: classNames('dvr-label', className),
|
|
76
|
+
style: {
|
|
77
|
+
color: this.getColor(),
|
|
78
|
+
width: this.getWidth(),
|
|
79
|
+
display: 'inline-block',
|
|
80
|
+
},
|
|
81
|
+
title: text,
|
|
82
|
+
ref: (ref: HTMLElement | null) => {
|
|
83
|
+
this.label = ref
|
|
84
|
+
},
|
|
85
|
+
...labelProps,
|
|
86
|
+
};
|
|
87
|
+
};
|
|
88
|
+
|
|
89
|
+
getFontSize = (): number | undefined => {
|
|
90
|
+
if (this.label) {
|
|
91
|
+
let fontSize: number | string = getComputedProperty('font-size', this.label);
|
|
92
|
+
fontSize = parseInt(fontSize.slice(0, fontSize.length - 2), 10);
|
|
93
|
+
return fontSize;
|
|
94
|
+
}
|
|
95
|
+
return undefined;
|
|
96
|
+
};
|
|
97
|
+
|
|
98
|
+
/**
|
|
99
|
+
* Truncate given text to given maxWidth. Truncating is done by removing characters from the end until the text + ...
|
|
100
|
+
* width is less then the given maxWidth. Trailing white spaces are removed and ... are appended.
|
|
101
|
+
* @param text Text to truncate
|
|
102
|
+
* @param maxWidth Max width in px
|
|
103
|
+
*/
|
|
104
|
+
reduceText = (text: string, maxWidth: number): string => {
|
|
105
|
+
let fontSize, fontFamily;
|
|
106
|
+
if (this.label) {
|
|
107
|
+
fontSize = this.getFontSize();
|
|
108
|
+
fontFamily = getComputedProperty('font-family', this.label);
|
|
109
|
+
}
|
|
110
|
+
while (calculateTextWidth(text + '...', fontSize, fontFamily) >= maxWidth)
|
|
111
|
+
text = text.slice(0, -1);
|
|
112
|
+
return text.trimRight() + '...';
|
|
113
|
+
};
|
|
114
|
+
|
|
115
|
+
/**
|
|
116
|
+
* Break a line by removing characters from the end until a whitespace or dash is found. Removed characters are
|
|
117
|
+
* returned as remainingChars.
|
|
118
|
+
* @param validLine Text to break
|
|
119
|
+
* @return Object containing the remainder of the the line and the removed characters.
|
|
120
|
+
*/
|
|
121
|
+
breakLine = (validLine: string): { validLine: string, remainingChars: string } => {
|
|
122
|
+
let remainingChars = '';
|
|
123
|
+
if (/[ -]$/.test(validLine)) {
|
|
124
|
+
validLine = validLine.slice(0, -1);
|
|
125
|
+
remainingChars = ' ';
|
|
126
|
+
}
|
|
127
|
+
|
|
128
|
+
while (!/[ -]$/.test(validLine) && validLine.length) {
|
|
129
|
+
remainingChars = validLine.slice(-1) + remainingChars;
|
|
130
|
+
validLine = validLine.slice(0, -1);
|
|
131
|
+
}
|
|
132
|
+
return {validLine, remainingChars};
|
|
133
|
+
};
|
|
134
|
+
|
|
135
|
+
/**
|
|
136
|
+
* Process the given text. This function divides the text into lines, by breaking the text according to the break
|
|
137
|
+
* mode given in the props. The width of the text is calculating by using a non-mounted canvas. The font family and
|
|
138
|
+
* font size are calculated from the computed properties of the rendered label.
|
|
139
|
+
*/
|
|
140
|
+
renderText = () => {
|
|
141
|
+
const {text, maxLines, breakMode} = this.props, chars = text.split(''), width = this.getWidth();
|
|
142
|
+
if (width === 'initial') return text;
|
|
143
|
+
|
|
144
|
+
const pxWidth: number = width.endsWith('px') ? Number(width.slice(0, -2)) : remToPx(Number(width.slice(0, -3))),
|
|
145
|
+
lines: string[] = new Array<string>();
|
|
146
|
+
let fontSize, fontFamily;
|
|
147
|
+
if (this.label) {
|
|
148
|
+
fontSize = this.getFontSize();
|
|
149
|
+
fontFamily = getComputedProperty('font-family', this.label);
|
|
150
|
+
}
|
|
151
|
+
|
|
152
|
+
let line = '';
|
|
153
|
+
for (let i = 0; i < chars.length; i++) {
|
|
154
|
+
const char = chars[i];
|
|
155
|
+
if (calculateTextWidth(line + char, fontSize, fontFamily) < pxWidth)
|
|
156
|
+
line += char;
|
|
157
|
+
else {
|
|
158
|
+
let processedLine = line;
|
|
159
|
+
if (breakMode === BreakType.WORD) {
|
|
160
|
+
const {validLine, remainingChars} = this.breakLine(line);
|
|
161
|
+
processedLine = validLine;
|
|
162
|
+
line = remainingChars;
|
|
163
|
+
} else line = '';
|
|
164
|
+
|
|
165
|
+
lines.push(processedLine);
|
|
166
|
+
if (maxLines > 0 && lines.length === maxLines) {
|
|
167
|
+
if (i < chars.length)
|
|
168
|
+
// Truncate last line if chars remaining
|
|
169
|
+
lines[lines.length - 1] = this.reduceText(lines[lines.length - 1], pxWidth);
|
|
170
|
+
line = '';
|
|
171
|
+
break;
|
|
172
|
+
}
|
|
173
|
+
line += char;
|
|
174
|
+
}
|
|
175
|
+
}
|
|
176
|
+
if (line.length) lines.push(line);
|
|
177
|
+
this.setState({text: lines.join('\n')});
|
|
178
|
+
};
|
|
179
|
+
|
|
180
|
+
componentDidMount = () => {
|
|
181
|
+
// Make sure the label has mounted before calculating the text
|
|
182
|
+
window.setTimeout(this.renderText, 0);
|
|
183
|
+
};
|
|
184
|
+
|
|
185
|
+
render = () => {
|
|
186
|
+
const {labelType} = this.props, {text} = this.state, labelProps = this.getLabelProps();
|
|
187
|
+
switch (labelType) {
|
|
188
|
+
case LabelType.LABEL:
|
|
189
|
+
return <label {...labelProps}>{text}</label>;
|
|
190
|
+
case LabelType.PAR:
|
|
191
|
+
return <p {...labelProps}>{text}</p>;
|
|
192
|
+
case LabelType.SPAN:
|
|
193
|
+
return <span {...labelProps}>{text}</span>;
|
|
194
|
+
}
|
|
195
|
+
};
|
|
196
|
+
}
|
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
/*
|
|
2
|
+
* Copyright (c) 2021. Dave van Rijn Development
|
|
3
|
+
*/
|
|
4
|
+
|
|
5
|
+
import './style/link.scss';
|
|
6
|
+
import classNames from 'classnames';
|
|
7
|
+
import React, {MouseEventHandler} from 'react';
|
|
8
|
+
import {navigate} from '../util/componentUtil';
|
|
9
|
+
|
|
10
|
+
interface Props {
|
|
11
|
+
onClick?: MouseEventHandler;
|
|
12
|
+
route?: string;
|
|
13
|
+
className?: string;
|
|
14
|
+
disabled?: boolean;
|
|
15
|
+
underline?: boolean;
|
|
16
|
+
target?: string;
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
export default function Link(props: React.PropsWithChildren<Props>) {
|
|
20
|
+
const {className, disabled, route, children, underline, target, onClick} = props;
|
|
21
|
+
|
|
22
|
+
function _onClick(evt: React.MouseEvent) {
|
|
23
|
+
evt.preventDefault();
|
|
24
|
+
if (!disabled) {
|
|
25
|
+
if (route) {
|
|
26
|
+
if (/^(www|http).+/.test(route)) window.open(route, target);
|
|
27
|
+
else navigate(route);
|
|
28
|
+
}
|
|
29
|
+
if (onClick) onClick(evt);
|
|
30
|
+
}
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
return (
|
|
34
|
+
<a href={route} onClick={_onClick} target={target}
|
|
35
|
+
className={classNames('app-link', className, disabled && 'disabled',
|
|
36
|
+
underline && 'underline')}>{children}</a>
|
|
37
|
+
);
|
|
38
|
+
};
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
/*!
|
|
2
|
+
* Copyright (c) 2021. Dave van Rijn Development
|
|
3
|
+
*/
|
|
4
|
+
|
|
5
|
+
@import '../../../style/variables';
|
|
6
|
+
|
|
7
|
+
.app-link {
|
|
8
|
+
color: $color-blue-1;
|
|
9
|
+
text-decoration: none;
|
|
10
|
+
transition: color .2s ease-in-out, border-bottom-color .2s ease-in-out;
|
|
11
|
+
cursor: pointer;
|
|
12
|
+
|
|
13
|
+
&.underline {
|
|
14
|
+
border-bottom: 1px solid transparent;
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
&:hover {
|
|
18
|
+
color: $color-blue-1-darken;
|
|
19
|
+
|
|
20
|
+
&.underline {
|
|
21
|
+
border-bottom: 1px solid currentColor;
|
|
22
|
+
}
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
&.disabled {
|
|
26
|
+
cursor: default;
|
|
27
|
+
color: $color-gray-4 !important;
|
|
28
|
+
border-bottom: 1px solid transparent !important;
|
|
29
|
+
}
|
|
30
|
+
}
|
|
@@ -0,0 +1,79 @@
|
|
|
1
|
+
/*
|
|
2
|
+
* Copyright (c) 2021. Dave van Rijn Development
|
|
3
|
+
*/
|
|
4
|
+
|
|
5
|
+
import './style/loader.scss';
|
|
6
|
+
|
|
7
|
+
import React, {CSSProperties} from 'react';
|
|
8
|
+
import classNames from 'classnames';
|
|
9
|
+
import {ThemeShape} from '../util/controlContext';
|
|
10
|
+
import {isNull} from "../util/controlUtil";
|
|
11
|
+
import {colorIsWhite, convertColor} from "../util/colorUtil";
|
|
12
|
+
|
|
13
|
+
interface LoaderProps {
|
|
14
|
+
label?: string,
|
|
15
|
+
size?: string,
|
|
16
|
+
thickness?: string,
|
|
17
|
+
baseColor: string,
|
|
18
|
+
trackColor: string,
|
|
19
|
+
containerClass: string,
|
|
20
|
+
loaderClass: string,
|
|
21
|
+
labelClass: string,
|
|
22
|
+
contextStyle: ThemeShape,
|
|
23
|
+
disableBackground: boolean,
|
|
24
|
+
loaderStyle: CSSProperties;
|
|
25
|
+
position: 'absolute' | 'fixed' | 'relative';
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
export class Loader extends React.Component<LoaderProps> {
|
|
29
|
+
getContainerClass = (): string => {
|
|
30
|
+
const {containerClass, disableBackground} = this.props, classes = ['loaderContainer'];
|
|
31
|
+
if (disableBackground) classes.push('noBack');
|
|
32
|
+
classes.push(containerClass);
|
|
33
|
+
return classNames(classes);
|
|
34
|
+
};
|
|
35
|
+
|
|
36
|
+
getLoaderClass = (): string => {
|
|
37
|
+
const {loaderClass} = this.props, classes = ['loader'];
|
|
38
|
+
classes.push(loaderClass);
|
|
39
|
+
return classNames(classes);
|
|
40
|
+
};
|
|
41
|
+
|
|
42
|
+
getLoaderStyle = (): object => {
|
|
43
|
+
const {baseColor, trackColor, contextStyle} = this.props;
|
|
44
|
+
let color = isNull(baseColor) ? 'color-orange-1' :
|
|
45
|
+
colorIsWhite(baseColor) ? contextStyle.contrastColor : baseColor,
|
|
46
|
+
track = isNull(trackColor) ? 'color-gray-7' : trackColor;
|
|
47
|
+
const style: CSSProperties = {borderColor: convertColor(track), borderTopColor: convertColor(color)};
|
|
48
|
+
return this.addPropStyles(style);
|
|
49
|
+
};
|
|
50
|
+
|
|
51
|
+
addPropStyles = (style: CSSProperties): CSSProperties => {
|
|
52
|
+
const {size, thickness, loaderStyle} = this.props;
|
|
53
|
+
if (size !== null && size !== undefined)
|
|
54
|
+
style = Object.assign({}, style, {
|
|
55
|
+
width: size,
|
|
56
|
+
height: size,
|
|
57
|
+
paddingBottom: 'unset',
|
|
58
|
+
});
|
|
59
|
+
if (thickness !== null && thickness !== undefined)
|
|
60
|
+
style = Object.assign({}, style, {borderWidth: thickness});
|
|
61
|
+
return Object.assign({}, style, loaderStyle);
|
|
62
|
+
};
|
|
63
|
+
|
|
64
|
+
renderLabel = (): React.ReactNode => {
|
|
65
|
+
const {label, labelClass} = this.props;
|
|
66
|
+
if (label === null || label === undefined) return null;
|
|
67
|
+
return <label className={classNames('loaderLabel', labelClass)}>{label}</label>
|
|
68
|
+
};
|
|
69
|
+
|
|
70
|
+
render = () => {
|
|
71
|
+
const {position} = this.props;
|
|
72
|
+
return (
|
|
73
|
+
<div className={this.getContainerClass()} style={{position}}>
|
|
74
|
+
<div className={this.getLoaderClass()} style={this.getLoaderStyle()}/>
|
|
75
|
+
{this.renderLabel()}
|
|
76
|
+
</div>
|
|
77
|
+
)
|
|
78
|
+
}
|
|
79
|
+
}
|
|
@@ -0,0 +1,61 @@
|
|
|
1
|
+
/*
|
|
2
|
+
* Copyright (c) 2021. Dave van Rijn Development
|
|
3
|
+
*/
|
|
4
|
+
|
|
5
|
+
import React, {CSSProperties} from 'react';
|
|
6
|
+
import {Loader} from "./loader";
|
|
7
|
+
import {ControlContext} from "../util/controlContext";
|
|
8
|
+
|
|
9
|
+
interface LoaderProps {
|
|
10
|
+
label?: string,
|
|
11
|
+
baseColor?: string,
|
|
12
|
+
thickness: string,
|
|
13
|
+
size: string,
|
|
14
|
+
trackColor: string,
|
|
15
|
+
containerClass: string,
|
|
16
|
+
loaderClass: string,
|
|
17
|
+
labelClass: string,
|
|
18
|
+
active: boolean,
|
|
19
|
+
disableBackground: boolean,
|
|
20
|
+
loaderStyle: CSSProperties;
|
|
21
|
+
position: 'absolute' | 'fixed' | 'relative';
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
export default class LoaderController extends React.Component<LoaderProps> {
|
|
25
|
+
// noinspection JSUnusedGlobalSymbols
|
|
26
|
+
declare context: React.ContextType<typeof ControlContext>;
|
|
27
|
+
static contextType = ControlContext;
|
|
28
|
+
|
|
29
|
+
static defaultProps = {
|
|
30
|
+
trackColor: 'transparent',
|
|
31
|
+
size: '5rem',
|
|
32
|
+
thickness: '.2rem',
|
|
33
|
+
containerClass: '',
|
|
34
|
+
trackClass: '',
|
|
35
|
+
loaderClass: '',
|
|
36
|
+
labelClass: '',
|
|
37
|
+
disableBackground: false,
|
|
38
|
+
loaderStyle: {},
|
|
39
|
+
position: 'absolute',
|
|
40
|
+
};
|
|
41
|
+
|
|
42
|
+
getBaseColor = () => {
|
|
43
|
+
const {baseColor} = this.props;
|
|
44
|
+
if (baseColor !== null && baseColor !== undefined) return baseColor;
|
|
45
|
+
// noinspection JSDeprecatedSymbols
|
|
46
|
+
return this.context.baseColor;
|
|
47
|
+
};
|
|
48
|
+
|
|
49
|
+
render = () => {
|
|
50
|
+
const {
|
|
51
|
+
active, trackColor, containerClass, loaderClass, labelClass, label, size, thickness, disableBackground,
|
|
52
|
+
loaderStyle, position
|
|
53
|
+
} = this.props;
|
|
54
|
+
if (active)
|
|
55
|
+
return <Loader baseColor={this.getBaseColor()} trackColor={trackColor} contextStyle={this.context}
|
|
56
|
+
containerClass={containerClass} loaderClass={loaderClass} labelClass={labelClass}
|
|
57
|
+
label={label} size={size} thickness={thickness} disableBackground={disableBackground}
|
|
58
|
+
loaderStyle={loaderStyle} position={position}/>;
|
|
59
|
+
return null;
|
|
60
|
+
}
|
|
61
|
+
}
|
|
@@ -0,0 +1,53 @@
|
|
|
1
|
+
/*!
|
|
2
|
+
* Copyright (c) 2021. Dave van Rijn Development
|
|
3
|
+
*/
|
|
4
|
+
|
|
5
|
+
@import '../../../style/variables';
|
|
6
|
+
|
|
7
|
+
.loaderContainer {
|
|
8
|
+
display: flex;
|
|
9
|
+
flex-direction: column;
|
|
10
|
+
align-items: center;
|
|
11
|
+
justify-content: center;
|
|
12
|
+
z-index: $z-index-high;
|
|
13
|
+
background-color: rgba(white, .6);
|
|
14
|
+
top: 0;
|
|
15
|
+
left: 0;
|
|
16
|
+
width: 100%;
|
|
17
|
+
height: 100%;
|
|
18
|
+
|
|
19
|
+
&.noBack {
|
|
20
|
+
background-color: transparent;
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
.loaderLabel {
|
|
24
|
+
@include borderRadius(.2rem);
|
|
25
|
+
font-size: .9rem;
|
|
26
|
+
color: $color-gray-6;
|
|
27
|
+
text-align: center;
|
|
28
|
+
margin-top: .5rem;
|
|
29
|
+
display: block;
|
|
30
|
+
padding: .2rem .3rem;
|
|
31
|
+
background-color: rgba(black, .6);
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
.loader {
|
|
35
|
+
@include borderRadius(50%);
|
|
36
|
+
border: 1rem solid;
|
|
37
|
+
animation: rotate 1s ease-in-out infinite;
|
|
38
|
+
min-width: 2rem;
|
|
39
|
+
padding-bottom: 100%;
|
|
40
|
+
width: 100%;
|
|
41
|
+
height: 0;
|
|
42
|
+
|
|
43
|
+
@keyframes rotate {
|
|
44
|
+
0% {
|
|
45
|
+
transform: rotate(0);
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
100% {
|
|
49
|
+
transform: rotate(360deg);
|
|
50
|
+
}
|
|
51
|
+
}
|
|
52
|
+
}
|
|
53
|
+
}
|
|
@@ -0,0 +1,72 @@
|
|
|
1
|
+
/*
|
|
2
|
+
* Copyright (c) 2021. Dave van Rijn Development
|
|
3
|
+
*/
|
|
4
|
+
|
|
5
|
+
import React, {PureComponent, MouseEventHandler} from 'react';
|
|
6
|
+
import {HTMLVideoEvent, MediaType} from '../util/interfaces';
|
|
7
|
+
import {generateComponentId} from "../util/componentUtil";
|
|
8
|
+
|
|
9
|
+
interface Props {
|
|
10
|
+
onVideoEnd?: VoidFunction;
|
|
11
|
+
onClick?: MouseEventHandler;
|
|
12
|
+
onCanPlay?: HTMLVideoEvent;
|
|
13
|
+
filename: string;
|
|
14
|
+
source?: string;
|
|
15
|
+
className?: string;
|
|
16
|
+
imgAlt?: string;
|
|
17
|
+
mediaType?: MediaType;
|
|
18
|
+
controls?: boolean;
|
|
19
|
+
loop?: boolean;
|
|
20
|
+
autoPlay?: boolean;
|
|
21
|
+
muted?: boolean;
|
|
22
|
+
extension?: string;
|
|
23
|
+
id?: string;
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
const videoExtensions = ['.mp4', '.webm'];
|
|
27
|
+
|
|
28
|
+
export default class Media extends PureComponent<Props> {
|
|
29
|
+
private readonly id = generateComponentId(this.props.id);
|
|
30
|
+
|
|
31
|
+
getExtension = (): string => {
|
|
32
|
+
const {source, filename, extension} = this.props;
|
|
33
|
+
if (extension) return extension;
|
|
34
|
+
if (source && source.match(/\.[A-Za-z\d]+$/))
|
|
35
|
+
return source.substr(source.lastIndexOf('.'), source.length);
|
|
36
|
+
else if (filename.match(/\.[A-Za-z\d]+$/))
|
|
37
|
+
return filename.substr(filename.lastIndexOf('.'), filename.length);
|
|
38
|
+
throw new TypeError('No extension found in either the source or filename')
|
|
39
|
+
};
|
|
40
|
+
|
|
41
|
+
getMediaType = (): MediaType => {
|
|
42
|
+
const {mediaType} = this.props;
|
|
43
|
+
if (mediaType) return mediaType;
|
|
44
|
+
const extension: string = this.getExtension();
|
|
45
|
+
return videoExtensions.includes(extension) ? MediaType.VIDEO : MediaType.IMAGE;
|
|
46
|
+
};
|
|
47
|
+
|
|
48
|
+
renderImgElement = () => {
|
|
49
|
+
const {source, filename, imgAlt, onClick, className} = this.props;
|
|
50
|
+
return (
|
|
51
|
+
<img id={this.id} src={source ?? filename} alt={imgAlt ?? 'DVR Controls'} onClick={onClick} className={className}/>
|
|
52
|
+
);
|
|
53
|
+
};
|
|
54
|
+
|
|
55
|
+
renderVideoElement = () => {
|
|
56
|
+
const {source, filename, onClick, onVideoEnd, className, controls, autoPlay, loop, muted, onCanPlay} = this.props,
|
|
57
|
+
extension = this.getExtension();
|
|
58
|
+
return (
|
|
59
|
+
<video onEnded={onVideoEnd} className={className} controls={controls} autoPlay={autoPlay} loop={loop}
|
|
60
|
+
muted={muted} onClick={onClick} id={this.id} onCanPlay={onCanPlay}>
|
|
61
|
+
<source src={source ?? filename} type={`video/${extension.substr(1)}`}/>
|
|
62
|
+
This browser does not support the HTML5 video element.
|
|
63
|
+
</video>
|
|
64
|
+
)
|
|
65
|
+
};
|
|
66
|
+
|
|
67
|
+
render = () => {
|
|
68
|
+
const mediaType: MediaType = this.getMediaType();
|
|
69
|
+
if (mediaType === MediaType.IMAGE) return this.renderImgElement();
|
|
70
|
+
return this.renderVideoElement();
|
|
71
|
+
}
|
|
72
|
+
}
|
|
@@ -0,0 +1,51 @@
|
|
|
1
|
+
/*
|
|
2
|
+
* Copyright (c) 2021. Dave van Rijn Development
|
|
3
|
+
*/
|
|
4
|
+
|
|
5
|
+
import React from 'react';
|
|
6
|
+
// import {RouteComponentProps, withRouter} from "react-router";
|
|
7
|
+
import { useNavigate } from 'react-router-dom';
|
|
8
|
+
import { useLocation } from 'react-router-dom';
|
|
9
|
+
import {debug} from '../util/miscUtil';
|
|
10
|
+
|
|
11
|
+
// let navigationData: any = null;
|
|
12
|
+
|
|
13
|
+
export default function AppNavigator() {
|
|
14
|
+
const location = useLocation();
|
|
15
|
+
const navigate = useNavigate();
|
|
16
|
+
|
|
17
|
+
function onNavigate(evt: React.MouseEvent) {
|
|
18
|
+
const navigator: HTMLButtonElement = evt.target as HTMLButtonElement;
|
|
19
|
+
const url = navigator.dataset.url + (navigator.dataset.strip === '0' ? location.search : '');
|
|
20
|
+
navigator.dataset.strip = '0';
|
|
21
|
+
debug(`Navigating to ${url}`);
|
|
22
|
+
navigate(url);
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
return (
|
|
26
|
+
<button id='appNavigator' style={{display: 'none'}} data-url='' data-strip='0' onClick={onNavigate}/>
|
|
27
|
+
)
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
// class AppNavigator extends React.Component<RouteComponentProps> {
|
|
31
|
+
// static setNavigationData = (data: any) => {
|
|
32
|
+
// navigationData = data;
|
|
33
|
+
// };
|
|
34
|
+
//
|
|
35
|
+
// static getNavigationData = (): any => navigationData;
|
|
36
|
+
//
|
|
37
|
+
// navigate = (evt: any) => {
|
|
38
|
+
// const {location, history} = this.props;
|
|
39
|
+
// const navigator = evt.target,
|
|
40
|
+
// url = navigator.dataset.url + (navigator.dataset.strip === '0' ? location.search : '');
|
|
41
|
+
// navigator.dataset.strip = '0';
|
|
42
|
+
// debug(`Navigating to ${url}`);
|
|
43
|
+
// history.push(url);
|
|
44
|
+
// };
|
|
45
|
+
//
|
|
46
|
+
// render = () => {
|
|
47
|
+
// return <button id='appNavigator' style={{display: 'none'}} data-url='' data-strip='0' onClick={this.navigate}/>
|
|
48
|
+
// }
|
|
49
|
+
// }
|
|
50
|
+
//
|
|
51
|
+
// export default withRouter(AppNavigator);
|