@adcops/autocore-react 3.0.8 → 3.0.10
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/dist/components/ToggleGroup.d.ts +3 -85
- package/dist/components/ToggleGroup.js +1 -1
- package/dist/components/ValueInput.d.ts +5 -2
- package/dist/components/ValueInput.js +1 -1
- package/package.json +1 -1
- package/src/components/ToggleGroup.tsx +204 -348
- package/src/components/ValueInput.tsx +125 -84
|
@@ -1,103 +1,21 @@
|
|
|
1
|
-
import
|
|
1
|
+
import React from 'react';
|
|
2
2
|
import { SelectButtonProps } from 'primereact/selectbutton';
|
|
3
|
-
import { EventEmitterContextType } from '../core/EventEmitterContext';
|
|
4
3
|
import { IndicatorColor } from "../core/IndicatorColor";
|
|
5
4
|
export { IndicatorColor };
|
|
6
5
|
import { ActionMode } from '../core/ActionMode';
|
|
7
6
|
export { ActionMode };
|
|
8
|
-
import { IndicatorButtonState } from '../core/IndicatorButtonState';
|
|
9
7
|
export interface ToggleGroupProps extends SelectButtonProps {
|
|
10
|
-
/**
|
|
11
|
-
* Label of the group/row. Can be any element.
|
|
12
|
-
*
|
|
13
|
-
* ## Examples
|
|
14
|
-
* ```
|
|
15
|
-
* <ToggleGroup label="Simple Text" />
|
|
16
|
-
* <ToggleGroup label={<span><i className="pi pi-check"></i> Icon and Text</span>} />
|
|
17
|
-
* <ToggleGroup label={<YourCustomIconComponent />} />
|
|
18
|
-
* ```
|
|
19
|
-
*/
|
|
20
8
|
label?: React.ReactNode;
|
|
21
|
-
/**
|
|
22
|
-
* Topic name to monitor for state indication.
|
|
23
|
-
* If `value` field is not undefined, then that value is used instead.
|
|
24
|
-
*/
|
|
25
9
|
topic?: string;
|
|
26
|
-
/**
|
|
27
|
-
* Color for the button when the state is TRUE.
|
|
28
|
-
*/
|
|
29
10
|
onColor?: IndicatorColor | IndicatorColor[];
|
|
30
|
-
/**
|
|
31
|
-
* Color for the button when the state is FALSE.
|
|
32
|
-
*/
|
|
33
11
|
offColor?: IndicatorColor;
|
|
34
|
-
/**
|
|
35
|
-
* Name of the command to invoke on button events.
|
|
36
|
-
* If command is "*", then the commandTopic will be dispatched
|
|
37
|
-
* internally.
|
|
38
|
-
*/
|
|
39
12
|
command?: string;
|
|
40
|
-
/**
|
|
41
|
-
* Optional topic parameter to send along with the command.
|
|
42
|
-
* If set, will automatically be included with commandArgs as
|
|
43
|
-
* the value of field 'topic.'
|
|
44
|
-
*/
|
|
45
13
|
commandTopic?: string;
|
|
46
|
-
/**
|
|
47
|
-
* Optional arguments sent with the command.
|
|
48
|
-
*/
|
|
49
14
|
commandArgs?: any;
|
|
50
|
-
/**
|
|
51
|
-
* Topic to disable button interaction.
|
|
52
|
-
*/
|
|
53
15
|
disableTopic?: string;
|
|
54
|
-
/**
|
|
55
|
-
* Topic to control the visibility of the button.
|
|
56
|
-
*/
|
|
57
16
|
invisibleTopic?: string;
|
|
58
|
-
/**
|
|
59
|
-
* Mode of input for the button (e.g., TAP, TOGGLE).
|
|
60
|
-
*/
|
|
61
17
|
actionMode?: ActionMode;
|
|
62
|
-
/**
|
|
63
|
-
* Inverts the signal values for TAP, PRESSED, and RELEASED modes.
|
|
64
|
-
*/
|
|
65
18
|
invert?: boolean;
|
|
66
19
|
}
|
|
67
|
-
export declare
|
|
68
|
-
|
|
69
|
-
constructor(props: ToggleGroupProps);
|
|
70
|
-
componentDidMount(): void;
|
|
71
|
-
componentDidUpdate(prevProps: ToggleGroupProps): void;
|
|
72
|
-
componentWillUnmount(): void;
|
|
73
|
-
/**
|
|
74
|
-
* Sets up subscriptions based on provided topics.
|
|
75
|
-
*/
|
|
76
|
-
private setupSubscriptions;
|
|
77
|
-
/**
|
|
78
|
-
* Handles updates for the main topic.
|
|
79
|
-
*/
|
|
80
|
-
private handleTopicUpdate;
|
|
81
|
-
/**
|
|
82
|
-
* Handles updates for the disable topic.
|
|
83
|
-
*/
|
|
84
|
-
private handleDisableTopicUpdate;
|
|
85
|
-
/**
|
|
86
|
-
* Handles updates for the invisible topic.
|
|
87
|
-
*/
|
|
88
|
-
private handleInvisibleTopicUpdate;
|
|
89
|
-
/**
|
|
90
|
-
* Handle the button being pressed down. Used for TAP and PRESSED action modes.
|
|
91
|
-
*/
|
|
92
|
-
protected handleOnPressed(): void;
|
|
93
|
-
/**
|
|
94
|
-
* Handle the button being released. Used for TAP and RELEASED action modes.
|
|
95
|
-
*/
|
|
96
|
-
protected handleOnReleased(): void;
|
|
97
|
-
/**
|
|
98
|
-
* Dispatch a value to any listeners.
|
|
99
|
-
* @param value The value to dispatch as part of the payload.
|
|
100
|
-
*/
|
|
101
|
-
protected dispatchCommand(value: any): void;
|
|
102
|
-
render(): import("react/jsx-runtime").JSX.Element;
|
|
103
|
-
}
|
|
20
|
+
export declare const ToggleGroup: React.FC<ToggleGroupProps>;
|
|
21
|
+
export default ToggleGroup;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
import{jsx as _jsx,jsxs as _jsxs}from"react/jsx-runtime";import{
|
|
1
|
+
import{jsx as _jsx,jsxs as _jsxs}from"react/jsx-runtime";import{useState,useEffect,useContext}from"react";import{SelectButton}from"primereact/selectbutton";import{EventEmitterContext}from"../core/EventEmitterContext";import{IndicatorColor}from"../core/IndicatorColor";export{IndicatorColor};import{ActionMode}from"../core/ActionMode";export{ActionMode};import clsx from"clsx";export const ToggleGroup=({label:o,topic:t,onColor:e,offColor:n,command:r,commandTopic:i,commandArgs:l,disableTopic:s,invisibleTopic:a,actionMode:c,invert:d,...u})=>{const[p]=useState((()=>`toggleGroup-${Math.random().toString(36).substr(2,9)}`)),[m,f]=useState(void 0),[g,v]=useState(!1),[x,b]=useState(!1),[h,I]=useState(!1),C=useContext(EventEmitterContext);useEffect((()=>(t&&C.subscribe(t,y),s&&C.subscribe(s,A),a&&C.subscribe(a,j),()=>{})),[t,s,a]);const y=o=>{f(o)},A=o=>{v(o)},j=o=>{b(o)},M=()=>{h||(I(!0),c!==ActionMode.Tap&&c!==ActionMode.Pressed||S(!0))},E=()=>{h&&(I(!1),c===ActionMode.Tap?S(!1):c===ActionMode.Released&&S(!0))},S=o=>{if(r&&r.length>0){const t={topic:i,value:o,...l};C.dispatch({topic:r,payload:t})}};let T=m;void 0!==u.value&&(T=u.value);let $=((o,t,e)=>{if(!t||0===t.length)return IndicatorColor.IndicatorInvalid;let n=Array.isArray(e)?e:void 0!==e?[e]:[IndicatorColor.IndicatorInvalid],r=typeof o;if("boolean"===r)return o?n[0]:n.length>1?n[1]:n[0];if("number"===r&&t.length>o){if(n.length>o){return n[o]}return n[0]}if("string"===r){let e=t.indexOf(o);return-1!==e&&e<n.length?n[e]:n[0]}return null!=e?Array.isArray(e)?e[0]:e:IndicatorColor.IndicatorInvalid})(T,u.options,e);void 0===T&&($=IndicatorColor.IndicatorInvalid);const _=void 0!==u.options&&null!==u.options&&void 0!==u.options.length&&u.options.length>2,N=`${p}-togglegroup-selectbutton-container`;return _jsxs("div",{className:"flex",children:[_jsx("style",{children:`\n ${void 0!==n?`\n .${N} .p-selectbutton .p-button {\n background-color: ${n};\n }\n `:""}\n .${N} .p-selectbutton .p-button.p-highlight {\n background-color: ${$} !important;\n border-color: ${$} !important;\n }\n `}),_jsx("div",{className:N,children:_jsxs("div",{className:"p-inputgroup",children:[_jsx("span",{className:"p-inputgroup-addon",style:{flexGrow:1},children:o}),_jsx(SelectButton,{...u,options:u.options,disabled:g||u.disabled,multiple:_,className:clsx(p,u.className,{"p-invalid":void 0===u.value}),style:x?{display:"none"}:{},value:((o,t)=>{if(null==t||0===t.length)return;let e=typeof o;if("boolean"==e){return o&&t.length>1?t[1]:t[0]}if("number"==e){let e=o;if(void 0!==e&&e<t.length)return t[e]}else if("string"==e)return o})(T,u.options),allowEmpty:!1,onMouseDown:M,onTouchStart:M,onMouseUp:E,onTouchEnd:E})]})})]})};export default ToggleGroup;
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import React from "react";
|
|
2
|
-
import { EventEmitterContext } from "../core/EventEmitterContext
|
|
2
|
+
import { EventEmitterContext } from "../core/EventEmitterContext";
|
|
3
3
|
/**
|
|
4
4
|
* Properties of the ValueInput component.
|
|
5
5
|
*/
|
|
@@ -105,6 +105,7 @@ interface ValueInputProps {
|
|
|
105
105
|
*/
|
|
106
106
|
interface ValueInputState {
|
|
107
107
|
entryValue: number | null;
|
|
108
|
+
currentValue: number | null;
|
|
108
109
|
editing: boolean;
|
|
109
110
|
}
|
|
110
111
|
/**
|
|
@@ -113,7 +114,7 @@ interface ValueInputState {
|
|
|
113
114
|
* accepting and rejecting values and keyboard management.
|
|
114
115
|
*/
|
|
115
116
|
export declare class ValueInput extends React.Component<ValueInputProps, ValueInputState> {
|
|
116
|
-
static contextType: React.Context<import("../core/EventEmitterContext
|
|
117
|
+
static contextType: React.Context<import("../core/EventEmitterContext").EventEmitterContextType>;
|
|
117
118
|
context: React.ContextType<typeof EventEmitterContext>;
|
|
118
119
|
/**
|
|
119
120
|
* Default properties for the component.
|
|
@@ -141,6 +142,7 @@ export declare class ValueInput extends React.Component<ValueInputProps, ValueIn
|
|
|
141
142
|
locale: string;
|
|
142
143
|
currency: string;
|
|
143
144
|
};
|
|
145
|
+
inputRef: React.RefObject<HTMLInputElement>;
|
|
144
146
|
/**
|
|
145
147
|
*
|
|
146
148
|
* @param {FooterViewProps} props
|
|
@@ -150,6 +152,7 @@ export declare class ValueInput extends React.Component<ValueInputProps, ValueIn
|
|
|
150
152
|
* The component has been loaded into the DOM.
|
|
151
153
|
*/
|
|
152
154
|
componentDidMount(): void;
|
|
155
|
+
private onBufferValue;
|
|
153
156
|
/**
|
|
154
157
|
* The user has elected to accept the input value. Validate and store, if valid.
|
|
155
158
|
*/
|
|
@@ -1 +1 @@
|
|
|
1
|
-
import{jsx as _jsx,jsxs as _jsxs}from"react/jsx-runtime";import React
|
|
1
|
+
import{jsx as _jsx,jsxs as _jsxs}from"react/jsx-runtime";import React,{createRef}from"react";import{InputNumber}from"primereact/inputnumber";import{Button}from"primereact/button";import{EventEmitterContext}from"../core/EventEmitterContext";export class ValueInput extends React.Component{constructor(t){super(t),Object.defineProperty(this,"inputRef",{enumerable:!0,configurable:!0,writable:!0,value:void 0}),this.state={entryValue:t.value,currentValue:t.value,editing:!1},this.inputRef=createRef()}componentDidMount(){}onBufferValue(t){null!==t&&(this.state.editing?this.setState({entryValue:t}):this.setState({entryValue:this.state.currentValue,editing:!0},(()=>{setTimeout((()=>{this.inputRef.current&&this.inputRef.current.focus()}),0)})))}onAcceptValue(){null!==this.state.entryValue&&(this.setState({editing:!1,currentValue:this.state.entryValue}),this.props.onValueChanged&&this.props.onValueChanged(this.state.entryValue),void 0!==this.props.dispatchTopic&&this.context.dispatch({topic:this.props.dispatchTopic,payload:this.state.entryValue}))}onResetValue(){this.state.editing&&this.setState({currentValue:this.state.currentValue,entryValue:this.state.currentValue,editing:!1})}render(){return _jsxs("div",{children:[_jsxs("div",{className:"p-inputgroup flex-1",children:[_jsx("span",{className:"p-inputgroup-addon",children:this.props.label}),_jsx(InputNumber,{inputRef:this.inputRef,min:this.props.min,max:this.props.max,minFractionDigits:this.props.minPrecision,maxFractionDigits:this.props.maxPrecision,mode:this.props.mode,prefix:this.props.prefix,suffix:this.props.suffix,showButtons:this.props.showButtons,step:this.props.step,placeholder:this.props.placeholder,value:this.state.currentValue,onChange:t=>{this.onBufferValue(t.value)},buttonLayout:"horizontal",decrementButtonClassName:"p-button-danger",incrementButtonClassName:"p-button-success",incrementButtonIcon:"pi pi-plus",decrementButtonIcon:"pi pi-minus",locale:"en-US",currency:this.props.currency,onKeyDown:t=>{"Enter"===t.key?this.onAcceptValue():"Escape"===t.key&&this.onResetValue()},disabled:this.props.disabled,autoFocus:!1},this.state.editing?"editing":"not-editing"),_jsx(Button,{icon:"pi pi-check",disabled:this.props.disabled||!this.state.editing,className:"p-button-success",onClick:()=>this.onAcceptValue(),visible:this.state.editing,size:"small",autoFocus:!1}),_jsx(Button,{icon:"pi pi-times",disabled:this.props.disabled||!this.state.editing,className:"p-button-danger",onClickCapture:()=>this.onResetValue(),visible:this.state.editing,size:"small",autoFocus:!1})]}),void 0!==this.props.description&&_jsx("small",{children:this.props.description})]})}}Object.defineProperty(ValueInput,"contextType",{enumerable:!0,configurable:!0,writable:!0,value:EventEmitterContext}),Object.defineProperty(ValueInput,"defaultProps",{enumerable:!0,configurable:!0,writable:!0,value:{label:"",value:void 0,keyFilter:void 0,writeTopic:void 0,onValueChanged:void 0,description:void 0,prefix:void 0,suffix:void 0,disabled:!1,dispatchTopic:void 0,placeholder:void 0,validator:void 0,min:void 0,max:void 0,minPrecision:0,maxPrecision:3,mode:"decimal",showButtons:!1,step:1,locale:"en-US",currency:"USD"}});
|
package/package.json
CHANGED
|
@@ -2,428 +2,284 @@
|
|
|
2
2
|
* Copyright (C) 2024 Automated Design Corp.. All Rights Reserved.
|
|
3
3
|
* Created Date: 2024-03-12 10:14:48
|
|
4
4
|
* -----
|
|
5
|
-
* Last Modified: 2024-
|
|
5
|
+
* Last Modified: 2024-04-16 09:16:59
|
|
6
6
|
* -----
|
|
7
7
|
*
|
|
8
8
|
*/
|
|
9
9
|
|
|
10
|
-
import {
|
|
10
|
+
import React, { useState, useEffect, useContext } from 'react';
|
|
11
11
|
import { SelectButton, SelectButtonProps } from 'primereact/selectbutton';
|
|
12
12
|
import {SelectItemOptionsType} from "primereact/selectitem";
|
|
13
13
|
|
|
14
|
-
import { EventEmitterContext
|
|
14
|
+
import { EventEmitterContext} from '../core/EventEmitterContext';
|
|
15
15
|
import {IndicatorColor} from "../core/IndicatorColor";
|
|
16
16
|
export {IndicatorColor}
|
|
17
17
|
import { ActionMode } from '../core/ActionMode';
|
|
18
18
|
export {ActionMode};
|
|
19
19
|
|
|
20
|
-
import
|
|
20
|
+
import clsx from 'clsx';
|
|
21
21
|
|
|
22
22
|
|
|
23
23
|
|
|
24
24
|
export interface ToggleGroupProps extends SelectButtonProps {
|
|
25
|
-
|
|
26
|
-
/**
|
|
27
|
-
* Label of the group/row. Can be any element.
|
|
28
|
-
*
|
|
29
|
-
* ## Examples
|
|
30
|
-
* ```
|
|
31
|
-
* <ToggleGroup label="Simple Text" />
|
|
32
|
-
* <ToggleGroup label={<span><i className="pi pi-check"></i> Icon and Text</span>} />
|
|
33
|
-
* <ToggleGroup label={<YourCustomIconComponent />} />
|
|
34
|
-
* ```
|
|
35
|
-
*/
|
|
36
|
-
label? : React.ReactNode;
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
/**
|
|
40
|
-
* Topic name to monitor for state indication.
|
|
41
|
-
* If `value` field is not undefined, then that value is used instead.
|
|
42
|
-
*/
|
|
25
|
+
label?: React.ReactNode;
|
|
43
26
|
topic?: string;
|
|
44
|
-
|
|
45
|
-
/**
|
|
46
|
-
* Color for the button when the state is TRUE.
|
|
47
|
-
*/
|
|
48
27
|
onColor?: IndicatorColor | IndicatorColor[];
|
|
49
|
-
|
|
50
|
-
/**
|
|
51
|
-
* Color for the button when the state is FALSE.
|
|
52
|
-
*/
|
|
53
28
|
offColor?: IndicatorColor;
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
/**
|
|
57
|
-
* Name of the command to invoke on button events.
|
|
58
|
-
* If command is "*", then the commandTopic will be dispatched
|
|
59
|
-
* internally.
|
|
60
|
-
*/
|
|
61
29
|
command?: string;
|
|
62
|
-
|
|
63
|
-
/**
|
|
64
|
-
* Optional topic parameter to send along with the command.
|
|
65
|
-
* If set, will automatically be included with commandArgs as
|
|
66
|
-
* the value of field 'topic.'
|
|
67
|
-
*/
|
|
68
|
-
commandTopic? : string;
|
|
69
|
-
|
|
70
|
-
/**
|
|
71
|
-
* Optional arguments sent with the command.
|
|
72
|
-
*/
|
|
30
|
+
commandTopic?: string;
|
|
73
31
|
commandArgs?: any;
|
|
74
|
-
|
|
75
|
-
/**
|
|
76
|
-
* Topic to disable button interaction.
|
|
77
|
-
*/
|
|
78
32
|
disableTopic?: string;
|
|
79
|
-
|
|
80
|
-
/**
|
|
81
|
-
* Topic to control the visibility of the button.
|
|
82
|
-
*/
|
|
83
33
|
invisibleTopic?: string;
|
|
84
|
-
|
|
85
|
-
/**
|
|
86
|
-
* Mode of input for the button (e.g., TAP, TOGGLE).
|
|
87
|
-
*/
|
|
88
34
|
actionMode?: ActionMode;
|
|
89
|
-
|
|
90
|
-
/**
|
|
91
|
-
* Inverts the signal values for TAP, PRESSED, and RELEASED modes.
|
|
92
|
-
*/
|
|
93
35
|
invert?: boolean;
|
|
94
36
|
}
|
|
95
37
|
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
let b = currentValue as boolean;
|
|
131
|
-
if (b) {
|
|
132
|
-
if (options.length > 1 )
|
|
133
|
-
return options[1];
|
|
134
|
-
else
|
|
135
|
-
return options[0];
|
|
136
|
-
}
|
|
137
|
-
else {
|
|
138
|
-
return options[0];
|
|
139
|
-
}
|
|
140
|
-
}
|
|
141
|
-
else if (t == "number") {
|
|
142
|
-
let n = currentValue as number;
|
|
143
|
-
if (n !== undefined && n < options.length ) {
|
|
144
|
-
return options[n];
|
|
145
|
-
}
|
|
146
|
-
}
|
|
147
|
-
else if (t == "string") {
|
|
148
|
-
// The SelectButton should match to this value automatically, if it's in the
|
|
149
|
-
// options array. No reason to search twice.
|
|
150
|
-
return currentValue;
|
|
151
|
-
}
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
return undefined;
|
|
155
|
-
}
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
/**
|
|
160
|
-
*
|
|
161
|
-
* @param currentValue
|
|
162
|
-
* @param options
|
|
163
|
-
* @returns
|
|
164
|
-
*/
|
|
165
|
-
|
|
166
|
-
function selectOnColor(
|
|
167
|
-
currentValue: any,
|
|
168
|
-
options: SelectItemOptionsType | undefined,
|
|
169
|
-
onColorProp: IndicatorColor | IndicatorColor[] | undefined
|
|
170
|
-
): IndicatorColor {
|
|
171
|
-
|
|
172
|
-
if (!options || options.length === 0)
|
|
173
|
-
return IndicatorColor.IndicatorInvalid;
|
|
174
|
-
|
|
175
|
-
let colorArray =
|
|
176
|
-
Array.isArray(onColorProp) ? onColorProp :
|
|
177
|
-
onColorProp !== undefined ? [onColorProp] : [IndicatorColor.IndicatorInvalid];
|
|
178
|
-
|
|
179
|
-
let t = typeof(currentValue);
|
|
180
|
-
if (t === "boolean") {
|
|
181
|
-
return currentValue ? colorArray[0] : colorArray.length > 1 ? colorArray[1] : colorArray[0];
|
|
182
|
-
}
|
|
183
|
-
else if (t === "number" && options.length > currentValue) {
|
|
184
|
-
if (colorArray.length > currentValue) {
|
|
185
|
-
let index = currentValue as number;
|
|
186
|
-
return colorArray[index];
|
|
187
|
-
}
|
|
188
|
-
else {
|
|
189
|
-
return colorArray[0];
|
|
190
|
-
}
|
|
191
|
-
}
|
|
192
|
-
else if (t === "string") {
|
|
193
|
-
let index = options.indexOf(currentValue);
|
|
194
|
-
if (index !== -1 && index < colorArray.length)
|
|
195
|
-
return colorArray[index];
|
|
196
|
-
else
|
|
197
|
-
return colorArray[0];
|
|
198
|
-
}
|
|
199
|
-
|
|
200
|
-
if (onColorProp !== undefined && onColorProp !== null) {
|
|
201
|
-
return Array.isArray(onColorProp) ? onColorProp[0] : onColorProp as IndicatorColor;
|
|
202
|
-
}
|
|
203
|
-
else {
|
|
204
|
-
return IndicatorColor.IndicatorInvalid;
|
|
205
|
-
}
|
|
206
|
-
|
|
207
|
-
}
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
export class ToggleGroup extends Component<ToggleGroupProps, IndicatorButtonState> {
|
|
211
|
-
|
|
212
|
-
static contextType = EventEmitterContext;
|
|
213
|
-
|
|
214
|
-
constructor(props: ToggleGroupProps) {
|
|
215
|
-
super(props);
|
|
216
|
-
this.state = {
|
|
217
|
-
currentValue: undefined,
|
|
218
|
-
isDisabled: false,
|
|
219
|
-
isInvisible: false,
|
|
220
|
-
isPressed: false
|
|
38
|
+
export const ToggleGroup: React.FC<ToggleGroupProps> = ({
|
|
39
|
+
label,
|
|
40
|
+
topic,
|
|
41
|
+
onColor,
|
|
42
|
+
offColor,
|
|
43
|
+
command,
|
|
44
|
+
commandTopic,
|
|
45
|
+
commandArgs,
|
|
46
|
+
disableTopic,
|
|
47
|
+
invisibleTopic,
|
|
48
|
+
actionMode,
|
|
49
|
+
invert,
|
|
50
|
+
...restProps
|
|
51
|
+
}) => {
|
|
52
|
+
|
|
53
|
+
const [uniqueId] = useState(() => `toggleGroup-${Math.random().toString(36).substr(2, 9)}`);
|
|
54
|
+
|
|
55
|
+
const [currentValue, setCurrentValue] = useState<any>(undefined);
|
|
56
|
+
const [isDisabled, setIsDisabled] = useState<boolean>(false);
|
|
57
|
+
const [isInvisible, setIsInvisible] = useState<boolean>(false);
|
|
58
|
+
const [isPressed, setIsPressed] = useState<boolean>(false);
|
|
59
|
+
const context = useContext(EventEmitterContext);
|
|
60
|
+
|
|
61
|
+
useEffect(() => {
|
|
62
|
+
const setupSubscriptions = () => {
|
|
63
|
+
if (topic) {
|
|
64
|
+
context.subscribe(topic, handleTopicUpdate);
|
|
65
|
+
}
|
|
66
|
+
if (disableTopic) {
|
|
67
|
+
context.subscribe(disableTopic, handleDisableTopicUpdate);
|
|
68
|
+
}
|
|
69
|
+
if (invisibleTopic) {
|
|
70
|
+
context.subscribe(invisibleTopic, handleInvisibleTopicUpdate);
|
|
71
|
+
}
|
|
221
72
|
};
|
|
222
|
-
}
|
|
223
73
|
|
|
224
|
-
|
|
225
|
-
this.setupSubscriptions();
|
|
226
|
-
}
|
|
74
|
+
setupSubscriptions();
|
|
227
75
|
|
|
228
|
-
|
|
229
|
-
|
|
230
|
-
|
|
231
|
-
}
|
|
232
|
-
|
|
233
|
-
componentWillUnmount() {
|
|
234
|
-
// Unsubscribe logic if needed
|
|
235
|
-
}
|
|
236
|
-
|
|
237
|
-
/**
|
|
238
|
-
* Sets up subscriptions based on provided topics.
|
|
239
|
-
*/
|
|
240
|
-
private setupSubscriptions() {
|
|
241
|
-
const { topic, disableTopic, invisibleTopic } = this.props;
|
|
242
|
-
const { subscribe } = this.context as EventEmitterContextType;
|
|
243
|
-
|
|
244
|
-
if (topic) {
|
|
245
|
-
// Subscribe to the main topic
|
|
246
|
-
subscribe(topic, this.handleTopicUpdate);
|
|
247
|
-
}
|
|
248
|
-
|
|
249
|
-
if (disableTopic) {
|
|
250
|
-
// Subscribe to the disable topic
|
|
251
|
-
subscribe(disableTopic, this.handleDisableTopicUpdate);
|
|
252
|
-
}
|
|
253
|
-
|
|
254
|
-
if (invisibleTopic) {
|
|
255
|
-
// Subscribe to the invisible topic
|
|
256
|
-
subscribe(invisibleTopic, this.handleInvisibleTopicUpdate);
|
|
257
|
-
}
|
|
258
|
-
}
|
|
76
|
+
return () => {
|
|
77
|
+
// Unsubscribe logic here
|
|
78
|
+
};
|
|
79
|
+
}, [topic, disableTopic, invisibleTopic]);
|
|
259
80
|
|
|
260
|
-
|
|
261
|
-
|
|
262
|
-
*/
|
|
263
|
-
private handleTopicUpdate = (value: boolean) => {
|
|
264
|
-
this.setState({ currentValue: value });
|
|
81
|
+
const handleTopicUpdate = (value: boolean) => {
|
|
82
|
+
setCurrentValue(value);
|
|
265
83
|
};
|
|
266
84
|
|
|
267
|
-
|
|
268
|
-
|
|
269
|
-
*/
|
|
270
|
-
private handleDisableTopicUpdate = (value: boolean) => {
|
|
271
|
-
this.setState({ isDisabled: value });
|
|
85
|
+
const handleDisableTopicUpdate = (value: boolean) => {
|
|
86
|
+
setIsDisabled(value);
|
|
272
87
|
};
|
|
273
88
|
|
|
274
|
-
|
|
275
|
-
|
|
276
|
-
|
|
277
|
-
private handleInvisibleTopicUpdate = (value: boolean) => {
|
|
278
|
-
this.setState({ isInvisible: value });
|
|
279
|
-
};
|
|
280
|
-
|
|
89
|
+
const handleInvisibleTopicUpdate = (value: boolean) => {
|
|
90
|
+
setIsInvisible(value);
|
|
91
|
+
};
|
|
281
92
|
|
|
282
|
-
|
|
283
|
-
* Handle the button being pressed down. Used for TAP and PRESSED action modes.
|
|
284
|
-
*/
|
|
285
|
-
protected handleOnPressed() {
|
|
286
|
-
const { isPressed } = this.state;
|
|
287
|
-
const {actionMode} = this.props;
|
|
288
|
-
|
|
93
|
+
const handleOnPressed = () => {
|
|
289
94
|
if (!isPressed) {
|
|
290
|
-
|
|
291
|
-
|
|
95
|
+
setIsPressed(true);
|
|
292
96
|
if (actionMode === ActionMode.Tap || actionMode === ActionMode.Pressed) {
|
|
293
|
-
|
|
97
|
+
dispatchCommand(true);
|
|
294
98
|
}
|
|
295
99
|
}
|
|
296
|
-
}
|
|
100
|
+
};
|
|
297
101
|
|
|
298
|
-
|
|
299
|
-
* Handle the button being released. Used for TAP and RELEASED action modes.
|
|
300
|
-
*/
|
|
301
|
-
protected handleOnReleased() {
|
|
302
|
-
const { isPressed } = this.state;
|
|
303
|
-
const {actionMode} = this.props;
|
|
304
|
-
|
|
102
|
+
const handleOnReleased = () => {
|
|
305
103
|
if (isPressed) {
|
|
306
|
-
|
|
307
|
-
|
|
308
|
-
|
|
309
|
-
|
|
310
|
-
|
|
311
|
-
else if (actionMode === ActionMode.Released) {
|
|
312
|
-
this.dispatchCommand(true);
|
|
104
|
+
setIsPressed(false);
|
|
105
|
+
if (actionMode === ActionMode.Tap) {
|
|
106
|
+
dispatchCommand(false);
|
|
107
|
+
} else if (actionMode === ActionMode.Released) {
|
|
108
|
+
dispatchCommand(true);
|
|
313
109
|
}
|
|
314
110
|
}
|
|
315
|
-
}
|
|
316
|
-
|
|
317
|
-
|
|
318
|
-
/**
|
|
319
|
-
* Dispatch a value to any listeners.
|
|
320
|
-
* @param value The value to dispatch as part of the payload.
|
|
321
|
-
*/
|
|
322
|
-
protected dispatchCommand(value : any) {
|
|
323
|
-
|
|
324
|
-
const {command, commandTopic, commandArgs} = this.props;
|
|
325
|
-
const { dispatch } = this.context as EventEmitterContextType;
|
|
111
|
+
};
|
|
326
112
|
|
|
327
|
-
|
|
328
|
-
{
|
|
113
|
+
const dispatchCommand = (value: any) => {
|
|
114
|
+
if (command && command.length > 0) {
|
|
329
115
|
const payload = {
|
|
330
116
|
topic: commandTopic,
|
|
331
117
|
value: value,
|
|
332
|
-
...commandArgs
|
|
118
|
+
...commandArgs
|
|
333
119
|
};
|
|
334
120
|
|
|
335
|
-
dispatch({
|
|
121
|
+
context.dispatch({
|
|
336
122
|
topic: command,
|
|
337
123
|
payload: payload
|
|
338
124
|
});
|
|
339
|
-
|
|
340
125
|
}
|
|
126
|
+
};
|
|
341
127
|
|
|
128
|
+
|
|
129
|
+
let displayValue = currentValue;
|
|
130
|
+
if (restProps.value !== undefined) {
|
|
131
|
+
displayValue = restProps.value;
|
|
342
132
|
}
|
|
343
133
|
|
|
344
134
|
|
|
135
|
+
/**
|
|
136
|
+
*
|
|
137
|
+
* @param currentValue
|
|
138
|
+
* @param options
|
|
139
|
+
* @returns
|
|
140
|
+
*/
|
|
345
141
|
|
|
142
|
+
const selectOnColor = (
|
|
143
|
+
currentValue: any,
|
|
144
|
+
options: SelectItemOptionsType | undefined,
|
|
145
|
+
onColorProp: IndicatorColor | IndicatorColor[] | undefined
|
|
146
|
+
): IndicatorColor => {
|
|
346
147
|
|
|
347
|
-
|
|
348
|
-
|
|
349
|
-
// const { className, severity, label, raised,
|
|
350
|
-
// onColor, offColor, options, topic, command,
|
|
351
|
-
// commandArgs, disableTopic, invisibleTopic, inputMode, invert,
|
|
352
|
-
// onIcon, offIcon, icon,
|
|
353
|
-
// ...restProps
|
|
354
|
-
// } = this.props;
|
|
148
|
+
if (!options || options.length === 0)
|
|
149
|
+
return IndicatorColor.IndicatorInvalid;
|
|
355
150
|
|
|
151
|
+
let colorArray =
|
|
152
|
+
Array.isArray(onColorProp) ? onColorProp :
|
|
153
|
+
onColorProp !== undefined ? [onColorProp] : [IndicatorColor.IndicatorInvalid];
|
|
356
154
|
|
|
357
|
-
|
|
358
|
-
|
|
359
|
-
|
|
360
|
-
|
|
361
|
-
|
|
155
|
+
let t = typeof (currentValue);
|
|
156
|
+
if (t === "boolean") {
|
|
157
|
+
return currentValue ? colorArray[0] : colorArray.length > 1 ? colorArray[1] : colorArray[0];
|
|
158
|
+
}
|
|
159
|
+
else if (t === "number" && options.length > currentValue) {
|
|
160
|
+
if (colorArray.length > currentValue) {
|
|
161
|
+
let index = currentValue as number;
|
|
162
|
+
return colorArray[index];
|
|
163
|
+
}
|
|
164
|
+
else {
|
|
165
|
+
return colorArray[0];
|
|
166
|
+
}
|
|
167
|
+
}
|
|
168
|
+
else if (t === "string") {
|
|
169
|
+
let index = options.indexOf(currentValue);
|
|
170
|
+
if (index !== -1 && index < colorArray.length)
|
|
171
|
+
return colorArray[index];
|
|
172
|
+
else
|
|
173
|
+
return colorArray[0];
|
|
174
|
+
}
|
|
362
175
|
|
|
176
|
+
if (onColorProp !== undefined && onColorProp !== null) {
|
|
177
|
+
return Array.isArray(onColorProp) ? onColorProp[0] : onColorProp as IndicatorColor;
|
|
178
|
+
}
|
|
179
|
+
else {
|
|
180
|
+
return IndicatorColor.IndicatorInvalid;
|
|
181
|
+
}
|
|
363
182
|
|
|
364
|
-
|
|
365
|
-
// if (btnIcon === undefined || btnIcon === null || btnIcon.length === 0)
|
|
366
|
-
// btnIcon = icon;
|
|
183
|
+
}
|
|
367
184
|
|
|
368
185
|
|
|
369
|
-
|
|
370
|
-
|
|
371
|
-
|
|
372
|
-
|
|
373
|
-
|
|
374
|
-
|
|
375
|
-
|
|
186
|
+
/**
|
|
187
|
+
*
|
|
188
|
+
* @param currentValue
|
|
189
|
+
* @param options
|
|
190
|
+
* @returns
|
|
191
|
+
*/
|
|
192
|
+
const matchCurrentValue = (currentValue: any, options: SelectItemOptionsType | undefined): any => {
|
|
193
|
+
|
|
194
|
+
if (options === undefined || options === null || options.length === 0)
|
|
195
|
+
return undefined;
|
|
196
|
+
|
|
197
|
+
let t = typeof (currentValue);
|
|
198
|
+
if (t == "boolean") {
|
|
199
|
+
let b = currentValue as boolean;
|
|
200
|
+
if (b) {
|
|
201
|
+
if (options.length > 1)
|
|
202
|
+
return options[1];
|
|
203
|
+
else
|
|
204
|
+
return options[0];
|
|
205
|
+
}
|
|
206
|
+
else {
|
|
207
|
+
return options[0];
|
|
208
|
+
}
|
|
376
209
|
}
|
|
377
|
-
|
|
378
|
-
|
|
379
|
-
|
|
380
|
-
|
|
381
|
-
|
|
382
|
-
|
|
210
|
+
else if (t == "number") {
|
|
211
|
+
let n = currentValue as number;
|
|
212
|
+
if (n !== undefined && n < options.length) {
|
|
213
|
+
return options[n];
|
|
214
|
+
}
|
|
215
|
+
}
|
|
216
|
+
else if (t == "string") {
|
|
217
|
+
// The SelectButton should match to this value automatically, if it's in the
|
|
218
|
+
// options array. No reason to search twice.
|
|
219
|
+
return currentValue;
|
|
383
220
|
}
|
|
384
221
|
|
|
385
|
-
|
|
386
|
-
|
|
387
|
-
|
|
388
|
-
|
|
389
|
-
|
|
390
|
-
|
|
391
|
-
|
|
392
|
-
|
|
393
|
-
|
|
394
|
-
|
|
395
|
-
|
|
396
|
-
|
|
397
|
-
|
|
398
|
-
|
|
399
|
-
|
|
400
|
-
|
|
401
|
-
|
|
402
|
-
|
|
403
|
-
|
|
222
|
+
|
|
223
|
+
return undefined;
|
|
224
|
+
}
|
|
225
|
+
|
|
226
|
+
|
|
227
|
+
let color = selectOnColor(displayValue, restProps.options, onColor);
|
|
228
|
+
|
|
229
|
+
if (displayValue === undefined) {
|
|
230
|
+
color = IndicatorColor.IndicatorInvalid;
|
|
231
|
+
}
|
|
232
|
+
|
|
233
|
+
const isMultiple = restProps.options !== undefined
|
|
234
|
+
&& restProps.options !== null
|
|
235
|
+
&& restProps.options.length !== undefined
|
|
236
|
+
&& restProps.options.length > 2
|
|
237
|
+
;
|
|
238
|
+
|
|
239
|
+
|
|
240
|
+
const toggleGroupName = `${uniqueId}-togglegroup-selectbutton-container`;
|
|
241
|
+
|
|
242
|
+
return (
|
|
243
|
+
<div className="flex">
|
|
244
|
+
{
|
|
245
|
+
<style>{`
|
|
246
|
+
${offColor !== undefined ? `
|
|
247
|
+
.${toggleGroupName} .p-selectbutton .p-button {
|
|
248
|
+
background-color: ${offColor};
|
|
404
249
|
}
|
|
405
|
-
`}
|
|
250
|
+
` : ''}
|
|
251
|
+
.${toggleGroupName} .p-selectbutton .p-button.p-highlight {
|
|
252
|
+
background-color: ${color} !important;
|
|
253
|
+
border-color: ${color} !important;
|
|
254
|
+
}
|
|
255
|
+
`}
|
|
406
256
|
</style>
|
|
407
|
-
|
|
408
|
-
|
|
257
|
+
}
|
|
258
|
+
|
|
259
|
+
<div className={toggleGroupName}>
|
|
260
|
+
|
|
261
|
+
<div className="p-inputgroup">
|
|
262
|
+
|
|
263
|
+
<span className="p-inputgroup-addon" style={{ flexGrow: 1 }}>
|
|
409
264
|
{label}
|
|
410
|
-
</span>
|
|
265
|
+
</span>
|
|
411
266
|
<SelectButton {...restProps}
|
|
412
|
-
options={options}
|
|
413
|
-
disabled={isDisabled || disabled}
|
|
267
|
+
options={restProps.options}
|
|
268
|
+
disabled={isDisabled || restProps.disabled}
|
|
414
269
|
multiple={isMultiple}
|
|
415
|
-
className={
|
|
416
|
-
{
|
|
417
|
-
value={matchCurrentValue(displayValue, options)}
|
|
418
|
-
allowEmpty={false}
|
|
419
|
-
onMouseDown={
|
|
420
|
-
onTouchStart={
|
|
421
|
-
onMouseUp={
|
|
422
|
-
onTouchEnd={
|
|
270
|
+
className={clsx(uniqueId, restProps.className, { 'p-invalid': restProps.value === undefined })}
|
|
271
|
+
style={isInvisible ? { display: 'none' } : {}}
|
|
272
|
+
value={matchCurrentValue(displayValue, restProps.options)}
|
|
273
|
+
allowEmpty={false}
|
|
274
|
+
onMouseDown={handleOnPressed}
|
|
275
|
+
onTouchStart={handleOnPressed}
|
|
276
|
+
onMouseUp={handleOnReleased}
|
|
277
|
+
onTouchEnd={handleOnReleased}
|
|
423
278
|
/>
|
|
424
|
-
</div>
|
|
279
|
+
</div>
|
|
425
280
|
</div>
|
|
426
|
-
|
|
427
|
-
|
|
281
|
+
</div>
|
|
282
|
+
);
|
|
283
|
+
};
|
|
428
284
|
|
|
429
|
-
|
|
285
|
+
export default ToggleGroup;
|
|
@@ -2,18 +2,18 @@
|
|
|
2
2
|
* Copyright (C) 2024 Automated Design Corp.. All Rights Reserved.
|
|
3
3
|
* Created Date: 2024-03-20 13:05:42
|
|
4
4
|
* -----
|
|
5
|
-
* Last Modified: 2024-
|
|
5
|
+
* Last Modified: 2024-04-16 19:06:17
|
|
6
6
|
* -----
|
|
7
7
|
*
|
|
8
8
|
*/
|
|
9
9
|
|
|
10
10
|
|
|
11
|
-
import React from "react";
|
|
11
|
+
import React, { createRef } from "react";
|
|
12
12
|
|
|
13
|
-
import { InputNumber} from 'primereact/inputnumber';
|
|
13
|
+
import { InputNumber } from 'primereact/inputnumber';
|
|
14
14
|
import { Button } from "primereact/button";
|
|
15
15
|
|
|
16
|
-
import { EventEmitterContext } from "../core/EventEmitterContext
|
|
16
|
+
import { EventEmitterContext } from "../core/EventEmitterContext";
|
|
17
17
|
|
|
18
18
|
/**
|
|
19
19
|
* Properties of the ValueInput component.
|
|
@@ -23,23 +23,23 @@ interface ValueInputProps {
|
|
|
23
23
|
/**
|
|
24
24
|
* The label for the ValueInput field.
|
|
25
25
|
*/
|
|
26
|
-
label
|
|
26
|
+
label: React.ReactNode | undefined;
|
|
27
27
|
|
|
28
28
|
|
|
29
29
|
/**
|
|
30
30
|
* The value for the field.
|
|
31
31
|
*/
|
|
32
|
-
value
|
|
32
|
+
value: number | null;
|
|
33
33
|
|
|
34
34
|
/**
|
|
35
35
|
* Minimum value for the field.
|
|
36
36
|
*/
|
|
37
|
-
min
|
|
37
|
+
min: number | undefined;
|
|
38
38
|
|
|
39
39
|
/**
|
|
40
40
|
* Minimum value for the field.
|
|
41
41
|
*/
|
|
42
|
-
max
|
|
42
|
+
max: number | undefined;
|
|
43
43
|
|
|
44
44
|
/**
|
|
45
45
|
* Minimum number of decimal points. The user will not
|
|
@@ -49,7 +49,7 @@ interface ValueInputProps {
|
|
|
49
49
|
* the component will throw an error.
|
|
50
50
|
* @default 0
|
|
51
51
|
*/
|
|
52
|
-
minPrecision
|
|
52
|
+
minPrecision: number | undefined;
|
|
53
53
|
|
|
54
54
|
|
|
55
55
|
/**
|
|
@@ -58,7 +58,7 @@ interface ValueInputProps {
|
|
|
58
58
|
* the component will throw an error.
|
|
59
59
|
* @default 3
|
|
60
60
|
*/
|
|
61
|
-
maxPrecision
|
|
61
|
+
maxPrecision: number | undefined;
|
|
62
62
|
|
|
63
63
|
|
|
64
64
|
/**
|
|
@@ -67,7 +67,7 @@ interface ValueInputProps {
|
|
|
67
67
|
* currency type using the currency property.
|
|
68
68
|
* @default "decimal"
|
|
69
69
|
*/
|
|
70
|
-
mode
|
|
70
|
+
mode: "currency" | "decimal" | undefined;
|
|
71
71
|
|
|
72
72
|
|
|
73
73
|
/**
|
|
@@ -78,19 +78,19 @@ interface ValueInputProps {
|
|
|
78
78
|
*
|
|
79
79
|
* @default "USD"
|
|
80
80
|
*/
|
|
81
|
-
currency
|
|
82
|
-
|
|
81
|
+
currency: string;
|
|
82
|
+
|
|
83
83
|
/**
|
|
84
84
|
* An optional prefix before the value of the field.
|
|
85
85
|
* Unlike the TextInput control, this prefix is internal to the field.
|
|
86
86
|
*/
|
|
87
|
-
prefix
|
|
87
|
+
prefix: string | undefined;
|
|
88
88
|
|
|
89
89
|
/**
|
|
90
90
|
* An optional suffix after the value of the field.
|
|
91
91
|
* Unlike the TextInput control, this prefix is internal to the field.
|
|
92
92
|
*/
|
|
93
|
-
suffix
|
|
93
|
+
suffix: string | undefined;
|
|
94
94
|
|
|
95
95
|
/**
|
|
96
96
|
* Set true to display buttons to increment/decrement the value.
|
|
@@ -98,12 +98,12 @@ interface ValueInputProps {
|
|
|
98
98
|
*
|
|
99
99
|
* @default false
|
|
100
100
|
*/
|
|
101
|
-
showButtons
|
|
101
|
+
showButtons: boolean;
|
|
102
102
|
|
|
103
103
|
/**
|
|
104
104
|
* The amount clicking an increment/decrement buttion will change the value.
|
|
105
105
|
*/
|
|
106
|
-
step
|
|
106
|
+
step: number | undefined;
|
|
107
107
|
|
|
108
108
|
|
|
109
109
|
/**
|
|
@@ -112,40 +112,41 @@ interface ValueInputProps {
|
|
|
112
112
|
*
|
|
113
113
|
* @default "en-US"
|
|
114
114
|
*/
|
|
115
|
-
locale
|
|
115
|
+
locale: string | undefined;
|
|
116
116
|
|
|
117
117
|
/**
|
|
118
118
|
* A small, advisory text below the field.
|
|
119
119
|
*/
|
|
120
|
-
description
|
|
120
|
+
description: React.ReactNode | undefined;
|
|
121
121
|
|
|
122
122
|
/**
|
|
123
123
|
* If true, all functions of the field will be disabled.
|
|
124
124
|
*/
|
|
125
|
-
disabled
|
|
126
|
-
|
|
125
|
+
disabled: boolean | undefined;
|
|
126
|
+
|
|
127
127
|
/** Topic on which the value will be dispatched through the user interfave on successful data entry. */
|
|
128
|
-
dispatchTopic
|
|
128
|
+
dispatchTopic: string | undefined;
|
|
129
129
|
|
|
130
130
|
/**
|
|
131
131
|
* Placeholder string to display if the value is empty.
|
|
132
132
|
*/
|
|
133
|
-
placeholder
|
|
133
|
+
placeholder: string | undefined;
|
|
134
134
|
|
|
135
135
|
/**
|
|
136
136
|
* The user has accepted a new value.
|
|
137
137
|
* @param newValue New value accepted by the user.
|
|
138
|
-
*/
|
|
139
|
-
onValueChanged?(newValue: number)
|
|
138
|
+
*/
|
|
139
|
+
onValueChanged?(newValue: number): void;
|
|
140
140
|
}
|
|
141
141
|
|
|
142
142
|
/**
|
|
143
143
|
* State variables of the ValueInput component.
|
|
144
144
|
*/
|
|
145
145
|
interface ValueInputState {
|
|
146
|
-
|
|
147
|
-
entryValue
|
|
148
|
-
|
|
146
|
+
|
|
147
|
+
entryValue: number | null;
|
|
148
|
+
currentValue: number | null;
|
|
149
|
+
editing: boolean;
|
|
149
150
|
}
|
|
150
151
|
|
|
151
152
|
|
|
@@ -165,67 +166,97 @@ export class ValueInput extends React.Component<ValueInputProps, ValueInputState
|
|
|
165
166
|
declare context: React.ContextType<typeof EventEmitterContext>;
|
|
166
167
|
|
|
167
168
|
|
|
168
|
-
|
|
169
|
+
|
|
169
170
|
|
|
170
171
|
/**
|
|
171
172
|
* Default properties for the component.
|
|
172
173
|
*/
|
|
173
174
|
static defaultProps = {
|
|
174
|
-
label
|
|
175
|
-
value
|
|
176
|
-
keyFilter
|
|
177
|
-
writeTopic
|
|
178
|
-
onValueChanged
|
|
175
|
+
label: '',
|
|
176
|
+
value: undefined,
|
|
177
|
+
keyFilter: undefined,
|
|
178
|
+
writeTopic: undefined,
|
|
179
|
+
onValueChanged: undefined,
|
|
179
180
|
description: undefined,
|
|
180
181
|
prefix: undefined,
|
|
181
|
-
suffix
|
|
182
|
-
disabled
|
|
183
|
-
dispatchTopic
|
|
184
|
-
placeholder
|
|
185
|
-
validator
|
|
186
|
-
min
|
|
187
|
-
max
|
|
188
|
-
minPrecision
|
|
189
|
-
maxPrecision
|
|
190
|
-
mode
|
|
191
|
-
showButtons
|
|
192
|
-
step
|
|
193
|
-
locale
|
|
194
|
-
currency
|
|
182
|
+
suffix: undefined,
|
|
183
|
+
disabled: false,
|
|
184
|
+
dispatchTopic: undefined,
|
|
185
|
+
placeholder: undefined,
|
|
186
|
+
validator: undefined,
|
|
187
|
+
min: undefined,
|
|
188
|
+
max: undefined,
|
|
189
|
+
minPrecision: 0,
|
|
190
|
+
maxPrecision: 3,
|
|
191
|
+
mode: "decimal",
|
|
192
|
+
showButtons: false,
|
|
193
|
+
step: 1,
|
|
194
|
+
locale: "en-US",
|
|
195
|
+
currency: "USD"
|
|
195
196
|
};
|
|
197
|
+
inputRef: React.RefObject<HTMLInputElement>;
|
|
196
198
|
|
|
197
199
|
/**
|
|
198
200
|
*
|
|
199
201
|
* @param {FooterViewProps} props
|
|
200
202
|
*/
|
|
201
|
-
constructor(props
|
|
203
|
+
constructor(props: ValueInputProps) {
|
|
202
204
|
super(props);
|
|
203
205
|
this.state = {
|
|
204
|
-
entryValue
|
|
205
|
-
|
|
206
|
+
entryValue: props.value,
|
|
207
|
+
currentValue: props.value,
|
|
208
|
+
editing: false
|
|
206
209
|
};
|
|
210
|
+
|
|
211
|
+
this.inputRef = createRef();
|
|
207
212
|
}
|
|
208
213
|
|
|
209
214
|
/**
|
|
210
215
|
* The component has been loaded into the DOM.
|
|
211
216
|
*/
|
|
212
|
-
componentDidMount() {
|
|
213
|
-
}
|
|
217
|
+
componentDidMount() {
|
|
218
|
+
}
|
|
219
|
+
|
|
220
|
+
|
|
221
|
+
private onBufferValue(val: number | null) {
|
|
222
|
+
if (val === null)
|
|
223
|
+
return;
|
|
214
224
|
|
|
215
|
-
|
|
225
|
+
if (!this.state.editing) {
|
|
226
|
+
this.setState({
|
|
227
|
+
entryValue: this.state.currentValue,
|
|
228
|
+
editing: true
|
|
229
|
+
}, () => {
|
|
230
|
+
|
|
231
|
+
setTimeout(() => {
|
|
232
|
+
if (this.inputRef.current) {
|
|
233
|
+
this.inputRef.current.focus();
|
|
234
|
+
}
|
|
235
|
+
|
|
236
|
+
}, 0);
|
|
237
|
+
|
|
238
|
+
}
|
|
239
|
+
);
|
|
240
|
+
}
|
|
241
|
+
else {
|
|
242
|
+
this.setState({
|
|
243
|
+
entryValue: val
|
|
244
|
+
});
|
|
245
|
+
}
|
|
246
|
+
}
|
|
216
247
|
|
|
217
248
|
/**
|
|
218
249
|
* The user has elected to accept the input value. Validate and store, if valid.
|
|
219
250
|
*/
|
|
220
251
|
private onAcceptValue() {
|
|
221
|
-
if (this.state.entryValue !== null
|
|
222
|
-
this.setState({editing :
|
|
223
|
-
|
|
252
|
+
if (this.state.entryValue !== null) {
|
|
253
|
+
this.setState({ editing: false, currentValue: this.state.entryValue });
|
|
254
|
+
|
|
224
255
|
if (this.props.onValueChanged)
|
|
225
256
|
this.props.onValueChanged(this.state.entryValue);
|
|
226
257
|
|
|
227
258
|
if (this.props.dispatchTopic !== undefined) {
|
|
228
|
-
this.context.dispatch({topic: this.props.dispatchTopic, payload:this.state.entryValue});
|
|
259
|
+
this.context.dispatch({ topic: this.props.dispatchTopic, payload: this.state.entryValue });
|
|
229
260
|
}
|
|
230
261
|
|
|
231
262
|
}
|
|
@@ -235,22 +266,29 @@ export class ValueInput extends React.Component<ValueInputProps, ValueInputState
|
|
|
235
266
|
* The user wishes to reset/cancel the previous value.
|
|
236
267
|
*/
|
|
237
268
|
private onResetValue() {
|
|
238
|
-
|
|
239
|
-
|
|
240
|
-
|
|
241
|
-
|
|
269
|
+
|
|
270
|
+
if (this.state.editing) {
|
|
271
|
+
|
|
272
|
+
this.setState({
|
|
273
|
+
currentValue: this.state.currentValue,
|
|
274
|
+
entryValue: this.state.currentValue,
|
|
275
|
+
editing: false
|
|
276
|
+
});
|
|
277
|
+
}
|
|
242
278
|
}
|
|
243
279
|
|
|
244
280
|
|
|
245
281
|
render() {
|
|
246
282
|
|
|
247
|
-
return(
|
|
283
|
+
return (
|
|
248
284
|
<div>
|
|
249
285
|
<div className="p-inputgroup flex-1" >
|
|
250
286
|
<span className="p-inputgroup-addon">
|
|
251
287
|
{this.props.label}
|
|
252
|
-
</span>
|
|
253
|
-
<InputNumber
|
|
288
|
+
</span>
|
|
289
|
+
<InputNumber
|
|
290
|
+
inputRef={this.inputRef}
|
|
291
|
+
key={this.state.editing ? "editing" : "not-editing"}
|
|
254
292
|
min={this.props.min}
|
|
255
293
|
max={this.props.max}
|
|
256
294
|
minFractionDigits={this.props.minPrecision}
|
|
@@ -260,14 +298,14 @@ export class ValueInput extends React.Component<ValueInputProps, ValueInputState
|
|
|
260
298
|
suffix={this.props.suffix}
|
|
261
299
|
showButtons={this.props.showButtons}
|
|
262
300
|
step={this.props.step}
|
|
263
|
-
placeholder={this.props.placeholder}
|
|
264
|
-
value={this.state.
|
|
265
|
-
onChange={(e) => {this.
|
|
301
|
+
placeholder={this.props.placeholder}
|
|
302
|
+
value={this.state.currentValue}
|
|
303
|
+
onChange={(e) => { this.onBufferValue(e.value) }}
|
|
266
304
|
|
|
267
305
|
buttonLayout="horizontal"
|
|
268
|
-
decrementButtonClassName="p-button-danger"
|
|
269
|
-
incrementButtonClassName="p-button-success"
|
|
270
|
-
incrementButtonIcon="pi pi-plus"
|
|
306
|
+
decrementButtonClassName="p-button-danger"
|
|
307
|
+
incrementButtonClassName="p-button-success"
|
|
308
|
+
incrementButtonIcon="pi pi-plus"
|
|
271
309
|
decrementButtonIcon="pi pi-minus"
|
|
272
310
|
|
|
273
311
|
locale="en-US"
|
|
@@ -280,32 +318,35 @@ export class ValueInput extends React.Component<ValueInputProps, ValueInputState
|
|
|
280
318
|
else if (e.key === 'Escape') {
|
|
281
319
|
this.onResetValue();
|
|
282
320
|
}
|
|
283
|
-
}}
|
|
284
|
-
disabled={this.props.disabled}
|
|
285
|
-
|
|
286
|
-
|
|
287
|
-
|
|
321
|
+
}}
|
|
322
|
+
disabled={this.props.disabled}
|
|
323
|
+
autoFocus={false}
|
|
324
|
+
/>
|
|
325
|
+
<Button
|
|
326
|
+
icon="pi pi-check"
|
|
288
327
|
disabled={this.props.disabled || !this.state.editing}
|
|
289
|
-
className="p-button-success"
|
|
290
|
-
onClick={() => this.onAcceptValue()}
|
|
328
|
+
className="p-button-success"
|
|
329
|
+
onClick={() => this.onAcceptValue()}
|
|
291
330
|
visible={this.state.editing}
|
|
292
331
|
size="small"
|
|
332
|
+
autoFocus={false}
|
|
293
333
|
/>
|
|
294
334
|
|
|
295
|
-
<Button
|
|
296
|
-
icon="pi pi-times"
|
|
335
|
+
<Button
|
|
336
|
+
icon="pi pi-times"
|
|
297
337
|
disabled={this.props.disabled || !this.state.editing}
|
|
298
|
-
className="p-button-danger"
|
|
299
|
-
onClickCapture={()=>this.onResetValue()}
|
|
338
|
+
className="p-button-danger"
|
|
339
|
+
onClickCapture={() => this.onResetValue()}
|
|
300
340
|
visible={this.state.editing}
|
|
301
341
|
size="small"
|
|
342
|
+
autoFocus={false}
|
|
302
343
|
/>
|
|
303
344
|
</div>
|
|
304
|
-
|
|
345
|
+
|
|
305
346
|
{this.props.description !== undefined &&
|
|
306
347
|
<small>{this.props.description}</small>
|
|
307
348
|
}
|
|
308
|
-
|
|
349
|
+
|
|
309
350
|
|
|
310
351
|
</div>
|
|
311
352
|
|