@adcops/autocore-react 3.0.4 → 3.0.6

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.
@@ -0,0 +1,13 @@
1
+ import React from 'react';
2
+ interface FitTextProps {
3
+ /** The children prop expects any valid React node. */
4
+ children: React.ReactNode;
5
+ }
6
+ /**
7
+ * FitText dynamically adjusts the font size of its children to fit the parent container.
8
+ *
9
+ * @param {FitTextProps} props The props for the FitText component.
10
+ * @returns A div element that resizes its child text to fit.
11
+ */
12
+ export declare const FitText: React.FC<FitTextProps>;
13
+ export default FitText;
@@ -0,0 +1 @@
1
+ import{jsx as _jsx}from"react/jsx-runtime";import useFitText from"use-fit-text";export const FitText=({children:t})=>{const{fontSize:e,ref:i}=useFitText();return _jsx("div",{ref:i,style:{width:"100%",height:"100%",display:"flex",justifyContent:"center",alignItems:"center"},children:_jsx("p",{style:{fontSize:e},children:t})})};export default FitText;
@@ -0,0 +1,109 @@
1
+ import React from "react";
2
+ import { EventEmitterContext } from "../core/EventEmitterContext.js";
3
+ import { KeyFilterType } from "primereact/keyfilter";
4
+ /**
5
+ * Properties of the component.
6
+ */
7
+ interface TextInputProps {
8
+ /**
9
+ * The label for the field.
10
+ */
11
+ label: React.ReactNode | undefined;
12
+ /**
13
+ * The value for the field.
14
+ */
15
+ value: string | undefined;
16
+ /**
17
+ * Optional filter for key entry. Not a validator, but won't accept keystrokes outside the filter.
18
+ * @type {RegExp | "pint" | "int" | "pnum" | "money" | "num" | "hex" | "email" | "alpha" | "alphanum"}
19
+ */
20
+ keyFilter: KeyFilterType | undefined;
21
+ /**
22
+ * An optional prefix before the data entry field.
23
+ */
24
+ prefix: React.ReactNode | undefined;
25
+ /**
26
+ * An optional suffix after the data entry field.
27
+ */
28
+ suffix: React.ReactNode | undefined;
29
+ /**
30
+ * A small, advisory text below the field.
31
+ */
32
+ description: React.ReactNode | undefined;
33
+ /**
34
+ * If true, all functions of the field will be disabled.
35
+ */
36
+ disabled: boolean | undefined;
37
+ /** Topic on which the value will be dispatched through the user interfave on successful data entry. */
38
+ dispatchTopic: string | undefined;
39
+ /**
40
+ * Placeholder string to display if the value is empty.
41
+ */
42
+ placeholder: string | undefined;
43
+ /**
44
+ * The user has accepted a new value.
45
+ * @param newValue New value accepted by the user.
46
+ */
47
+ onValueChanged?(newValue: string): void;
48
+ /** Regular expression used to validate the value before it is broadcast */
49
+ validator: RegExp;
50
+ }
51
+ /**
52
+ * State variables of the component.
53
+ */
54
+ interface TextInputState {
55
+ entryValue: string | undefined;
56
+ isValid: boolean;
57
+ editing: boolean;
58
+ }
59
+ /**
60
+ * A convenient field with all the usual features of inputing values.
61
+ * Wraps the common features of use of a InputText, p-inputgroup, some icon buttons,
62
+ * accepting and rejecting values and keyboard management.
63
+ */
64
+ export declare class TextInput extends React.Component<TextInputProps, TextInputState> {
65
+ static contextType: React.Context<import("../core/EventEmitterContext.js").EventEmitterContextType>;
66
+ context: React.ContextType<typeof EventEmitterContext>;
67
+ /**
68
+ * Default properties for the component.
69
+ */
70
+ static defaultProps: {
71
+ label: string;
72
+ value: undefined;
73
+ keyFilter: undefined;
74
+ writeTopic: undefined;
75
+ onValueChanged: undefined;
76
+ description: undefined;
77
+ prefix: undefined;
78
+ suffix: undefined;
79
+ disabled: boolean;
80
+ dispatchTopic: undefined;
81
+ placeholder: undefined;
82
+ validator: undefined;
83
+ };
84
+ /**
85
+ *
86
+ * @param {FooterViewProps} props
87
+ */
88
+ constructor(props: TextInputProps);
89
+ /**
90
+ * The component has been loaded into the DOM.
91
+ */
92
+ componentDidMount(): void;
93
+ /**
94
+ * Check the new value against the validator RegEx, if one was specified.
95
+ * @param val The new value.
96
+ * @returns True if no validator specified or the value is valid, false if not valid.
97
+ */
98
+ private validateValue;
99
+ /**
100
+ * The user has elected to accept the input value. Validate and store, if valid.
101
+ */
102
+ private onAcceptValue;
103
+ /**
104
+ * The user wishes to reset/cancel the previous value.
105
+ */
106
+ private onResetValue;
107
+ render(): import("react/jsx-runtime").JSX.Element;
108
+ }
109
+ export {};
@@ -0,0 +1 @@
1
+ import{jsx as _jsx,jsxs as _jsxs}from"react/jsx-runtime";import React from"react";import{InputText}from"primereact/inputtext";import{Button}from"primereact/button";import{EventEmitterContext}from"../core/EventEmitterContext.js";export class TextInput extends React.Component{constructor(t){super(t),Object.defineProperty(this,"validateValue",{enumerable:!0,configurable:!0,writable:!0,value:t=>void 0===this.props.validator||null===this.props.validator||this.props.validator.test(t)}),this.state={entryValue:t.value,isValid:void 0!==t.value&&this.validateValue(t.value),editing:!1}}componentDidMount(){}onAcceptValue(){void 0!==this.state.entryValue&&this.validateValue(this.state.entryValue)?(this.setState({isValid:!0,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})):this.setState({isValid:!1})}onResetValue(){this.setState({entryValue:this.props.value,isValid:void 0!==this.props.value&&this.validateValue(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}),void 0!==this.props.prefix&&_jsx("span",{className:"p-inputgroup-addon",children:this.props.prefix}),_jsx(InputText,{keyfilter:this.props.keyFilter,placeholder:this.props.placeholder,value:this.state.entryValue,onChange:t=>{this.setState({entryValue:t.target.value,editing:!0})},className:this.state.isValid?"":"p-invalid",onKeyDown:t=>{"Enter"===t.key?this.onAcceptValue():"Escape"===t.key&&this.onResetValue()},disabled:this.props.disabled}),void 0!==this.props.suffix&&_jsx("span",{className:"p-inputgroup-addon",children:this.props.suffix}),_jsx(Button,{icon:"pi pi-check",disabled:this.props.disabled||!this.state.editing,className:"p-button-success",onClick:()=>this.onAcceptValue(),visible:this.state.editing}),_jsx(Button,{icon:"pi pi-times",disabled:this.props.disabled||!this.state.editing,className:"p-button-danger",onClickCapture:()=>this.onResetValue(),visible:this.state.editing})]}),void 0!==this.props.description&&_jsx("small",{children:this.props.description})]})}}Object.defineProperty(TextInput,"contextType",{enumerable:!0,configurable:!0,writable:!0,value:EventEmitterContext}),Object.defineProperty(TextInput,"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}});
@@ -0,0 +1,61 @@
1
+ import React, { Component } from 'react';
2
+ import type { NumerableFormatOptions } from '../core/NumerableTypes';
3
+ /**
4
+ * Properties of the ValueDisplay component.
5
+ */
6
+ interface ValueIndicatorProps {
7
+ /**
8
+ * Label for the indicator.
9
+ */
10
+ label?: React.ReactNode | undefined;
11
+ /**
12
+ * Value to be displayed
13
+ */
14
+ value?: string | number | null | undefined;
15
+ /**
16
+ * Tooltip to display on hover
17
+ */
18
+ tooltip?: string | undefined;
19
+ /**
20
+ * Format for `value`<br/>
21
+ * See [numerable formats](https://github.com/gastonmesseri/numerable#1234-formatting-numbers)
22
+ */
23
+ format?: string | null | undefined;
24
+ /**
25
+ * Format options for `value`<br/>
26
+ * See [numerable format options](https://github.com/gastonmesseri/numerable#format)
27
+ */
28
+ formatOptions?: NumerableFormatOptions;
29
+ /**
30
+ * Custom class name to be attached
31
+ */
32
+ className?: string;
33
+ /**
34
+ * The topic to monitor to display. Optional.
35
+ */
36
+ topic?: string;
37
+ }
38
+ /**
39
+ * State of the ValueDisplay component.
40
+ */
41
+ interface ValueIndicatorState {
42
+ }
43
+ /**
44
+ * `ValueIndicator` wraps `ValueDisplay` in a frame and label, giving it a widget appearance.
45
+ * Care is taken to adapt to the selected theme of the application.
46
+ *
47
+ */
48
+ export declare class ValueIndicator extends Component<ValueIndicatorProps, ValueIndicatorState> {
49
+ /**
50
+ * The constructor initializes the component state and binds the initial value.
51
+ * @param {ValueIndicatorProps} props The properties passed to the component, including initial value and other display options.
52
+ */
53
+ constructor(props: ValueIndicatorProps);
54
+ /**
55
+ * Renders the component into the DOM.
56
+ * @returns A styled `div` element displaying the indicator.
57
+ */
58
+ render(): import("react/jsx-runtime").JSX.Element;
59
+ }
60
+ export default ValueIndicator;
61
+ export { NumerableFormatOptions };
@@ -0,0 +1 @@
1
+ import{jsxs as _jsxs,jsx as _jsx,Fragment as _Fragment}from"react/jsx-runtime";import{Component}from"react";import{Tooltip}from"primereact/tooltip";import{ValueDisplay}from"./ValueDisplay";export class ValueIndicator extends Component{constructor(r){super(r),this.state={}}render(){return _jsxs(_Fragment,{children:[_jsxs("style",{children:["\n .value-indicator-container {\n\n background-color: var(--surface-ground);\n border-color: var(--surface-border);\n border-radius: var(--border-radius);\n border-width: 1px;\n border-style: solid;\n display: flex;\n flex-direction: column;\n justify-content: center;\n align-items: center;\n padding: 2mm;\n }\n\n .value-indicator-label {\n padding-bottom: 1mm;\n } \n ","'"]}),_jsx(Tooltip,{target:".value-indicator-tooltip"}),_jsx("span",{className:"value-indicator-tooltip",children:_jsxs("div",{className:"value-indicator-container",children:[void 0!==this.props.label&&_jsx("div",{className:"value-indicator-label",children:this.props.label}),_jsx(ValueDisplay,{className:this.props.className,value:this.props.value,format:this.props.format,formatOptions:this.props.formatOptions,topic:this.props.topic,"data-pr-tooltip":this.props.tooltip,"data-pr-position":"down","data-pr-mousetrack":!0,"data-pr-showDelay":2e3})]})})]})}}export default ValueIndicator;
@@ -1,8 +1,7 @@
1
1
  import React from "react";
2
2
  import { EventEmitterContext } from "../core/EventEmitterContext.js";
3
- import { KeyFilterType } from "primereact/keyfilter";
4
3
  /**
5
- * Properties of the Configuration View
4
+ * Properties of the ValueInput component.
6
5
  */
7
6
  interface ValueInputProps {
8
7
  /**
@@ -12,20 +11,75 @@ interface ValueInputProps {
12
11
  /**
13
12
  * The value for the field.
14
13
  */
15
- value: string | undefined;
14
+ value: number | null;
16
15
  /**
17
- * Optional filter for key entry. Not a validator, but won't accept keystrokes outside the filter.
18
- * @type {RegExp | "pint" | "int" | "pnum" | "money" | "num" | "hex" | "email" | "alpha" | "alphanum"}
16
+ * Minimum value for the field.
19
17
  */
20
- keyFilter: KeyFilterType | undefined;
18
+ min: number | undefined;
21
19
  /**
22
- * An optional prefix before the data entry field.
20
+ * Minimum value for the field.
23
21
  */
24
- prefix: React.ReactNode | undefined;
22
+ max: number | undefined;
25
23
  /**
26
- * An optional prefix before the data entry field.
24
+ * Minimum number of decimal points. The user will not
25
+ * be required to type the decimal values, but this minimum
26
+ * precision will always be displayed.
27
+ * Must be less than or equal to maxPrecision, or
28
+ * the component will throw an error.
29
+ * @default 0
27
30
  */
28
- suffix: React.ReactNode | undefined;
31
+ minPrecision: number | undefined;
32
+ /**
33
+ * Maximum number of decimal points.
34
+ * Set to 0 for integer-only. Must be greater or equal to than minPrecision, or
35
+ * the component will throw an error.
36
+ * @default 3
37
+ */
38
+ maxPrecision: number | undefined;
39
+ /**
40
+ * Defines the behavior of the component.
41
+ * If set to "currency", then you need to specify the
42
+ * currency type using the currency property.
43
+ * @default "decimal"
44
+ */
45
+ mode: "currency" | "decimal" | undefined;
46
+ /**
47
+ * The currency to use in currency formatting. Possible values are the
48
+ * [ISO 4217 currency codes](https://www.six-group.com/en/products-services/financial-information/data-standards.html#scrollTo=maintenance-agency),
49
+ * such as "USD" for the US dollar, "EUR" for the euro, or "CNY" for the Chinese RMB.
50
+ * If the mode is "currency", the currency property must be provided.
51
+ *
52
+ * @default "USD"
53
+ */
54
+ currency: string;
55
+ /**
56
+ * An optional prefix before the value of the field.
57
+ * Unlike the TextInput control, this prefix is internal to the field.
58
+ */
59
+ prefix: string | undefined;
60
+ /**
61
+ * An optional suffix after the value of the field.
62
+ * Unlike the TextInput control, this prefix is internal to the field.
63
+ */
64
+ suffix: string | undefined;
65
+ /**
66
+ * Set true to display buttons to increment/decrement the value.
67
+ * Use the step property to adjust the amount that the value will change.
68
+ *
69
+ * @default false
70
+ */
71
+ showButtons: boolean;
72
+ /**
73
+ * The amount clicking an increment/decrement buttion will change the value.
74
+ */
75
+ step: number | undefined;
76
+ /**
77
+ * Locale to be used in formatting. Changes how the numbers/separators are displayed
78
+ * for international users. The typical locale codes are used.
79
+ *
80
+ * @default "en-US"
81
+ */
82
+ locale: string | undefined;
29
83
  /**
30
84
  * A small, advisory text below the field.
31
85
  */
@@ -44,21 +98,18 @@ interface ValueInputProps {
44
98
  * The user has accepted a new value.
45
99
  * @param newValue New value accepted by the user.
46
100
  */
47
- onValueChanged?(newValue: string): void;
48
- /** Regular expression used to validate the value before it is broadcast */
49
- validator: RegExp;
101
+ onValueChanged?(newValue: number): void;
50
102
  }
51
103
  /**
52
- * State variables of the Configuration View
104
+ * State variables of the ValueInput component.
53
105
  */
54
106
  interface ValueInputState {
55
- entryValue: string | undefined;
56
- isValid: boolean;
107
+ entryValue: number | null;
57
108
  editing: boolean;
58
109
  }
59
110
  /**
60
- * A convenient field with all the usual features of inputing values.
61
- * Wraps the common features of use of a InputText, p-inputgroup, some icon buttons,
111
+ * A convenient field with all the usual features of inputing numbers.
112
+ * Wraps the common features of use of a InputNumber, p-inputgroup, some icon buttons,
62
113
  * accepting and rejecting values and keyboard management.
63
114
  */
64
115
  export declare class ValueInput extends React.Component<ValueInputProps, ValueInputState> {
@@ -80,6 +131,15 @@ export declare class ValueInput extends React.Component<ValueInputProps, ValueIn
80
131
  dispatchTopic: undefined;
81
132
  placeholder: undefined;
82
133
  validator: undefined;
134
+ min: undefined;
135
+ max: undefined;
136
+ minPrecision: number;
137
+ maxPrecision: number;
138
+ mode: string;
139
+ showButtons: boolean;
140
+ step: number;
141
+ locale: string;
142
+ currency: string;
83
143
  };
84
144
  /**
85
145
  *
@@ -90,12 +150,6 @@ export declare class ValueInput extends React.Component<ValueInputProps, ValueIn
90
150
  * The component has been loaded into the DOM.
91
151
  */
92
152
  componentDidMount(): void;
93
- /**
94
- * Check the new value against the validator RegEx, if one was specified.
95
- * @param val The new value.
96
- * @returns True if no validator specified or the value is valid, false if not valid.
97
- */
98
- private validateValue;
99
153
  /**
100
154
  * The user has elected to accept the input value. Validate and store, if valid.
101
155
  */
@@ -1 +1 @@
1
- import{jsx as _jsx,jsxs as _jsxs}from"react/jsx-runtime";import React from"react";import{InputText}from"primereact/inputtext";import{Button}from"primereact/button";import{EventEmitterContext}from"../core/EventEmitterContext.js";export class ValueInput extends React.Component{constructor(e){super(e),Object.defineProperty(this,"validateValue",{enumerable:!0,configurable:!0,writable:!0,value:e=>void 0===this.props.validator||null===this.props.validator||this.props.validator.test(e)}),this.state={entryValue:e.value,isValid:void 0!==e.value&&this.validateValue(e.value),editing:!1}}componentDidMount(){}onAcceptValue(){void 0!==this.state.entryValue&&this.validateValue(this.state.entryValue)?(this.setState({isValid:!0,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})):this.setState({isValid:!1})}onResetValue(){this.setState({entryValue:this.props.value,isValid:void 0!==this.props.value&&this.validateValue(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}),void 0!==this.props.prefix&&_jsx("span",{className:"p-inputgroup-addon",children:this.props.prefix}),_jsx(InputText,{keyfilter:this.props.keyFilter,placeholder:this.props.placeholder,value:this.state.entryValue,onChange:e=>{this.setState({entryValue:e.target.value,editing:!0})},className:this.state.isValid?"":"p-invalid",onKeyDown:e=>{"Enter"===e.key?this.onAcceptValue():"Escape"===e.key&&this.onResetValue()},disabled:this.props.disabled}),void 0!==this.props.suffix&&_jsx("span",{className:"p-inputgroup-addon",children:this.props.suffix}),_jsx(Button,{icon:"pi pi-check",disabled:this.props.disabled||!this.state.editing,className:"p-button-success",onClick:()=>this.onAcceptValue()}),_jsx(Button,{icon:"pi pi-times",disabled:this.props.disabled||!this.state.editing,className:"p-button-danger",onClickCapture:()=>this.onResetValue()})]}),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}});
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"}});
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@adcops/autocore-react",
3
- "version": "3.0.4",
3
+ "version": "3.0.6",
4
4
  "description": "A React component library for industrial user interfaces.",
5
5
  "private": false,
6
6
  "type": "module",
@@ -0,0 +1,36 @@
1
+ /*
2
+ * Copyright (C) 2024 Automated Design Corp.. All Rights Reserved.
3
+ * Created Date: 2024-03-21 13:03:38
4
+ * -----
5
+ * Last Modified: 2024-03-21 13:36:25
6
+ * -----
7
+ *
8
+ */
9
+
10
+
11
+ import React from 'react';
12
+ import useFitText from 'use-fit-text';
13
+
14
+ interface FitTextProps {
15
+ /** The children prop expects any valid React node. */
16
+ children: React.ReactNode;
17
+ }
18
+
19
+ /**
20
+ * FitText dynamically adjusts the font size of its children to fit the parent container.
21
+ *
22
+ * @param {FitTextProps} props The props for the FitText component.
23
+ * @returns A div element that resizes its child text to fit.
24
+ */
25
+ export const FitText: React.FC<FitTextProps> = ({ children }) => {
26
+ const { fontSize, ref } = useFitText();
27
+
28
+ return (
29
+ <div ref={ref} style={{ width: '100%', height: '100%', display: 'flex', justifyContent: 'center', alignItems: 'center' }}>
30
+ <p style={{ fontSize }}>{children}</p>
31
+ </div>
32
+ );
33
+ };
34
+
35
+
36
+ export default FitText;
@@ -0,0 +1,263 @@
1
+ /*
2
+ * Copyright (C) 2024 Automated Design Corp.. All Rights Reserved.
3
+ * Created Date: 2024-03-20 13:05:42
4
+ * -----
5
+ * Last Modified: 2024-03-21 08:35:18
6
+ * -----
7
+ *
8
+ */
9
+
10
+
11
+ import React from "react";
12
+
13
+ import { InputText } from 'primereact/inputtext';
14
+ import { Button } from "primereact/button";
15
+
16
+ import { EventEmitterContext } from "../core/EventEmitterContext.js";
17
+ import { KeyFilterType } from "primereact/keyfilter";
18
+
19
+ /**
20
+ * Properties of the component.
21
+ */
22
+ interface TextInputProps {
23
+
24
+ /**
25
+ * The label for the field.
26
+ */
27
+ label : React.ReactNode | undefined;
28
+
29
+
30
+ /**
31
+ * The value for the field.
32
+ */
33
+ value : string | undefined;
34
+
35
+
36
+ /**
37
+ * Optional filter for key entry. Not a validator, but won't accept keystrokes outside the filter.
38
+ * @type {RegExp | "pint" | "int" | "pnum" | "money" | "num" | "hex" | "email" | "alpha" | "alphanum"}
39
+ */
40
+ keyFilter : KeyFilterType | undefined;
41
+
42
+
43
+ /**
44
+ * An optional prefix before the data entry field.
45
+ */
46
+ prefix : React.ReactNode | undefined;
47
+
48
+ /**
49
+ * An optional suffix after the data entry field.
50
+ */
51
+ suffix : React.ReactNode | undefined;
52
+
53
+ /**
54
+ * A small, advisory text below the field.
55
+ */
56
+ description : React.ReactNode | undefined;
57
+
58
+ /**
59
+ * If true, all functions of the field will be disabled.
60
+ */
61
+ disabled : boolean | undefined;
62
+
63
+ /** Topic on which the value will be dispatched through the user interfave on successful data entry. */
64
+ dispatchTopic : string | undefined;
65
+
66
+ /**
67
+ * Placeholder string to display if the value is empty.
68
+ */
69
+ placeholder : string | undefined;
70
+
71
+ /**
72
+ * The user has accepted a new value.
73
+ * @param newValue New value accepted by the user.
74
+ */
75
+ onValueChanged?(newValue: string) : void;
76
+ /** Regular expression used to validate the value before it is broadcast */
77
+ validator : RegExp;
78
+ }
79
+
80
+ /**
81
+ * State variables of the component.
82
+ */
83
+ interface TextInputState {
84
+
85
+ entryValue : string | undefined;
86
+ isValid : boolean;
87
+ editing : boolean;
88
+ }
89
+
90
+
91
+ /**
92
+ * A convenient field with all the usual features of inputing values.
93
+ * Wraps the common features of use of a InputText, p-inputgroup, some icon buttons,
94
+ * accepting and rejecting values and keyboard management.
95
+ */
96
+ export class TextInput extends React.Component<TextInputProps, TextInputState> {
97
+
98
+ // Here's an example of using the Application-wide EventEmitter con
99
+ // Define the contextType for the class to access the context
100
+ static contextType = EventEmitterContext;
101
+ // After specifying contextType, you can declare the context's type for the TypeScript compiler.
102
+ // Basically, we're telling TypeScript the type of the context; this line doesn't
103
+ // actually do any linking linking to the EventEmitterContext.
104
+ declare context: React.ContextType<typeof EventEmitterContext>;
105
+
106
+
107
+
108
+
109
+ /**
110
+ * Default properties for the component.
111
+ */
112
+ static defaultProps = {
113
+ label : '',
114
+ value : undefined,
115
+ keyFilter : undefined,
116
+ writeTopic : undefined,
117
+ onValueChanged : undefined,
118
+ description: undefined,
119
+ prefix: undefined,
120
+ suffix : undefined,
121
+ disabled : false,
122
+ dispatchTopic : undefined,
123
+ placeholder : undefined,
124
+ validator : undefined
125
+ };
126
+
127
+ /**
128
+ *
129
+ * @param {FooterViewProps} props
130
+ */
131
+ constructor(props : TextInputProps) {
132
+ super(props);
133
+ this.state = {
134
+ entryValue : props.value,
135
+ isValid : props.value !== undefined ? this.validateValue(props.value) : false,
136
+ editing : false
137
+ };
138
+ }
139
+
140
+ /**
141
+ * The component has been loaded into the DOM.
142
+ */
143
+ componentDidMount() {
144
+ }
145
+
146
+
147
+
148
+ /**
149
+ * Check the new value against the validator RegEx, if one was specified.
150
+ * @param val The new value.
151
+ * @returns True if no validator specified or the value is valid, false if not valid.
152
+ */
153
+ private validateValue = (val : string) => {
154
+
155
+ if (this.props.validator !== undefined && this.props.validator !== null) {
156
+ return this.props.validator.test(val);
157
+ }
158
+ else {
159
+ return true;
160
+ }
161
+
162
+ };
163
+
164
+
165
+ /**
166
+ * The user has elected to accept the input value. Validate and store, if valid.
167
+ */
168
+ private onAcceptValue() {
169
+ if (this.state.entryValue !== undefined ) {
170
+ if (this.validateValue(this.state.entryValue) ) {
171
+ this.setState({isValid : true, editing : false});
172
+
173
+ if (this.props.onValueChanged)
174
+ this.props.onValueChanged(this.state.entryValue);
175
+
176
+ if (this.props.dispatchTopic !== undefined) {
177
+ this.context.dispatch({topic: this.props.dispatchTopic, payload:this.state.entryValue});
178
+ }
179
+
180
+ }
181
+ else {
182
+ this.setState({isValid : false});
183
+ }
184
+ }
185
+ else {
186
+ this.setState({isValid: false});
187
+ }
188
+ }
189
+
190
+ /**
191
+ * The user wishes to reset/cancel the previous value.
192
+ */
193
+ private onResetValue() {
194
+ this.setState({
195
+ entryValue: this.props.value,
196
+ isValid: this.props.value !== undefined ? this.validateValue(this.props.value) : false,
197
+ editing : false
198
+ });
199
+ }
200
+
201
+
202
+ render() {
203
+
204
+ return(
205
+ <div>
206
+ <div className="p-inputgroup flex-1" >
207
+ <span className="p-inputgroup-addon">
208
+ {this.props.label}
209
+ </span>
210
+ { this.props.prefix !== undefined &&
211
+ <span className="p-inputgroup-addon">
212
+ {this.props.prefix}
213
+ </span>
214
+ }
215
+ <InputText
216
+ keyfilter={this.props.keyFilter}
217
+ placeholder={this.props.placeholder}
218
+ value={this.state.entryValue}
219
+ onChange={(e) => {this.setState({entryValue: e.target.value, editing : true})} }
220
+ className={this.state.isValid ? '' : 'p-invalid'}
221
+ onKeyDown={(e) => {
222
+ if (e.key === 'Enter') {
223
+ this.onAcceptValue();
224
+ }
225
+ else if (e.key === 'Escape') {
226
+ this.onResetValue();
227
+ }
228
+ }}
229
+ disabled={this.props.disabled}
230
+ />
231
+ { this.props.suffix !== undefined &&
232
+ <span className="p-inputgroup-addon">
233
+ {this.props.suffix}
234
+ </span>
235
+ }
236
+ <Button
237
+ icon="pi pi-check"
238
+ disabled={this.props.disabled || !this.state.editing}
239
+ className="p-button-success"
240
+ onClick={() => this.onAcceptValue()}
241
+ visible={this.state.editing}
242
+ />
243
+
244
+ <Button
245
+ icon="pi pi-times"
246
+ disabled={this.props.disabled || !this.state.editing}
247
+ className="p-button-danger"
248
+ onClickCapture={()=>this.onResetValue()}
249
+ visible={this.state.editing}
250
+ />
251
+ </div>
252
+
253
+ {this.props.description !== undefined &&
254
+ <small>{this.props.description}</small>
255
+ }
256
+
257
+
258
+ </div>
259
+
260
+ );
261
+ }
262
+
263
+ }
@@ -0,0 +1,152 @@
1
+ /*
2
+ * Copyright (C) 2024 Automated Design Corp. All Rights Reserved.
3
+ * Created Date: 2024-01-16 14:17:02
4
+ * -----
5
+ * Last Modified: 2024-03-21 15:24:54
6
+ * Modified By: ADC
7
+ * -----
8
+ *
9
+ */
10
+
11
+
12
+
13
+ import React, { Component } from 'react';
14
+
15
+ import { Tooltip } from "primereact/tooltip";
16
+
17
+ import { ValueDisplay } from './ValueDisplay';
18
+ import type { NumerableFormatOptions } from '../core/NumerableTypes';
19
+
20
+
21
+
22
+
23
+ /**
24
+ * Properties of the ValueDisplay component.
25
+ */
26
+ interface ValueIndicatorProps {
27
+
28
+ /**
29
+ * Label for the indicator.
30
+ */
31
+ label?: React.ReactNode | undefined;
32
+
33
+ /**
34
+ * Value to be displayed
35
+ */
36
+ value?: string | number | null | undefined;
37
+
38
+
39
+ /**
40
+ * Tooltip to display on hover
41
+ */
42
+ tooltip?: string | undefined;
43
+
44
+ /**
45
+ * Format for `value`<br/>
46
+ * See [numerable formats](https://github.com/gastonmesseri/numerable#1234-formatting-numbers)
47
+ */
48
+ format?: string | null | undefined;
49
+
50
+ /**
51
+ * Format options for `value`<br/>
52
+ * See [numerable format options](https://github.com/gastonmesseri/numerable#format)
53
+ */
54
+ formatOptions?: NumerableFormatOptions;
55
+
56
+ /**
57
+ * Custom class name to be attached
58
+ */
59
+ className?: string;
60
+
61
+ /**
62
+ * The topic to monitor to display. Optional.
63
+ */
64
+ topic?: string;
65
+ }
66
+
67
+ /**
68
+ * State of the ValueDisplay component.
69
+ */
70
+ interface ValueIndicatorState {
71
+ }
72
+
73
+
74
+
75
+ /**
76
+ * `ValueIndicator` wraps `ValueDisplay` in a frame and label, giving it a widget appearance.
77
+ * Care is taken to adapt to the selected theme of the application.
78
+ *
79
+ */
80
+ export class ValueIndicator extends Component<ValueIndicatorProps, ValueIndicatorState> {
81
+
82
+
83
+ /**
84
+ * The constructor initializes the component state and binds the initial value.
85
+ * @param {ValueIndicatorProps} props The properties passed to the component, including initial value and other display options.
86
+ */
87
+ constructor(props: ValueIndicatorProps) {
88
+ super(props);
89
+ this.state = {
90
+ };
91
+ }
92
+
93
+ /**
94
+ * Renders the component into the DOM.
95
+ * @returns A styled `div` element displaying the indicator.
96
+ */
97
+ render() {
98
+
99
+
100
+ return (
101
+ <>
102
+ <style>
103
+ {`
104
+ .value-indicator-container {
105
+
106
+ background-color: var(--surface-ground);
107
+ border-color: var(--surface-border);
108
+ border-radius: var(--border-radius);
109
+ border-width: 1px;
110
+ border-style: solid;
111
+ display: flex;
112
+ flex-direction: column;
113
+ justify-content: center;
114
+ align-items: center;
115
+ padding: 2mm;
116
+ }
117
+
118
+ .value-indicator-label {
119
+ padding-bottom: 1mm;
120
+ }
121
+ `}'
122
+ </style>
123
+ <Tooltip target=".value-indicator-tooltip" />
124
+ <span className="value-indicator-tooltip" >
125
+ <div className='value-indicator-container'>
126
+
127
+ {this.props.label !== undefined &&
128
+ <div className="value-indicator-label">
129
+ {this.props.label}
130
+ </div>
131
+ }
132
+
133
+ <ValueDisplay
134
+ className={this.props.className}
135
+ value={this.props.value}
136
+ format={this.props.format}
137
+ formatOptions={this.props.formatOptions}
138
+ topic={this.props.topic}
139
+ data-pr-tooltip={this.props.tooltip}
140
+ data-pr-position="down"
141
+ data-pr-mousetrack={true}
142
+ data-pr-showDelay={2000}
143
+ />
144
+ </div>
145
+ </span>
146
+ </>
147
+ );
148
+ }
149
+ }
150
+
151
+ export default ValueIndicator;
152
+ export { NumerableFormatOptions };
@@ -2,7 +2,7 @@
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-20 16:22:06
5
+ * Last Modified: 2024-03-21 09:37:17
6
6
  * -----
7
7
  *
8
8
  */
@@ -10,14 +10,13 @@
10
10
 
11
11
  import React from "react";
12
12
 
13
- import { InputText } from 'primereact/inputtext';
13
+ import { InputNumber} from 'primereact/inputnumber';
14
14
  import { Button } from "primereact/button";
15
15
 
16
16
  import { EventEmitterContext } from "../core/EventEmitterContext.js";
17
- import { KeyFilterType } from "primereact/keyfilter";
18
17
 
19
18
  /**
20
- * Properties of the Configuration View
19
+ * Properties of the ValueInput component.
21
20
  */
22
21
  interface ValueInputProps {
23
22
 
@@ -30,25 +29,90 @@ interface ValueInputProps {
30
29
  /**
31
30
  * The value for the field.
32
31
  */
33
- value : string | undefined;
32
+ value : number | null;
34
33
 
34
+ /**
35
+ * Minimum value for the field.
36
+ */
37
+ min : number | undefined;
35
38
 
36
- /**
37
- * Optional filter for key entry. Not a validator, but won't accept keystrokes outside the filter.
38
- * @type {RegExp | "pint" | "int" | "pnum" | "money" | "num" | "hex" | "email" | "alpha" | "alphanum"}
39
+ /**
40
+ * Minimum value for the field.
39
41
  */
40
- keyFilter : KeyFilterType | undefined;
41
-
42
+ max : number | undefined;
43
+
44
+ /**
45
+ * Minimum number of decimal points. The user will not
46
+ * be required to type the decimal values, but this minimum
47
+ * precision will always be displayed.
48
+ * Must be less than or equal to maxPrecision, or
49
+ * the component will throw an error.
50
+ * @default 0
51
+ */
52
+ minPrecision : number | undefined;
53
+
54
+
55
+ /**
56
+ * Maximum number of decimal points.
57
+ * Set to 0 for integer-only. Must be greater or equal to than minPrecision, or
58
+ * the component will throw an error.
59
+ * @default 3
60
+ */
61
+ maxPrecision : number | undefined;
62
+
63
+
64
+ /**
65
+ * Defines the behavior of the component.
66
+ * If set to "currency", then you need to specify the
67
+ * currency type using the currency property.
68
+ * @default "decimal"
69
+ */
70
+ mode : "currency" | "decimal" | undefined;
71
+
72
+
73
+ /**
74
+ * The currency to use in currency formatting. Possible values are the
75
+ * [ISO 4217 currency codes](https://www.six-group.com/en/products-services/financial-information/data-standards.html#scrollTo=maintenance-agency),
76
+ * such as "USD" for the US dollar, "EUR" for the euro, or "CNY" for the Chinese RMB.
77
+ * If the mode is "currency", the currency property must be provided.
78
+ *
79
+ * @default "USD"
80
+ */
81
+ currency : string;
42
82
 
43
83
  /**
44
- * An optional prefix before the data entry field.
84
+ * An optional prefix before the value of the field.
85
+ * Unlike the TextInput control, this prefix is internal to the field.
86
+ */
87
+ prefix : string | undefined;
88
+
89
+ /**
90
+ * An optional suffix after the value of the field.
91
+ * Unlike the TextInput control, this prefix is internal to the field.
45
92
  */
46
- prefix : React.ReactNode | undefined;
93
+ suffix : string | undefined;
47
94
 
48
95
  /**
49
- * An optional prefix before the data entry field.
96
+ * Set true to display buttons to increment/decrement the value.
97
+ * Use the step property to adjust the amount that the value will change.
98
+ *
99
+ * @default false
50
100
  */
51
- suffix : React.ReactNode | undefined;
101
+ showButtons : boolean;
102
+
103
+ /**
104
+ * The amount clicking an increment/decrement buttion will change the value.
105
+ */
106
+ step : number | undefined;
107
+
108
+
109
+ /**
110
+ * Locale to be used in formatting. Changes how the numbers/separators are displayed
111
+ * for international users. The typical locale codes are used.
112
+ *
113
+ * @default "en-US"
114
+ */
115
+ locale : string | undefined;
52
116
 
53
117
  /**
54
118
  * A small, advisory text below the field.
@@ -72,25 +136,22 @@ interface ValueInputProps {
72
136
  * The user has accepted a new value.
73
137
  * @param newValue New value accepted by the user.
74
138
  */
75
- onValueChanged?(newValue: string) : void;
76
- /** Regular expression used to validate the value before it is broadcast */
77
- validator : RegExp;
139
+ onValueChanged?(newValue: number) : void;
78
140
  }
79
141
 
80
142
  /**
81
- * State variables of the Configuration View
143
+ * State variables of the ValueInput component.
82
144
  */
83
145
  interface ValueInputState {
84
146
 
85
- entryValue : string | undefined;
86
- isValid : boolean;
147
+ entryValue : number | null;
87
148
  editing : boolean;
88
149
  }
89
150
 
90
151
 
91
152
  /**
92
- * A convenient field with all the usual features of inputing values.
93
- * Wraps the common features of use of a InputText, p-inputgroup, some icon buttons,
153
+ * A convenient field with all the usual features of inputing numbers.
154
+ * Wraps the common features of use of a InputNumber, p-inputgroup, some icon buttons,
94
155
  * accepting and rejecting values and keyboard management.
95
156
  */
96
157
  export class ValueInput extends React.Component<ValueInputProps, ValueInputState> {
@@ -121,7 +182,16 @@ export class ValueInput extends React.Component<ValueInputProps, ValueInputState
121
182
  disabled : false,
122
183
  dispatchTopic : undefined,
123
184
  placeholder : undefined,
124
- validator : 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"
125
195
  };
126
196
 
127
197
  /**
@@ -132,7 +202,6 @@ export class ValueInput extends React.Component<ValueInputProps, ValueInputState
132
202
  super(props);
133
203
  this.state = {
134
204
  entryValue : props.value,
135
- isValid : props.value !== undefined ? this.validateValue(props.value) : false,
136
205
  editing : false
137
206
  };
138
207
  }
@@ -145,45 +214,20 @@ export class ValueInput extends React.Component<ValueInputProps, ValueInputState
145
214
 
146
215
 
147
216
 
148
- /**
149
- * Check the new value against the validator RegEx, if one was specified.
150
- * @param val The new value.
151
- * @returns True if no validator specified or the value is valid, false if not valid.
152
- */
153
- private validateValue = (val : string) => {
154
-
155
- if (this.props.validator !== undefined && this.props.validator !== null) {
156
- return this.props.validator.test(val);
157
- }
158
- else {
159
- return true;
160
- }
161
-
162
- };
163
-
164
-
165
217
  /**
166
218
  * The user has elected to accept the input value. Validate and store, if valid.
167
219
  */
168
220
  private onAcceptValue() {
169
- if (this.state.entryValue !== undefined ) {
170
- if (this.validateValue(this.state.entryValue) ) {
171
- this.setState({isValid : true, editing : false});
172
-
173
- if (this.props.onValueChanged)
174
- this.props.onValueChanged(this.state.entryValue);
175
-
176
- if (this.props.dispatchTopic !== undefined) {
177
- this.context.dispatch({topic: this.props.dispatchTopic, payload:this.state.entryValue});
178
- }
179
-
221
+ if (this.state.entryValue !== null ) {
222
+ this.setState({editing : false});
223
+
224
+ if (this.props.onValueChanged)
225
+ this.props.onValueChanged(this.state.entryValue);
226
+
227
+ if (this.props.dispatchTopic !== undefined) {
228
+ this.context.dispatch({topic: this.props.dispatchTopic, payload:this.state.entryValue});
180
229
  }
181
- else {
182
- this.setState({isValid : false});
183
- }
184
- }
185
- else {
186
- this.setState({isValid: false});
230
+
187
231
  }
188
232
  }
189
233
 
@@ -193,7 +237,6 @@ export class ValueInput extends React.Component<ValueInputProps, ValueInputState
193
237
  private onResetValue() {
194
238
  this.setState({
195
239
  entryValue: this.props.value,
196
- isValid: this.props.value !== undefined ? this.validateValue(this.props.value) : false,
197
240
  editing : false
198
241
  });
199
242
  }
@@ -206,18 +249,30 @@ export class ValueInput extends React.Component<ValueInputProps, ValueInputState
206
249
  <div className="p-inputgroup flex-1" >
207
250
  <span className="p-inputgroup-addon">
208
251
  {this.props.label}
209
- </span>
210
- { this.props.prefix !== undefined &&
211
- <span className="p-inputgroup-addon">
212
- {this.props.prefix}
213
- </span>
214
- }
215
- <InputText
216
- keyfilter={this.props.keyFilter}
252
+ </span>
253
+ <InputNumber
254
+ min={this.props.min}
255
+ max={this.props.max}
256
+ minFractionDigits={this.props.minPrecision}
257
+ maxFractionDigits={this.props.maxPrecision}
258
+ mode={this.props.mode}
259
+ prefix={this.props.prefix}
260
+ suffix={this.props.suffix}
261
+ showButtons={this.props.showButtons}
262
+ step={this.props.step}
217
263
  placeholder={this.props.placeholder}
218
264
  value={this.state.entryValue}
219
- onChange={(e) => {this.setState({entryValue: e.target.value, editing : true})} }
220
- className={this.state.isValid ? '' : 'p-invalid'}
265
+ onChange={(e) => {this.setState({entryValue: e.value, editing : true})} }
266
+
267
+ buttonLayout="horizontal"
268
+ decrementButtonClassName="p-button-danger"
269
+ incrementButtonClassName="p-button-success"
270
+ incrementButtonIcon="pi pi-plus"
271
+ decrementButtonIcon="pi pi-minus"
272
+
273
+ locale="en-US"
274
+ currency={this.props.currency}
275
+
221
276
  onKeyDown={(e) => {
222
277
  if (e.key === 'Enter') {
223
278
  this.onAcceptValue();
@@ -226,18 +281,15 @@ export class ValueInput extends React.Component<ValueInputProps, ValueInputState
226
281
  this.onResetValue();
227
282
  }
228
283
  }}
229
- disabled={this.props.disabled}
230
- />
231
- { this.props.suffix !== undefined &&
232
- <span className="p-inputgroup-addon">
233
- {this.props.suffix}
234
- </span>
235
- }
284
+ disabled={this.props.disabled}
285
+ />
236
286
  <Button
237
287
  icon="pi pi-check"
238
288
  disabled={this.props.disabled || !this.state.editing}
239
289
  className="p-button-success"
240
290
  onClick={() => this.onAcceptValue()}
291
+ visible={this.state.editing}
292
+ size="small"
241
293
  />
242
294
 
243
295
  <Button
@@ -245,6 +297,8 @@ export class ValueInput extends React.Component<ValueInputProps, ValueInputState
245
297
  disabled={this.props.disabled || !this.state.editing}
246
298
  className="p-button-danger"
247
299
  onClickCapture={()=>this.onResetValue()}
300
+ visible={this.state.editing}
301
+ size="small"
248
302
  />
249
303
  </div>
250
304