@dvrd/dvr-controls 1.0.37 → 1.0.39
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 +2 -0
- package/package.json +1 -1
- package/src/js/colorPicker/colorPicker.tsx +6 -1
- package/src/js/radio/dvrdRadio.tsx +72 -0
- package/src/js/radio/dvrdRadioController.tsx +79 -0
- package/src/js/radio/style/dvrdRadio.scss +80 -0
- package/src/js/util/controlContext.tsx +4 -3
- package/src/js/util/miscUtil.ts +2 -2
- package/src/js/util/momentUtil.ts +9 -0
package/index.ts
CHANGED
|
@@ -55,6 +55,7 @@ import DvrdSelectController from './src/js/select/dvrdSelectController';
|
|
|
55
55
|
import DvrdSwitch from './src/js/switch/dvrdSwitch';
|
|
56
56
|
import DvrdHeaderController from './src/js/header/v2/dvrdHeaderController';
|
|
57
57
|
import FileUpload from './src/js/fileUpload/fileUpload';
|
|
58
|
+
import DvrdRadioController from './src/js/radio/dvrdRadioController';
|
|
58
59
|
|
|
59
60
|
export {
|
|
60
61
|
// Components
|
|
@@ -102,6 +103,7 @@ export {
|
|
|
102
103
|
DvrdSwitch,
|
|
103
104
|
DvrdHeaderController as DvrdHeader,
|
|
104
105
|
FileUpload,
|
|
106
|
+
DvrdRadioController as DvrdRadio,
|
|
105
107
|
|
|
106
108
|
// Interfaces / Enums
|
|
107
109
|
DialogActionShape,
|
package/package.json
CHANGED
|
@@ -16,6 +16,7 @@ import {Button} from "../../../index";
|
|
|
16
16
|
|
|
17
17
|
interface Props extends ColorPickerProps<any> {
|
|
18
18
|
onSubmit: (color: Color) => void;
|
|
19
|
+
onSubmitColorResult?: (colorResult: ColorResult | null) => void;
|
|
19
20
|
onPreChange?: (color: Color) => void;
|
|
20
21
|
onClose: MouseEventHandler;
|
|
21
22
|
pickerType: ColorPickerType;
|
|
@@ -27,6 +28,7 @@ interface Props extends ColorPickerProps<any> {
|
|
|
27
28
|
|
|
28
29
|
interface State {
|
|
29
30
|
color: Color;
|
|
31
|
+
colorResult: ColorResult | null;
|
|
30
32
|
}
|
|
31
33
|
|
|
32
34
|
export default class ColorPicker extends PureComponent<Props, State> {
|
|
@@ -39,14 +41,17 @@ export default class ColorPicker extends PureComponent<Props, State> {
|
|
|
39
41
|
|
|
40
42
|
state: State = {
|
|
41
43
|
color: this.props.color || '#000',
|
|
44
|
+
colorResult: null,
|
|
42
45
|
};
|
|
43
46
|
|
|
44
47
|
onSubmit = () => {
|
|
45
|
-
const {onSubmit} = this.props, {color} = this.state;
|
|
48
|
+
const {onSubmit, onSubmitColorResult} = this.props, {color, colorResult} = this.state;
|
|
46
49
|
onSubmit(color);
|
|
50
|
+
onSubmitColorResult?.(colorResult);
|
|
47
51
|
};
|
|
48
52
|
|
|
49
53
|
onChange = (color: ColorResult) => {
|
|
54
|
+
this.setState({colorResult: color});
|
|
50
55
|
let newColor: Color;
|
|
51
56
|
switch (this.props.resultType) {
|
|
52
57
|
case ColorPickerResultType.HEX:
|
|
@@ -0,0 +1,72 @@
|
|
|
1
|
+
/*
|
|
2
|
+
* Copyright (c) Dave van Rijn Development 2023.
|
|
3
|
+
*/
|
|
4
|
+
import './style/dvrdRadio.scss';
|
|
5
|
+
|
|
6
|
+
import classNames from 'classnames';
|
|
7
|
+
import React, {MouseEventHandler, useContext, useMemo} from 'react';
|
|
8
|
+
import {ControlContext} from "../util/controlContext";
|
|
9
|
+
import {editColor} from "../util/colorUtil";
|
|
10
|
+
|
|
11
|
+
interface Props {
|
|
12
|
+
onClick: MouseEventHandler;
|
|
13
|
+
onMouseEnter: MouseEventHandler;
|
|
14
|
+
onMouseLeave: MouseEventHandler;
|
|
15
|
+
checked: boolean;
|
|
16
|
+
hasHover: boolean;
|
|
17
|
+
id: string;
|
|
18
|
+
labelPosition: 'left' | 'right';
|
|
19
|
+
disabled?: boolean;
|
|
20
|
+
label?: string;
|
|
21
|
+
baseColor?: string;
|
|
22
|
+
title?: string;
|
|
23
|
+
className?: string;
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
export default function DvrdRadio(props: Props) {
|
|
27
|
+
const context = useContext(ControlContext);
|
|
28
|
+
const {
|
|
29
|
+
checked, label, labelPosition, hasHover, onClick, title, disabled, onMouseLeave, onMouseEnter, className, id
|
|
30
|
+
} = props;
|
|
31
|
+
const baseColor = useMemo(() => {
|
|
32
|
+
return props.baseColor ?? context.baseColor
|
|
33
|
+
}, [props.baseColor, context.baseColor]);
|
|
34
|
+
|
|
35
|
+
function getBulletContainerStyle() {
|
|
36
|
+
let borderColor: string = baseColor;
|
|
37
|
+
if (disabled) borderColor = 'color-gray-4';
|
|
38
|
+
else if (hasHover) borderColor = editColor(-.2, baseColor);
|
|
39
|
+
return {borderColor};
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
function getBulletStyle() {
|
|
43
|
+
let color: string = baseColor;
|
|
44
|
+
if (disabled) color = 'color-gray-4';
|
|
45
|
+
else if (hasHover) color = editColor(-.2, baseColor);
|
|
46
|
+
return {backgroundColor: color};
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
function renderLabel(position: 'left' | 'right') {
|
|
50
|
+
if (!label?.length || position !== labelPosition) return;
|
|
51
|
+
return <label className='dvrd-radio-button-label'>{label}</label>;
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
function renderBullet() {
|
|
55
|
+
return (
|
|
56
|
+
<div className='dvrd-radio-bullet-container' style={getBulletContainerStyle()}>
|
|
57
|
+
<div className='ripple' style={{backgroundColor: baseColor}}/>
|
|
58
|
+
<div className={classNames('dvrd-radio-bullet', checked && 'checked')} style={getBulletStyle()}/>
|
|
59
|
+
</div>
|
|
60
|
+
)
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
return (
|
|
64
|
+
<div
|
|
65
|
+
className={classNames('dvrd-radio-button', disabled && 'disbled', !!context.noAnimations && 'no-animations', className)}
|
|
66
|
+
onClick={onClick} id={id} onMouseEnter={onMouseEnter} onMouseLeave={onMouseLeave} title={title}>
|
|
67
|
+
{renderLabel('left')}
|
|
68
|
+
{renderBullet()}
|
|
69
|
+
{renderLabel('right')}
|
|
70
|
+
</div>
|
|
71
|
+
)
|
|
72
|
+
}
|
|
@@ -0,0 +1,79 @@
|
|
|
1
|
+
/*
|
|
2
|
+
* Copyright (c) Dave van Rijn Development 2023.
|
|
3
|
+
*/
|
|
4
|
+
|
|
5
|
+
import React, {useCallback, useContext, useRef, useState} from 'react';
|
|
6
|
+
import {ChangeFunction} from "../util/interfaces";
|
|
7
|
+
import {generateComponentId} from "../util/componentUtil";
|
|
8
|
+
import {ControlContext} from "../util/controlContext";
|
|
9
|
+
import DvrdRadio from "./dvrdRadio";
|
|
10
|
+
|
|
11
|
+
interface Props {
|
|
12
|
+
onChange: ChangeFunction<string | number | bigint>;
|
|
13
|
+
value: string | number | bigint;
|
|
14
|
+
checked: boolean;
|
|
15
|
+
disabled?: boolean;
|
|
16
|
+
label?: string;
|
|
17
|
+
labelPosition?: 'left' | 'right';
|
|
18
|
+
baseColor?: string;
|
|
19
|
+
id?: string;
|
|
20
|
+
title?: string;
|
|
21
|
+
className?: string;
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
export default function DvrdRadioController(props: Props) {
|
|
25
|
+
const context = useContext(ControlContext);
|
|
26
|
+
const {disabled, onChange, value, checked, labelPosition, label, className, baseColor, title} = props;
|
|
27
|
+
const [hasHover, setHasHover] = useState(false);
|
|
28
|
+
const id = useRef(generateComponentId(props.id));
|
|
29
|
+
|
|
30
|
+
const getContainer = useCallback(() => {
|
|
31
|
+
return document.getElementById(id.current);
|
|
32
|
+
}, [id.current]);
|
|
33
|
+
|
|
34
|
+
const getRipple = useCallback(() => {
|
|
35
|
+
const container = getContainer();
|
|
36
|
+
if (container === null) return null;
|
|
37
|
+
return container.querySelector('div.ripple');
|
|
38
|
+
}, [id.current]);
|
|
39
|
+
|
|
40
|
+
function onClick() {
|
|
41
|
+
if (disabled) return;
|
|
42
|
+
onChange(value);
|
|
43
|
+
if (!context.noAnimations)
|
|
44
|
+
addRipple();
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
function onMouseEnter() {
|
|
48
|
+
if (!disabled)
|
|
49
|
+
setHasHover(true);
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
function onMouseLeave() {
|
|
53
|
+
setHasHover(false);
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
function addRipple() {
|
|
57
|
+
const container = getContainer();
|
|
58
|
+
const ripple = this.getRipple();
|
|
59
|
+
if (!container || !ripple) return;
|
|
60
|
+
if (container.classList.contains('rippling'))
|
|
61
|
+
container.classList.remove('rippling');
|
|
62
|
+
ripple.addEventListener('transitionend', removeRipple);
|
|
63
|
+
container.classList.add('rippling');
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
function removeRipple() {
|
|
67
|
+
const ripple = getRipple();
|
|
68
|
+
const container = getContainer();
|
|
69
|
+
if (!container || !ripple) return;
|
|
70
|
+
ripple.removeEventListener('transitionend', this.removeRipple);
|
|
71
|
+
container.classList.remove('rippling');
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
return (
|
|
75
|
+
<DvrdRadio onClick={onClick} onMouseEnter={onMouseEnter} onMouseLeave={onMouseLeave} checked={checked}
|
|
76
|
+
hasHover={hasHover} id={id.current} labelPosition={labelPosition ?? 'right'} label={label}
|
|
77
|
+
baseColor={baseColor} className={className} title={title} disabled={disabled}/>
|
|
78
|
+
);
|
|
79
|
+
}
|
|
@@ -0,0 +1,80 @@
|
|
|
1
|
+
/*!
|
|
2
|
+
* Copyright (c) Dave van Rijn Development 2023.
|
|
3
|
+
*/
|
|
4
|
+
|
|
5
|
+
@import '../../../style/variables';
|
|
6
|
+
|
|
7
|
+
.dvrd-radio-button {
|
|
8
|
+
cursor: pointer;
|
|
9
|
+
display: flex;
|
|
10
|
+
column-gap: .5rem;
|
|
11
|
+
align-items: center;
|
|
12
|
+
|
|
13
|
+
.dvrd-radio-button-label {
|
|
14
|
+
font-size: .9rem;
|
|
15
|
+
color: $color-blue-text;
|
|
16
|
+
cursor: inherit;
|
|
17
|
+
user-select: none;
|
|
18
|
+
transition: color .2s ease;
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
.dvrd-radio-bullet-container {
|
|
22
|
+
@include backgroundShadow2;
|
|
23
|
+
width: 22px;
|
|
24
|
+
height: 22px;
|
|
25
|
+
position: relative;
|
|
26
|
+
border-radius: 50%;
|
|
27
|
+
border: 2px solid;
|
|
28
|
+
cursor: inherit;
|
|
29
|
+
background-color: white;
|
|
30
|
+
display: flex;
|
|
31
|
+
justify-content: center;
|
|
32
|
+
align-items: center;
|
|
33
|
+
|
|
34
|
+
.dvrd-radio-bullet {
|
|
35
|
+
width: 10px;
|
|
36
|
+
height: 10px;
|
|
37
|
+
border-radius: 50%;
|
|
38
|
+
visibility: hidden;
|
|
39
|
+
opacity: 0;
|
|
40
|
+
transition: visibility .2s ease-in-out, opacity .2s ease-in-out;
|
|
41
|
+
|
|
42
|
+
&.checked {
|
|
43
|
+
visibility: visible;
|
|
44
|
+
opacity: 1;
|
|
45
|
+
}
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
.ripple {
|
|
49
|
+
@include centerXY;
|
|
50
|
+
@include borderRadius(50%);
|
|
51
|
+
opacity: 1;
|
|
52
|
+
width: 8px;
|
|
53
|
+
height: 8px;
|
|
54
|
+
visibility: hidden;
|
|
55
|
+
pointer-events: none;
|
|
56
|
+
}
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
&.disabled {
|
|
60
|
+
cursor: default;
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
&.no-animations {
|
|
64
|
+
&, * {
|
|
65
|
+
transition: none !important;
|
|
66
|
+
}
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
&.rippling {
|
|
70
|
+
.dvrd-radio-bullet-container {
|
|
71
|
+
.ripple {
|
|
72
|
+
width: 56px;
|
|
73
|
+
height: 56px;
|
|
74
|
+
visibility: visible;
|
|
75
|
+
opacity: 0;
|
|
76
|
+
transition: opacity .5s ease-in-out, opacity .5s ease, width .5s ease-in-out, height .5s ease-in-out;
|
|
77
|
+
}
|
|
78
|
+
}
|
|
79
|
+
}
|
|
80
|
+
}
|
|
@@ -8,9 +8,9 @@ import {defer} from 'lodash';
|
|
|
8
8
|
|
|
9
9
|
// noinspection JSUnusedGlobalSymbols
|
|
10
10
|
export interface ThemeContextShape {
|
|
11
|
-
baseColor: string
|
|
12
|
-
contrastColor: string
|
|
13
|
-
onChange: Function
|
|
11
|
+
baseColor: string;
|
|
12
|
+
contrastColor: string;
|
|
13
|
+
onChange: Function;
|
|
14
14
|
}
|
|
15
15
|
|
|
16
16
|
export interface ProviderProps {
|
|
@@ -23,6 +23,7 @@ export interface ThemeShape {
|
|
|
23
23
|
controlVariant?: ControlVariant;
|
|
24
24
|
borderColor?: string;
|
|
25
25
|
onChange?: (theme?: ThemeShape) => void;
|
|
26
|
+
noAnimations?: boolean;
|
|
26
27
|
}
|
|
27
28
|
|
|
28
29
|
export const ControlContext: Context<ThemeShape> = React.createContext<ThemeShape>(
|
package/src/js/util/miscUtil.ts
CHANGED
|
@@ -136,8 +136,8 @@ export const shuffleArray = (arr: any[]): any[] => {
|
|
|
136
136
|
return arr;
|
|
137
137
|
};
|
|
138
138
|
|
|
139
|
-
export function nullify<T extends string | Array<any> | Set<any> | number>(value?: T | null): T | null {
|
|
140
|
-
if (typeof value === 'number') {
|
|
139
|
+
export function nullify<T extends string | Array<any> | Set<any> | number | bigint>(value?: T | null): T | null {
|
|
140
|
+
if (typeof value === 'number' || typeof value === 'bigint') {
|
|
141
141
|
if (value > 0) return value;
|
|
142
142
|
return null;
|
|
143
143
|
}
|
|
@@ -5,6 +5,15 @@
|
|
|
5
5
|
import moment, {Moment} from "moment";
|
|
6
6
|
|
|
7
7
|
export const MOMENT_FORMATS: string[] = [
|
|
8
|
+
'MM/DD/YYYY HH:mm:ssZ',
|
|
9
|
+
'MM-DD-YYYY HH:mm:ssZ',
|
|
10
|
+
'DD/MM/YYYY HH:mm:ssZ',
|
|
11
|
+
'DD-MM-YYYY HH:mm:ssZ',
|
|
12
|
+
'YYYY-MM-DD HH:mm:ssZ',
|
|
13
|
+
'YYYY/MM/DD HH:mm:ssZ',
|
|
14
|
+
'DD/MM/YYYYTHH:mm:ssZ',
|
|
15
|
+
'DD-MM-YYYYTHH:mm:ssZ',
|
|
16
|
+
'YYYY-MM-DDTHH:mm:ssZ',
|
|
8
17
|
'MM/DD/YYYY HH:mm:ss',
|
|
9
18
|
'MM-DD-YYYY HH:mm:ss',
|
|
10
19
|
'DD/MM/YYYY HH:mm:ss',
|