@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.
@@ -1,103 +1,21 @@
1
- import { Component } from 'react';
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 class ToggleGroup extends Component<ToggleGroupProps, IndicatorButtonState> {
68
- static contextType: import("react").Context<EventEmitterContextType>;
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{Component}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};function matchCurrentValue(e,t){if(null==t||0===t.length)return;let o=typeof e;if("boolean"==o){return e&&t.length>1?t[1]:t[0]}if("number"==o){let o=e;if(void 0!==o&&o<t.length)return t[o]}else if("string"==o)return e}function selectOnColor(e,t,o){if(!t||0===t.length)return IndicatorColor.IndicatorInvalid;let n=Array.isArray(o)?o:void 0!==o?[o]:[IndicatorColor.IndicatorInvalid],i=typeof e;if("boolean"===i)return e?n[0]:n.length>1?n[1]:n[0];if("number"===i&&t.length>e){if(n.length>e){return n[e]}return n[0]}if("string"===i){let o=t.indexOf(e);return-1!==o&&o<n.length?n[o]:n[0]}return null!=o?Array.isArray(o)?o[0]:o:IndicatorColor.IndicatorInvalid}export class ToggleGroup extends Component{constructor(e){super(e),Object.defineProperty(this,"handleTopicUpdate",{enumerable:!0,configurable:!0,writable:!0,value:e=>{this.setState({currentValue:e})}}),Object.defineProperty(this,"handleDisableTopicUpdate",{enumerable:!0,configurable:!0,writable:!0,value:e=>{this.setState({isDisabled:e})}}),Object.defineProperty(this,"handleInvisibleTopicUpdate",{enumerable:!0,configurable:!0,writable:!0,value:e=>{this.setState({isInvisible:e})}}),this.state={currentValue:void 0,isDisabled:!1,isInvisible:!1,isPressed:!1}}componentDidMount(){this.setupSubscriptions()}componentDidUpdate(e){}componentWillUnmount(){}setupSubscriptions(){const{topic:e,disableTopic:t,invisibleTopic:o}=this.props,{subscribe:n}=this.context;e&&n(e,this.handleTopicUpdate),t&&n(t,this.handleDisableTopicUpdate),o&&n(o,this.handleInvisibleTopicUpdate)}handleOnPressed(){const{isPressed:e}=this.state,{actionMode:t}=this.props;e||(this.setState({isPressed:!0}),t!==ActionMode.Tap&&t!==ActionMode.Pressed||this.dispatchCommand(!0))}handleOnReleased(){const{isPressed:e}=this.state,{actionMode:t}=this.props;e&&(this.setState({isPressed:!1}),t===ActionMode.Tap?this.dispatchCommand(!1):t===ActionMode.Released&&this.dispatchCommand(!0))}dispatchCommand(e){const{command:t,commandTopic:o,commandArgs:n}=this.props,{dispatch:i}=this.context;if(null!=t&&t.length>0){i({topic:t,payload:{topic:o,value:e,...n}})}}render(){const{currentValue:e,isDisabled:t,isInvisible:o}=this.state,{label:n,value:i,disabled:r,className:s,onColor:l,offColor:a,options:c,...d}=this.props;let p=e;void 0!==i&&(p=i);let u=selectOnColor(p,c,l);void 0===p&&(u=IndicatorColor.IndicatorInvalid);const h=null!=c&&c.length>2;return _jsxs("div",{className:"flex",children:[_jsx("style",{children:` \n ${void 0!==a?`\n .togglegroup-selectbutton-container .p-selectbutton .p-button {\n background-color: ${a};\n }\n `:""}\n .togglegroup-selectbutton-container .p-selectbutton .p-button.p-highlight {\n background-color: ${u} !important;\n border-color: ${u} !important;\n }\n .togglegroup-selectbutton-container .p-selectbutton .p-highlight {\n background-color: ${u} !important;\n border-color: ${u} !important;\n }\n `}),_jsxs("div",{className:"p-inputgroup togglegroup-selectbutton-container",children:[_jsx("span",{className:"p-inputgroup-addon",style:{flexGrow:1},children:n}),_jsx(SelectButton,{...d,options:c,disabled:t||r,multiple:h,className:`${s||""} ${void 0===p?"p-invalid":""}`.trim(),...o&&{style:{display:"none"}},value:matchCurrentValue(p,c),allowEmpty:!1,onMouseDown:()=>this.handleOnPressed(),onTouchStart:()=>this.handleOnPressed(),onMouseUp:()=>this.handleOnReleased(),onTouchEnd:()=>this.handleOnReleased()})]})]})}}Object.defineProperty(ToggleGroup,"contextType",{enumerable:!0,configurable:!0,writable:!0,value:EventEmitterContext});
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.js";
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.js").EventEmitterContextType>;
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 from"react";import{InputNumber}from"primereact/inputnumber";import{Button}from"primereact/button";import{EventEmitterContext}from"../core/EventEmitterContext.js";export class ValueInput extends React.Component{constructor(e){super(e),this.state={entryValue:e.value,editing:!1}}componentDidMount(){}onAcceptValue(){null!==this.state.entryValue&&(this.setState({editing:!1}),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.setState({entryValue:this.props.value,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,{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.entryValue,onChange:e=>{this.setState({entryValue:e.value,editing:!0})},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:e=>{"Enter"===e.key?this.onAcceptValue():"Escape"===e.key&&this.onResetValue()},disabled:this.props.disabled}),_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"}),_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"})]}),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"}});
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
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@adcops/autocore-react",
3
- "version": "3.0.8",
3
+ "version": "3.0.10",
4
4
  "description": "A React component library for industrial user interfaces.",
5
5
  "private": false,
6
6
  "type": "module",
@@ -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-03-12 20:40:14
5
+ * Last Modified: 2024-04-16 09:16:59
6
6
  * -----
7
7
  *
8
8
  */
9
9
 
10
- import { Component } from 'react';
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, EventEmitterContextType } from '../core/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 { IndicatorButtonState } from '../core/IndicatorButtonState';
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
- * @param s string | undefined[]
100
- * @returns
101
- */
102
- // function generateSelectButtonOptions(s? : SelectItemOptionsType | undefined) : SelectItemOptionsType | undefined {
103
- // if (s !== undefined && s !== null) {
104
- // let ret : SelectItemOptionsType = [];
105
- // for (let i=0;i<s.length;++i) {
106
- // ret.push({label:s[i]});
107
- // }
108
-
109
- // return ret;
110
- // }
111
- // else {
112
- // return undefined;
113
- // }
114
- // }
115
-
116
-
117
- /**
118
- *
119
- * @param currentValue
120
- * @param options
121
- * @returns
122
- */
123
- function matchCurrentValue(currentValue : any, options : SelectItemOptionsType | undefined) : any {
124
-
125
- if (options === undefined || options === null || options.length === 0)
126
- return undefined;
127
-
128
- let t = typeof(currentValue);
129
- if (t == "boolean" ) {
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
- componentDidMount() {
225
- this.setupSubscriptions();
226
- }
74
+ setupSubscriptions();
227
75
 
228
- componentDidUpdate(prevProps: ToggleGroupProps) {
229
- prevProps;
230
- // Logic to handle updates in props, if necessary
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
- * Handles updates for the main topic.
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
- * Handles updates for the disable topic.
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
- * Handles updates for the invisible topic.
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
- this.setState({isPressed: true});
291
-
95
+ setIsPressed(true);
292
96
  if (actionMode === ActionMode.Tap || actionMode === ActionMode.Pressed) {
293
- this.dispatchCommand(true);
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
- this.setState({isPressed: false});
307
-
308
- if (actionMode === ActionMode.Tap ) {
309
- this.dispatchCommand(false);
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
- if (command !== undefined && command !== null && command.length > 0 )
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
- render() {
348
- // const { currentValue, isDisabled, isInvisible } = this.state;
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
- const { currentValue, isDisabled, isInvisible} = this.state;
358
- const { label, value, disabled, className,
359
- onColor, offColor, options,
360
- ...restProps
361
- } = this.props;
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
- // let btnIcon = currentValue ? onIcon : offIcon;
365
- // if (btnIcon === undefined || btnIcon === null || btnIcon.length === 0)
366
- // btnIcon = icon;
183
+ }
367
184
 
368
185
 
369
- //
370
- // Load the value from the proper source.
371
- // If the `value` property is undefined, that takes precedence.
372
- //
373
- let displayValue = currentValue;
374
- if (value !== undefined) {
375
- displayValue = value;
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
- let color = selectOnColor(displayValue, options, onColor); // displayValue ? onColor : offColor;
379
-
380
- // Handle special cases like undefined state or specific input modes
381
- if (displayValue === undefined) {
382
- color = IndicatorColor.IndicatorInvalid;
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
- const isMultiple = options !== undefined && options !== null && options.length > 2;
386
-
387
-
388
- return (
389
- <div className="flex">
390
-
391
- <style>{`
392
- ${offColor !== undefined ? `
393
- .togglegroup-selectbutton-container .p-selectbutton .p-button {
394
- background-color: ${offColor};
395
- }
396
- ` : ''}
397
- .togglegroup-selectbutton-container .p-selectbutton .p-button.p-highlight {
398
- background-color: ${color} !important;
399
- border-color: ${color} !important;
400
- }
401
- .togglegroup-selectbutton-container .p-selectbutton .p-highlight {
402
- background-color: ${color} !important;
403
- border-color: ${color} !important;
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
- <div className='p-inputgroup togglegroup-selectbutton-container'>
408
- <span className="p-inputgroup-addon" style={{flexGrow: 1}}>
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={`${className || ''} ${displayValue === undefined ? 'p-invalid' : ''}`.trim()}
416
- {...(isInvisible && { style: { display: 'none' }})}
417
- value={matchCurrentValue(displayValue, options)}
418
- allowEmpty={false}
419
- onMouseDown={() => this.handleOnPressed() }
420
- onTouchStart={() => this.handleOnPressed() }
421
- onMouseUp={() => this.handleOnReleased() }
422
- onTouchEnd={() => this.handleOnReleased() }
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-03-21 09:37:17
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.js";
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 : React.ReactNode | undefined;
26
+ label: React.ReactNode | undefined;
27
27
 
28
28
 
29
29
  /**
30
30
  * The value for the field.
31
31
  */
32
- value : number | null;
32
+ value: number | null;
33
33
 
34
34
  /**
35
35
  * Minimum value for the field.
36
36
  */
37
- min : number | undefined;
37
+ min: number | undefined;
38
38
 
39
39
  /**
40
40
  * Minimum value for the field.
41
41
  */
42
- max : number | undefined;
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 : number | undefined;
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 : number | undefined;
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 : "currency" | "decimal" | undefined;
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 : string;
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 : string | undefined;
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 : string | undefined;
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 : boolean;
101
+ showButtons: boolean;
102
102
 
103
103
  /**
104
104
  * The amount clicking an increment/decrement buttion will change the value.
105
105
  */
106
- step : number | undefined;
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 : string | undefined;
115
+ locale: string | undefined;
116
116
 
117
117
  /**
118
118
  * A small, advisory text below the field.
119
119
  */
120
- description : React.ReactNode | undefined;
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 : boolean | undefined;
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 : string | undefined;
128
+ dispatchTopic: string | undefined;
129
129
 
130
130
  /**
131
131
  * Placeholder string to display if the value is empty.
132
132
  */
133
- placeholder : string | undefined;
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) : void;
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 : number | null;
148
- editing : boolean;
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 : undefined,
176
- keyFilter : undefined,
177
- writeTopic : undefined,
178
- onValueChanged : undefined,
175
+ label: '',
176
+ value: undefined,
177
+ keyFilter: undefined,
178
+ writeTopic: undefined,
179
+ onValueChanged: undefined,
179
180
  description: undefined,
180
181
  prefix: undefined,
181
- suffix : undefined,
182
- disabled : false,
183
- dispatchTopic : undefined,
184
- placeholder : undefined,
185
- validator : undefined,
186
- min : undefined,
187
- max : undefined,
188
- minPrecision : 0,
189
- maxPrecision : 3,
190
- mode : "decimal",
191
- showButtons : false,
192
- step : 1,
193
- locale : "en-US",
194
- currency : "USD"
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 : ValueInputProps) {
203
+ constructor(props: ValueInputProps) {
202
204
  super(props);
203
205
  this.state = {
204
- entryValue : props.value,
205
- editing : false
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 : false});
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
- this.setState({
239
- entryValue: this.props.value,
240
- editing : false
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.entryValue}
265
- onChange={(e) => {this.setState({entryValue: e.value, editing : true})} }
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
- <Button
287
- icon="pi pi-check"
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