@adcops/autocore-react 3.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE +59 -0
- package/additional-docs/ButtonApiSpecs.md +48 -0
- package/additional-docs/GlobalEventEmitter.md +244 -0
- package/additional-docs/general_recommendations.md +22 -0
- package/dist/components/DPad.css +522 -0
- package/dist/components/DPad.d.ts +34 -0
- package/dist/components/DPad.js +1 -0
- package/dist/components/Indicator.d.ts +81 -0
- package/dist/components/Indicator.js +1 -0
- package/dist/components/IndicatorButton.d.ts +137 -0
- package/dist/components/IndicatorButton.js +1 -0
- package/dist/components/IndicatorColor.d.ts +26 -0
- package/dist/components/IndicatorColor.js +1 -0
- package/dist/components/Osk.d.ts +14 -0
- package/dist/components/Osk.js +1 -0
- package/dist/components/OskDialog.d.ts +33 -0
- package/dist/components/OskDialog.js +1 -0
- package/dist/components/ValueDisplay.d.ts +99 -0
- package/dist/components/ValueDisplay.js +1 -0
- package/dist/components/osk.css +123 -0
- package/dist/core/EventEmitterContext.d.ts +223 -0
- package/dist/core/EventEmitterContext.js +1 -0
- package/dist/core/MaskPatterns.d.ts +71 -0
- package/dist/core/MaskPatterns.js +1 -0
- package/dist/core/NumerableTypes.d.ts +58 -0
- package/dist/core/NumerableTypes.js +1 -0
- package/dist/core/PositionContext.d.ts +38 -0
- package/dist/core/PositionContext.js +1 -0
- package/dist/core/UniqueId.d.ts +16 -0
- package/dist/core/UniqueId.js +1 -0
- package/dist/core/ValueSimulator.d.ts +71 -0
- package/dist/core/ValueSimulator.js +1 -0
- package/dist/core/hoc.d.ts +31 -0
- package/dist/core/hoc.js +1 -0
- package/dist/hub/HubBase.d.ts +169 -0
- package/dist/hub/HubBase.js +1 -0
- package/dist/hub/HubSimulate.d.ts +20 -0
- package/dist/hub/HubSimulate.js +1 -0
- package/dist/hub/HubSocketIo.d.ts +101 -0
- package/dist/hub/HubSocketIo.js +1 -0
- package/dist/hub/HubTauri.d.ts +86 -0
- package/dist/hub/HubTauri.js +1 -0
- package/dist/hub/index.d.ts +13 -0
- package/dist/hub/index.js +1 -0
- package/docs/.nojekyll +1 -0
- package/docs/assets/highlight.css +106 -0
- package/docs/assets/icons.js +15 -0
- package/docs/assets/icons.svg +1 -0
- package/docs/assets/main.js +59 -0
- package/docs/assets/navigation.js +1 -0
- package/docs/assets/search.js +1 -0
- package/docs/assets/style.css +1414 -0
- package/docs/classes/components_Indicator.Indicator.html +105 -0
- package/docs/classes/components_IndicatorButton.IndicatorButton.html +119 -0
- package/docs/classes/components_OskDialog.OskDialog.html +117 -0
- package/docs/classes/components_ValueDisplay.ValueDisplay.html +104 -0
- package/docs/classes/core_ValueSimulator.ValueSimulator.html +41 -0
- package/docs/classes/hub_HubBase.HubBase.html +67 -0
- package/docs/classes/hub_HubSimulate.HubSimulate.html +72 -0
- package/docs/classes/hub_HubSocketIo.HubSocketIo.html +80 -0
- package/docs/classes/hub_HubTauri.HubTauri.html +80 -0
- package/docs/enums/components_DPad.VcJoyPadAction.html +10 -0
- package/docs/enums/components_DPad.VcJoyPadButtonId.html +7 -0
- package/docs/enums/components_IndicatorButton.ActionMode.html +6 -0
- package/docs/enums/components_IndicatorColor.IndicatorColor.html +13 -0
- package/docs/functions/components_DPad.VcDPad.html +5 -0
- package/docs/functions/components_Osk.Osk.html +5 -0
- package/docs/functions/core_EventEmitterContext.EventEmitterProvider.html +8 -0
- package/docs/functions/core_UniqueId.UniqueId.html +4 -0
- package/docs/functions/core_hoc.hocAddSubscription.html +6 -0
- package/docs/functions/hub.createHub.html +3 -0
- package/docs/hierarchy.html +1 -0
- package/docs/index.html +69 -0
- package/docs/interfaces/components_IndicatorButton.IndicatorButtonProps.html +635 -0
- package/docs/interfaces/components_IndicatorButton.IndicatorButtonState.html +10 -0
- package/docs/interfaces/core_DimensionsContext.IDimensionsContext.html +4 -0
- package/docs/interfaces/core_EventEmitterContext.Action.html +5 -0
- package/docs/interfaces/core_EventEmitterContext.EventEmitterContextType.html +18 -0
- package/docs/interfaces/core_EventEmitterContext.State.html +8 -0
- package/docs/interfaces/core_EventEmitterContext.Subscription.html +6 -0
- package/docs/modules/components_DPad.html +5 -0
- package/docs/modules/components_Indicator.html +4 -0
- package/docs/modules/components_IndicatorButton.html +7 -0
- package/docs/modules/components_IndicatorColor.html +2 -0
- package/docs/modules/components_Osk.html +3 -0
- package/docs/modules/components_OskDialog.html +3 -0
- package/docs/modules/components_ValueDisplay.html +3 -0
- package/docs/modules/core_DimensionsContext.html +4 -0
- package/docs/modules/core_EventEmitterContext.html +11 -0
- package/docs/modules/core_InputPatterns.html +2 -0
- package/docs/modules/core_NumerableTypes.html +2 -0
- package/docs/modules/core_UniqueId.html +2 -0
- package/docs/modules/core_ValueSimulator.html +3 -0
- package/docs/modules/core_hoc.html +3 -0
- package/docs/modules/hub.html +6 -0
- package/docs/modules/hub_HubBase.html +3 -0
- package/docs/modules/hub_HubSimulate.html +3 -0
- package/docs/modules/hub_HubSocketIo.html +3 -0
- package/docs/modules/hub_HubTauri.html +2 -0
- package/docs/types/core_EventEmitterContext.EmitterDispatchFunction.html +1 -0
- package/docs/types/core_EventEmitterContext.EmitterSubscribeFunction.html +1 -0
- package/docs/types/core_EventEmitterContext.EmitterUnsubscribeFunction.html +1 -0
- package/docs/types/core_NumerableTypes.NumerableFormatOptions.html +1 -0
- package/docs/types/core_hoc.HocAddSubscriptionProps.html +4 -0
- package/docs/variables/core_DimensionsContext.DimensionsContext.html +1 -0
- package/docs/variables/core_EventEmitterContext.EventEmitterContext.html +5 -0
- package/docs/variables/core_InputPatterns.InputPatterns.html +2 -0
- package/package.json +79 -0
- package/readme.md +140 -0
- package/src/components/DPad.css +522 -0
- package/src/components/DPad.tsx +94 -0
- package/src/components/Indicator.tsx +243 -0
- package/src/components/IndicatorButton.tsx +306 -0
- package/src/components/IndicatorColor.ts +36 -0
- package/src/components/Osk.tsx +193 -0
- package/src/components/OskDialog.tsx +165 -0
- package/src/components/ValueDisplay.tsx +181 -0
- package/src/components/osk.css +123 -0
- package/src/core/EventEmitterContext.tsx +394 -0
- package/src/core/MaskPatterns.ts +82 -0
- package/src/core/NumerableTypes.ts +81 -0
- package/src/core/PositionContext.ts +60 -0
- package/src/core/UniqueId.ts +41 -0
- package/src/core/ValueSimulator.ts +167 -0
- package/src/core/hoc.tsx +65 -0
- package/src/hub/HubBase.ts +293 -0
- package/src/hub/HubSimulate.ts +47 -0
- package/src/hub/HubSocketIo.ts +166 -0
- package/src/hub/HubTauri.ts +145 -0
- package/src/hub/index.ts +41 -0
- package/terser.config.cjs +25 -0
- package/todo.md +18 -0
- package/tools/copy-distribution-files.cjs +73 -0
- package/tools/minify.cjs +56 -0
- package/tsconfig.json +34 -0
- package/typedoc.json +13 -0
|
@@ -0,0 +1,193 @@
|
|
|
1
|
+
import React, { useState, useEffect, useRef } from 'react';
|
|
2
|
+
import { InputText } from 'primereact/inputtext';
|
|
3
|
+
import Keyboard from "react-simple-keyboard";
|
|
4
|
+
import "./osk.css";
|
|
5
|
+
import { RegExMaskPatterns } from "../core/MaskPatterns";
|
|
6
|
+
|
|
7
|
+
|
|
8
|
+
const numpadLayout = {
|
|
9
|
+
numbers: ["1 2 3", "4 5 6", "7 8 9", "- 0 .", "{symbols} {backspace}"],
|
|
10
|
+
default: ["! / #", "$ % ^", "& * (", "= ) +", "{numbers} {backspace}"]
|
|
11
|
+
};
|
|
12
|
+
|
|
13
|
+
|
|
14
|
+
const englishLayout = {
|
|
15
|
+
default: [
|
|
16
|
+
"q w e r t y u i o p",
|
|
17
|
+
"a s d f g h j k l",
|
|
18
|
+
"{shift} z x c v b n m {backspace}",
|
|
19
|
+
"{numbers} {space} {ent}"
|
|
20
|
+
],
|
|
21
|
+
shift: [
|
|
22
|
+
"Q W E R T Y U I O P",
|
|
23
|
+
"A S D F G H J K L",
|
|
24
|
+
"{shift} Z X C V B N M {backspace}",
|
|
25
|
+
"{numbers} {space} {ent}"
|
|
26
|
+
],
|
|
27
|
+
numbers: ["1 2 3", "4 5 6", "7 8 9", "{abc} 0 {backspace}"]
|
|
28
|
+
};
|
|
29
|
+
|
|
30
|
+
const keyboardDisplay = {
|
|
31
|
+
"{numbers}": "123",
|
|
32
|
+
"{ent}": "return",
|
|
33
|
+
"{escape}": "esc ⎋",
|
|
34
|
+
"{tab}": "tab ⇥",
|
|
35
|
+
"{backspace}": "⌫",
|
|
36
|
+
"{capslock}": "caps lock ⇪",
|
|
37
|
+
"{shift}": "⇧",
|
|
38
|
+
"{controlleft}": "ctrl ⌃",
|
|
39
|
+
"{controlright}": "ctrl ⌃",
|
|
40
|
+
"{altleft}": "alt ⌥",
|
|
41
|
+
"{altright}": "alt ⌥",
|
|
42
|
+
"{metaleft}": "cmd ⌘",
|
|
43
|
+
"{metaright}": "cmd ⌘",
|
|
44
|
+
"{abc}": "ABC",
|
|
45
|
+
"{space}": "space",
|
|
46
|
+
"{symbols}": "#+="
|
|
47
|
+
};
|
|
48
|
+
|
|
49
|
+
|
|
50
|
+
|
|
51
|
+
interface OskProps {
|
|
52
|
+
onAccept?: () => void;
|
|
53
|
+
onChange?: (value: string) => void;
|
|
54
|
+
isNumPad?: boolean;
|
|
55
|
+
input?: string;
|
|
56
|
+
label?: string;
|
|
57
|
+
inputPattern?: RegExp;
|
|
58
|
+
checkValue?: (value: string) => string;
|
|
59
|
+
description?: string;
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
export const Osk: React.FC<OskProps> = ({
|
|
63
|
+
onAccept,
|
|
64
|
+
onChange,
|
|
65
|
+
isNumPad = false,
|
|
66
|
+
input = "",
|
|
67
|
+
label = "",
|
|
68
|
+
inputPattern,
|
|
69
|
+
checkValue,
|
|
70
|
+
description,
|
|
71
|
+
}) => {
|
|
72
|
+
const [state, setState] = useState({
|
|
73
|
+
isVisible: false,
|
|
74
|
+
layoutName: isNumPad ? "numbers" : "default",
|
|
75
|
+
minWidth: 500,
|
|
76
|
+
maxWidth: 800,
|
|
77
|
+
input,
|
|
78
|
+
label,
|
|
79
|
+
isNumPad,
|
|
80
|
+
inputPattern: inputPattern || RegExMaskPatterns.IntegerPositive,
|
|
81
|
+
checkValue,
|
|
82
|
+
description,
|
|
83
|
+
firstKeyPressed: false,
|
|
84
|
+
onAccept: onAccept || undefined,
|
|
85
|
+
onChange: onChange || undefined
|
|
86
|
+
});
|
|
87
|
+
const keyboardRef = useRef<any>(null);
|
|
88
|
+
|
|
89
|
+
useEffect(() => {
|
|
90
|
+
return () => {
|
|
91
|
+
if (keyboardRef.current) {
|
|
92
|
+
keyboardRef.current.destroy();
|
|
93
|
+
}
|
|
94
|
+
};
|
|
95
|
+
}, []);
|
|
96
|
+
|
|
97
|
+
// const setProperty = (key: keyof typeof state, val: any) => {
|
|
98
|
+
// setState((prev) => ({ ...prev, [key]: val }));
|
|
99
|
+
// };
|
|
100
|
+
|
|
101
|
+
const onChanged = (val: string) => {
|
|
102
|
+
let newInput = val;
|
|
103
|
+
if (!state.firstKeyPressed) {
|
|
104
|
+
newInput = state.input + val;
|
|
105
|
+
keyboardRef.current.setInput(newInput);
|
|
106
|
+
}
|
|
107
|
+
|
|
108
|
+
if (state.onChange) {
|
|
109
|
+
state.onChange(newInput);
|
|
110
|
+
}
|
|
111
|
+
|
|
112
|
+
setState(prevState => ({ ...prevState, input: newInput, firstKeyPressed: true }));
|
|
113
|
+
};
|
|
114
|
+
|
|
115
|
+
|
|
116
|
+
const getLayout = () => {
|
|
117
|
+
if (state.isNumPad) {
|
|
118
|
+
if (state.isNumPad) {
|
|
119
|
+
|
|
120
|
+
if ( state.inputPattern === undefined || state.inputPattern === null) {
|
|
121
|
+
setState(prevState=> ({...prevState, inputPattern:RegExMaskPatterns.IntegerPositive}));
|
|
122
|
+
}
|
|
123
|
+
|
|
124
|
+
return numpadLayout;
|
|
125
|
+
}
|
|
126
|
+
else {
|
|
127
|
+
return englishLayout;
|
|
128
|
+
}
|
|
129
|
+
}
|
|
130
|
+
}
|
|
131
|
+
|
|
132
|
+
|
|
133
|
+
const onKeyPress = (button: string) => {
|
|
134
|
+
if (button === "{shift}" || button === "{lock}" || button == "{symbols}")
|
|
135
|
+
handleShift();
|
|
136
|
+
|
|
137
|
+
if (button === "{numbers}" || button === "{abc}")
|
|
138
|
+
handleNumbers();
|
|
139
|
+
|
|
140
|
+
if (button === "{backspace}" ) {
|
|
141
|
+
// Backspace was pressed
|
|
142
|
+
|
|
143
|
+
if ( !state.firstKeyPressed )
|
|
144
|
+
{
|
|
145
|
+
setState(prevState => ({...prevState, input:"",firstKeyPressed:true}));
|
|
146
|
+
}
|
|
147
|
+
}
|
|
148
|
+
};
|
|
149
|
+
|
|
150
|
+
|
|
151
|
+
|
|
152
|
+
/**
|
|
153
|
+
* Toggle between the shifted and default display when the shift key is pressed.
|
|
154
|
+
*/
|
|
155
|
+
const handleShift = () => {
|
|
156
|
+
let currentLayout = state.layoutName;
|
|
157
|
+
let shiftToggle = currentLayout === "default" ? "shift" : "default";
|
|
158
|
+
setState(prevState => ({...prevState, layoutName: shiftToggle }));
|
|
159
|
+
}
|
|
160
|
+
|
|
161
|
+
/**
|
|
162
|
+
* Toggle between the number and alpha-numeric display when the numbers key is pressed.
|
|
163
|
+
*/
|
|
164
|
+
const handleNumbers = () => {
|
|
165
|
+
let currentLayout = state.layoutName;
|
|
166
|
+
let numbersToggle = currentLayout !== "numbers" ? "numbers" : "default";
|
|
167
|
+
setState(prevState => ({...prevState, layoutName: numbersToggle }));
|
|
168
|
+
}
|
|
169
|
+
|
|
170
|
+
return (
|
|
171
|
+
<div>
|
|
172
|
+
<InputText
|
|
173
|
+
value={state.input}
|
|
174
|
+
readOnly={true}
|
|
175
|
+
tooltip={state.description}
|
|
176
|
+
/>
|
|
177
|
+
<br />
|
|
178
|
+
<Keyboard
|
|
179
|
+
keyboardRef={(r) => (keyboardRef.current = r)}
|
|
180
|
+
name='keyboard'
|
|
181
|
+
layoutName={state.layoutName}
|
|
182
|
+
layout={getLayout()}
|
|
183
|
+
display={keyboardDisplay}
|
|
184
|
+
physicalKeyboardHighlight={true}
|
|
185
|
+
physicalKeyboardHighlightPress={true}
|
|
186
|
+
onChange={(val) => onChanged(val)}
|
|
187
|
+
onKeyPress={(button) => onKeyPress(button)}
|
|
188
|
+
/>
|
|
189
|
+
</div>
|
|
190
|
+
);
|
|
191
|
+
};
|
|
192
|
+
|
|
193
|
+
export default Osk;
|
|
@@ -0,0 +1,165 @@
|
|
|
1
|
+
import React from 'react';
|
|
2
|
+
import ReactDOM from 'react-dom';
|
|
3
|
+
import { Dialog } from 'primereact/dialog';
|
|
4
|
+
import {Button} from "primereact/button";
|
|
5
|
+
import { Osk } from './Osk';
|
|
6
|
+
|
|
7
|
+
interface OskDialogProps {
|
|
8
|
+
isVisible: boolean;
|
|
9
|
+
onAccept?: (value: string) => void;
|
|
10
|
+
onReject?: () => void;
|
|
11
|
+
onChange?: (value: string) => void;
|
|
12
|
+
isNumPad?: boolean;
|
|
13
|
+
maxWidth?: number;
|
|
14
|
+
input?: string;
|
|
15
|
+
label?: string;
|
|
16
|
+
description?: string;
|
|
17
|
+
inputPattern?: RegExp;
|
|
18
|
+
textMode?: boolean;
|
|
19
|
+
minValue?: number;
|
|
20
|
+
maxValue?: number;
|
|
21
|
+
minLength?: number;
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
interface OskDialogState {
|
|
25
|
+
input: string;
|
|
26
|
+
errorMessage: string;
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
export class OskDialog extends React.Component<OskDialogProps, OskDialogState> {
|
|
30
|
+
private container: HTMLDivElement | null = null;
|
|
31
|
+
|
|
32
|
+
constructor(props: OskDialogProps) {
|
|
33
|
+
super(props);
|
|
34
|
+
this.state = {
|
|
35
|
+
input: props.input || "",
|
|
36
|
+
errorMessage: ""
|
|
37
|
+
};
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
componentWillUnmount() {
|
|
41
|
+
if (this.container) {
|
|
42
|
+
document.body.removeChild(this.container);
|
|
43
|
+
}
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
checkValue = (value: string): string => {
|
|
47
|
+
// Checks the value against settings and returns an error message
|
|
48
|
+
// if invalid. If the value is valid and should be accepted,
|
|
49
|
+
// a blank error message is returned.
|
|
50
|
+
|
|
51
|
+
var ok = true;
|
|
52
|
+
|
|
53
|
+
if (value !== undefined && value !== null && value.length > 0) {
|
|
54
|
+
|
|
55
|
+
if (this.props.inputPattern !== undefined) {
|
|
56
|
+
ok = this.props.inputPattern.test(value);
|
|
57
|
+
}
|
|
58
|
+
else if (!this.props.textMode) {
|
|
59
|
+
|
|
60
|
+
if (value.length < 0)
|
|
61
|
+
ok = false;
|
|
62
|
+
|
|
63
|
+
if (isNaN(parseFloat(value)))
|
|
64
|
+
ok = false;
|
|
65
|
+
|
|
66
|
+
|
|
67
|
+
var checkValue = parseFloat(value);
|
|
68
|
+
|
|
69
|
+
if (this.props.minValue !== undefined && this.props.minValue !== null) {
|
|
70
|
+
if (checkValue < this.props.minValue)
|
|
71
|
+
ok = false;
|
|
72
|
+
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
if (this.props.maxValue !== undefined && this.props.maxValue !== null) {
|
|
76
|
+
if (checkValue > this.props.maxValue)
|
|
77
|
+
ok = false;
|
|
78
|
+
}
|
|
79
|
+
}
|
|
80
|
+
else {
|
|
81
|
+
if (this.props.minLength !== undefined
|
|
82
|
+
&& value.length < this.props.minLength
|
|
83
|
+
) {
|
|
84
|
+
ok = false;
|
|
85
|
+
}
|
|
86
|
+
}
|
|
87
|
+
}
|
|
88
|
+
else {
|
|
89
|
+
ok = false;
|
|
90
|
+
}
|
|
91
|
+
|
|
92
|
+
if (ok) {
|
|
93
|
+
return "";
|
|
94
|
+
}
|
|
95
|
+
else {
|
|
96
|
+
return "Invalid value.";
|
|
97
|
+
}
|
|
98
|
+
}
|
|
99
|
+
|
|
100
|
+
onAccepted = () => {
|
|
101
|
+
const error = this.checkValue(this.state.input);
|
|
102
|
+
if (!error) {
|
|
103
|
+
this.props.onAccept?.(this.state.input);
|
|
104
|
+
this.closeDialog();
|
|
105
|
+
} else {
|
|
106
|
+
this.setState({ errorMessage: error });
|
|
107
|
+
}
|
|
108
|
+
}
|
|
109
|
+
|
|
110
|
+
onChanged = (val: string) => {
|
|
111
|
+
this.setState({ input: val, errorMessage: "" });
|
|
112
|
+
if (this.props.onChange) {
|
|
113
|
+
this.props.onChange(val);
|
|
114
|
+
}
|
|
115
|
+
}
|
|
116
|
+
|
|
117
|
+
closeDialog = () => {
|
|
118
|
+
if (this.container) {
|
|
119
|
+
ReactDOM.unmountComponentAtNode(this.container);
|
|
120
|
+
this.container = null;
|
|
121
|
+
}
|
|
122
|
+
this.props.onReject?.();
|
|
123
|
+
}
|
|
124
|
+
|
|
125
|
+
show = () => {
|
|
126
|
+
if (!this.container) {
|
|
127
|
+
this.container = document.createElement('div');
|
|
128
|
+
document.body.appendChild(this.container);
|
|
129
|
+
}
|
|
130
|
+
|
|
131
|
+
const footerContent = (
|
|
132
|
+
<div>
|
|
133
|
+
<Button label="Cancel" icon="pi pi-times" onClick={() => this.closeDialog()} className="p-button-text" />
|
|
134
|
+
<Button label="Accept" icon="pi pi-check" onClick={() => this.onAccepted()} autoFocus />
|
|
135
|
+
</div>
|
|
136
|
+
);
|
|
137
|
+
|
|
138
|
+
|
|
139
|
+
ReactDOM.render(
|
|
140
|
+
<Dialog
|
|
141
|
+
visible={this.props.isVisible}
|
|
142
|
+
onHide={this.closeDialog}
|
|
143
|
+
header={this.props.label}
|
|
144
|
+
style={{ width: this.props.maxWidth || '50vw' }}
|
|
145
|
+
footer={footerContent}
|
|
146
|
+
>
|
|
147
|
+
<Osk
|
|
148
|
+
onChange={this.onChanged}
|
|
149
|
+
isNumPad={this.props.isNumPad}
|
|
150
|
+
inputPattern={this.props.inputPattern}
|
|
151
|
+
input={this.state.input}
|
|
152
|
+
/>
|
|
153
|
+
{this.state.errorMessage && <div className="error-message">{this.state.errorMessage}</div>}
|
|
154
|
+
</Dialog>,
|
|
155
|
+
this.container
|
|
156
|
+
);
|
|
157
|
+
}
|
|
158
|
+
|
|
159
|
+
render() {
|
|
160
|
+
// The actual rendering is handled by the show method.
|
|
161
|
+
return null;
|
|
162
|
+
}
|
|
163
|
+
}
|
|
164
|
+
|
|
165
|
+
export default OskDialog;
|
|
@@ -0,0 +1,181 @@
|
|
|
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-08 07:48:42
|
|
6
|
+
* Modified By: ADC
|
|
7
|
+
* -----
|
|
8
|
+
*
|
|
9
|
+
*/
|
|
10
|
+
|
|
11
|
+
|
|
12
|
+
|
|
13
|
+
import {Component} from 'react';
|
|
14
|
+
//import useFitText from 'use-fit-text';
|
|
15
|
+
import { format as numerableFormat } from 'numerable';
|
|
16
|
+
import clsx from 'clsx';
|
|
17
|
+
import { EventEmitterContext, EventEmitterContextType} from '../core/EventEmitterContext';
|
|
18
|
+
|
|
19
|
+
import {IPositionContext} from '../core/PositionContext';
|
|
20
|
+
import type { NumerableFormatOptions } from '../core/NumerableTypes';
|
|
21
|
+
|
|
22
|
+
/**
|
|
23
|
+
* Properties of the ValueDisplay component.
|
|
24
|
+
*/
|
|
25
|
+
interface Props {
|
|
26
|
+
/**
|
|
27
|
+
* Value to be displayed
|
|
28
|
+
*/
|
|
29
|
+
value?: string | number | null | undefined;
|
|
30
|
+
/**
|
|
31
|
+
* X position (in pixels)
|
|
32
|
+
*/
|
|
33
|
+
x?: number;
|
|
34
|
+
/**
|
|
35
|
+
* Y position (in pixels)
|
|
36
|
+
*/
|
|
37
|
+
y?: number;
|
|
38
|
+
/**
|
|
39
|
+
* Width (in pixels)
|
|
40
|
+
*/
|
|
41
|
+
width?: number;
|
|
42
|
+
/**
|
|
43
|
+
* Height (in pixels)<br/>
|
|
44
|
+
* @default width
|
|
45
|
+
*/
|
|
46
|
+
height?: number;
|
|
47
|
+
/**
|
|
48
|
+
* Format for `value`<br/>
|
|
49
|
+
* See [numerable formats](https://github.com/gastonmesseri/numerable#1234-formatting-numbers)
|
|
50
|
+
*/
|
|
51
|
+
format?: string | null | undefined;
|
|
52
|
+
/**
|
|
53
|
+
* Format options for `value`<br/>
|
|
54
|
+
* See [numerable format options](https://github.com/gastonmesseri/numerable#format)
|
|
55
|
+
*/
|
|
56
|
+
formatOptions?: NumerableFormatOptions;
|
|
57
|
+
/**
|
|
58
|
+
* Custom class name to be attached
|
|
59
|
+
*/
|
|
60
|
+
className?: string;
|
|
61
|
+
|
|
62
|
+
/**
|
|
63
|
+
* Enable absolute positioning for the component, allowing it to be
|
|
64
|
+
* placed on a specific position of its parent. This is useful when
|
|
65
|
+
* laying components over an image or wireframe.
|
|
66
|
+
*/
|
|
67
|
+
useAbsolutePositioning?: boolean;
|
|
68
|
+
|
|
69
|
+
|
|
70
|
+
/**
|
|
71
|
+
* The topic to monitor to display. Optional.
|
|
72
|
+
*/
|
|
73
|
+
topic?: string;
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
/**
|
|
77
|
+
* State of the ValueDisplay component.
|
|
78
|
+
*/
|
|
79
|
+
interface State {
|
|
80
|
+
subscribedValue?: string | number | null;
|
|
81
|
+
fontSize?: string;
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
|
|
85
|
+
|
|
86
|
+
/**
|
|
87
|
+
* `ValueDisplay` is a React component that subscribes to a value from an `EventEmitterContext` and renders it.
|
|
88
|
+
* This component adjusts its display based on the provided properties, including positioning and styling adjustments
|
|
89
|
+
* based on its context. It is designed to work within a system that provides dynamic updates to values via an event emitter.
|
|
90
|
+
*/
|
|
91
|
+
class ValueDisplay extends Component<Props, State> {
|
|
92
|
+
|
|
93
|
+
/** Defines the context type to subscribe to changes using EventEmitter. */
|
|
94
|
+
static contextType = EventEmitterContext;
|
|
95
|
+
|
|
96
|
+
|
|
97
|
+
/** ID for the subscription to the topic, used to unsubscribe on component unmount. */
|
|
98
|
+
protected unsubscribeTopicId: number | null = null;
|
|
99
|
+
|
|
100
|
+
/**
|
|
101
|
+
* The constructor initializes the component state and binds the initial value.
|
|
102
|
+
* @param props The properties passed to the component, including initial value and other display options.
|
|
103
|
+
*/
|
|
104
|
+
constructor(props: Props) {
|
|
105
|
+
super(props);
|
|
106
|
+
this.state = {
|
|
107
|
+
subscribedValue: props.value,
|
|
108
|
+
fontSize: '100%' // Initial font size, adjust as needed
|
|
109
|
+
};
|
|
110
|
+
}
|
|
111
|
+
|
|
112
|
+
/**
|
|
113
|
+
* Upon mounting, the component subscribes to updates on the specified topic if it exists,
|
|
114
|
+
* updating its state with the new value when the topic publishes updates.
|
|
115
|
+
*/
|
|
116
|
+
componentDidMount() {
|
|
117
|
+
const { topic } = this.props;
|
|
118
|
+
if (topic) {
|
|
119
|
+
const { subscribe } = this.context as EventEmitterContextType;
|
|
120
|
+
this.unsubscribeTopicId = subscribe(topic, (value: any) => {
|
|
121
|
+
this.setState({ subscribedValue: value });
|
|
122
|
+
});
|
|
123
|
+
}
|
|
124
|
+
}
|
|
125
|
+
|
|
126
|
+
/**
|
|
127
|
+
* If the value prop changes, the component updates its state with the new value.
|
|
128
|
+
* This ensures that the component remains in sync with its props.
|
|
129
|
+
* @param prevProps The previous properties for comparison to detect changes.
|
|
130
|
+
*/
|
|
131
|
+
componentDidUpdate(prevProps: Props) {
|
|
132
|
+
// Check if the value prop has changed
|
|
133
|
+
if (this.props.value !== prevProps.value) {
|
|
134
|
+
// Update the state with the new value
|
|
135
|
+
this.setState({ subscribedValue: this.props.value });
|
|
136
|
+
}
|
|
137
|
+
}
|
|
138
|
+
|
|
139
|
+
/**
|
|
140
|
+
* Before the component is unmounted, it unsubscribes from the topic to prevent memory leaks
|
|
141
|
+
* and unnecessary updates from occurring.
|
|
142
|
+
*/
|
|
143
|
+
componentWillUnmount() {
|
|
144
|
+
if (this.unsubscribeTopicId) {
|
|
145
|
+
const { unsubscribe } = this.context as EventEmitterContextType;
|
|
146
|
+
unsubscribe(this.unsubscribeTopicId);
|
|
147
|
+
}
|
|
148
|
+
}
|
|
149
|
+
|
|
150
|
+
/**
|
|
151
|
+
* Renders the component with styling and formatting based on the provided properties and state.
|
|
152
|
+
* Supports absolute or relative positioning and scales the display based on the context's dimensions.
|
|
153
|
+
* @returns A styled `div` element displaying the formatted value.
|
|
154
|
+
*/
|
|
155
|
+
render() {
|
|
156
|
+
const { x, y, width, height, format, formatOptions, className, useAbsolutePositioning } = this.props;
|
|
157
|
+
const { subscribedValue, fontSize } = this.state;
|
|
158
|
+
const { scale, xOffset, yOffset } = this.context as IPositionContext;
|
|
159
|
+
|
|
160
|
+
const style : React.CSSProperties = {
|
|
161
|
+
position: useAbsolutePositioning ? 'absolute' : 'relative',
|
|
162
|
+
display: useAbsolutePositioning ? "" : "inline-block",
|
|
163
|
+
verticalAlign: 'middle',
|
|
164
|
+
fontSize: fontSize && scale > 1 ? `${scale * 100}%` : fontSize,
|
|
165
|
+
top: useAbsolutePositioning && y ? `${yOffset + scale * y}px` : undefined,
|
|
166
|
+
left: useAbsolutePositioning && x ? `${xOffset + scale * x}px` : undefined,
|
|
167
|
+
width: width ? `${width * scale}px` : undefined,
|
|
168
|
+
height: height ? `${height * scale}px` : undefined,
|
|
169
|
+
lineHeight: height ? `${height * scale}px` : undefined,
|
|
170
|
+
whiteSpace: 'nowrap',
|
|
171
|
+
};
|
|
172
|
+
|
|
173
|
+
return (
|
|
174
|
+
<div className={clsx(className)} style={style}>
|
|
175
|
+
{numerableFormat(subscribedValue, format, formatOptions)}
|
|
176
|
+
</div>
|
|
177
|
+
);
|
|
178
|
+
}
|
|
179
|
+
}
|
|
180
|
+
|
|
181
|
+
export { ValueDisplay, NumerableFormatOptions };
|
|
@@ -0,0 +1,123 @@
|
|
|
1
|
+
/*
|
|
2
|
+
* Customized by Thomas C. Bitsky Jr. Automated Design Corporation.
|
|
3
|
+
*
|
|
4
|
+
* Original file:
|
|
5
|
+
*
|
|
6
|
+
* simple-keyboard v2.32.100
|
|
7
|
+
* https://github.com/hodgef/simple-keyboard
|
|
8
|
+
*
|
|
9
|
+
* Copyright (c) Francisco Hodge (https://github.com/hodgef)
|
|
10
|
+
*/
|
|
11
|
+
|
|
12
|
+
.hg-theme-default {
|
|
13
|
+
width: 100%;
|
|
14
|
+
-webkit-user-select: none;
|
|
15
|
+
-moz-user-select: none;
|
|
16
|
+
-ms-user-select: none;
|
|
17
|
+
user-select: none;
|
|
18
|
+
box-sizing: border-box;
|
|
19
|
+
overflow: hidden;
|
|
20
|
+
touch-action: manipulation
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
.hg-theme-default .hg-button span {
|
|
24
|
+
pointer-events: none
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
.hg-theme-default button.hg-button {
|
|
28
|
+
border-width: 0;
|
|
29
|
+
outline: 0;
|
|
30
|
+
font-size: inherit
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
.hg-theme-default {
|
|
34
|
+
background-color: #ececec;
|
|
35
|
+
padding: 5px;
|
|
36
|
+
border-radius: 5px
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
.hg-theme-default .hg-button {
|
|
40
|
+
display: inline-block;
|
|
41
|
+
flex-grow: 1
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
.hg-theme-default .hg-row {
|
|
45
|
+
display: flex
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
.hg-theme-default .hg-row:not(:last-child) {
|
|
49
|
+
margin-bottom: 5px
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
.hg-theme-default .hg-row .hg-button-container,
|
|
53
|
+
.hg-theme-default .hg-row .hg-button:not(:last-child) {
|
|
54
|
+
margin-right: 5px
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
.hg-theme-default .hg-row>div:last-child {
|
|
58
|
+
margin-right: 0
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
.hg-theme-default .hg-row .hg-button-container {
|
|
62
|
+
display: flex
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
.hg-theme-default .hg-button {
|
|
66
|
+
/* box-shadow: 0 0 3px -1px rgba(0, 0, 0, .3); */ /* use the shadow for an ios look */
|
|
67
|
+
font-weight: 600;
|
|
68
|
+
font-size: large;
|
|
69
|
+
height: 40px;
|
|
70
|
+
border-radius: 3px; /* set to 5 for ios look, 3 for microsoft look */
|
|
71
|
+
box-sizing: border-box;
|
|
72
|
+
padding: 5px;
|
|
73
|
+
color: white; /* color of the button text */
|
|
74
|
+
background: #444444; /* background of the button text */
|
|
75
|
+
border: 1px solid black;
|
|
76
|
+
cursor:pointer;
|
|
77
|
+
display: flex;
|
|
78
|
+
align-items: center;
|
|
79
|
+
justify-content: center;
|
|
80
|
+
-webkit-tap-highlight-color: rgba(0, 0, 0, 0)
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
.hg-theme-default .hg-button.hg-activeButton {
|
|
84
|
+
background: #efefef
|
|
85
|
+
}
|
|
86
|
+
|
|
87
|
+
.hg-theme-default.hg-layout-numeric .hg-button {
|
|
88
|
+
width: 33.3%;
|
|
89
|
+
height: 60px;
|
|
90
|
+
align-items: center;
|
|
91
|
+
display: flex;
|
|
92
|
+
justify-content: center
|
|
93
|
+
}
|
|
94
|
+
|
|
95
|
+
.hg-theme-default .hg-button.hg-button-numpadadd,
|
|
96
|
+
.hg-theme-default .hg-button.hg-button-numpadenter {
|
|
97
|
+
height: 85px
|
|
98
|
+
}
|
|
99
|
+
|
|
100
|
+
.hg-theme-default .hg-button.hg-button-numpad0 {
|
|
101
|
+
width: 105px
|
|
102
|
+
}
|
|
103
|
+
|
|
104
|
+
.hg-theme-default .hg-button.hg-button-com {
|
|
105
|
+
max-width: 85px
|
|
106
|
+
}
|
|
107
|
+
|
|
108
|
+
.hg-theme-default .hg-button.hg-standardBtn.hg-button-at {
|
|
109
|
+
max-width: 45px
|
|
110
|
+
}
|
|
111
|
+
|
|
112
|
+
.hg-theme-default .hg-button.hg-selectedButton {
|
|
113
|
+
background: rgba(5, 25, 70, .53);
|
|
114
|
+
color: #fff
|
|
115
|
+
}
|
|
116
|
+
|
|
117
|
+
.hg-theme-default .hg-button.hg-standardBtn[data-skbtn=".com"] {
|
|
118
|
+
max-width: 82px
|
|
119
|
+
}
|
|
120
|
+
|
|
121
|
+
.hg-theme-default .hg-button.hg-standardBtn[data-skbtn="@"] {
|
|
122
|
+
max-width: 60px
|
|
123
|
+
}
|