@adcops/autocore-react 3.3.9 → 3.3.10
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE +58 -58
- package/additional-docs/AutoCoreTagContext.md +441 -441
- package/additional-docs/ButtonApiSpecs.md +48 -48
- package/additional-docs/GlobalEventEmitter.md +243 -243
- package/additional-docs/general_recommendations.md +22 -22
- package/additional-docs/react_performance_notes.md +94 -94
- package/dist/assets/svg/blockly_logo.svg +82 -82
- package/dist/assets/svg/distance.svg +40 -40
- package/dist/assets/svg/python_logo.svg +246 -246
- package/dist/assets/svg/rotation_ccw.svg +50 -50
- package/dist/assets/svg/rotation_ccw_a.svg +57 -57
- package/dist/assets/svg/rotation_ccw_b.svg +57 -57
- package/dist/assets/svg/rotation_ccw_c.svg +57 -57
- package/dist/assets/svg/rotation_cw.svg +49 -49
- package/dist/assets/svg/rotation_cw_a.svg +30 -30
- package/dist/assets/svg/rotation_cw_b.svg +30 -30
- package/dist/assets/svg/rotation_cw_c.svg +30 -30
- package/dist/assets/svg/speed.svg +39 -39
- package/dist/components/BlocklyEditor.css +93 -93
- package/dist/components/JogPanel.css +41 -41
- package/dist/components/ProgressBarWithValue.css +27 -27
- package/dist/components/ValueIndicator.css +31 -31
- package/dist/components/osk.css +123 -123
- package/dist/core/AutoCoreTagContext.d.ts.map +1 -1
- package/dist/core/AutoCoreTagContext.js +1 -1
- package/dist/hub/HubBase.d.ts +3 -3
- package/dist/hub/HubBase.d.ts.map +1 -1
- package/dist/hub/HubBase.js +1 -1
- package/package.json +104 -104
- package/readme.md +343 -343
- package/src/assets/BlocklyLogo.tsx +27 -27
- package/src/assets/Distance.tsx +18 -18
- package/src/assets/JogLong.tsx +13 -13
- package/src/assets/JogMedium.tsx +13 -13
- package/src/assets/JogShort.tsx +13 -13
- package/src/assets/PythonLogo.tsx +83 -83
- package/src/assets/Rotation3D.tsx +13 -13
- package/src/assets/RotationCcw.tsx +33 -33
- package/src/assets/RotationCcwA.tsx +45 -45
- package/src/assets/RotationCcwB.tsx +45 -45
- package/src/assets/RotationCcwC.tsx +45 -45
- package/src/assets/RotationCw.tsx +31 -31
- package/src/assets/RotationCwA.tsx +42 -42
- package/src/assets/RotationCwB.tsx +42 -42
- package/src/assets/RotationCwC.tsx +42 -42
- package/src/assets/Run.tsx +13 -13
- package/src/assets/Speed.tsx +18 -18
- package/src/assets/SpeedFast.tsx +13 -13
- package/src/assets/SpeedMedium.tsx +13 -13
- package/src/assets/SpeedNone.tsx +13 -13
- package/src/assets/SpeedSlow.tsx +13 -13
- package/src/assets/Walk.tsx +13 -13
- package/src/assets/index.ts +22 -22
- package/src/assets/svg/blockly_logo.svg +82 -82
- package/src/assets/svg/distance.svg +40 -40
- package/src/assets/svg/python_logo.svg +246 -246
- package/src/assets/svg/rotation_ccw.svg +50 -50
- package/src/assets/svg/rotation_ccw_a.svg +57 -57
- package/src/assets/svg/rotation_ccw_b.svg +57 -57
- package/src/assets/svg/rotation_ccw_c.svg +57 -57
- package/src/assets/svg/rotation_cw.svg +49 -49
- package/src/assets/svg/rotation_cw_a.svg +30 -30
- package/src/assets/svg/rotation_cw_b.svg +30 -30
- package/src/assets/svg/rotation_cw_c.svg +30 -30
- package/src/assets/svg/speed.svg +39 -39
- package/src/components/AutoCoreDevPanel.tsx +414 -414
- package/src/components/BlocklyEditor.css +93 -93
- package/src/components/BlocklyEditor.tsx +609 -609
- package/src/components/CodeEditor.tsx +155 -155
- package/src/components/FileList.tsx +390 -390
- package/src/components/FileSelect.tsx +128 -128
- package/src/components/FitText.tsx +35 -35
- package/src/components/Indicator.tsx +188 -188
- package/src/components/IndicatorButton.tsx +214 -214
- package/src/components/IndicatorRect.tsx +172 -172
- package/src/components/JogPanel.css +41 -41
- package/src/components/JogPanel.tsx +461 -461
- package/src/components/Lamp.tsx +243 -243
- package/src/components/Osk.tsx +192 -192
- package/src/components/OskDialog.tsx +164 -164
- package/src/components/ProgressBarWithValue.css +27 -27
- package/src/components/ProgressBarWithValue.tsx +48 -48
- package/src/components/TextInput.tsx +195 -195
- package/src/components/ToggleGroup.tsx +322 -322
- package/src/components/ValueDisplay.tsx +236 -236
- package/src/components/ValueIndicator.css +31 -31
- package/src/components/ValueIndicator.tsx +135 -135
- package/src/components/ValueInput.tsx +368 -368
- package/src/components/osk.css +123 -123
- package/src/core/ActionMode.ts +19 -19
- package/src/core/AutoCoreTagContext.tsx +625 -614
- package/src/core/AutoCoreTagTypes.ts +334 -334
- package/src/core/CoreStreamTypes.ts +512 -512
- package/src/core/EventEmitterContext.tsx +434 -434
- package/src/core/IndicatorButtonState.ts +34 -34
- package/src/core/IndicatorColor.ts +35 -35
- package/src/core/MaskPatterns.ts +87 -87
- package/src/core/NumerableTypes.ts +80 -80
- package/src/core/PositionContext.ts +59 -59
- package/src/core/UniqueId.ts +41 -41
- package/src/core/ValueSimulator.ts +166 -166
- package/src/core/hoc.tsx +65 -65
- package/src/hooks/adsHooks.tsx +287 -287
- package/src/hooks/commandHooks.tsx +300 -300
- package/src/hooks/index.ts +12 -12
- package/src/hooks/useAutoCoreTag.ts +103 -103
- package/src/hooks/useScaledValue.tsx +99 -99
- package/src/hub/CommandMessage.ts +89 -89
- package/src/hub/DebugPanel.ts +307 -307
- package/src/hub/HubBase.ts +249 -236
- package/src/hub/HubSimulate.ts +124 -124
- package/src/hub/HubTauri.ts +140 -140
- package/src/hub/HubWebSocket.ts +250 -250
- package/src/hub/debug.ts +211 -211
- package/src/hub/index.ts +81 -81
- package/src/themes/adc-dark/_extensions.scss +166 -166
- package/src/themes/adc-dark/_variables.scss +913 -913
- package/src/themes/adc-dark/blue/_fonts.scss +23 -23
- package/src/themes/adc-dark/blue/adc_theme.scss +31 -31
- package/src/themes/adc-dark/blue/theme.scss +14 -14
- package/src/themes/theme-base/_colors.scss +17 -17
- package/src/themes/theme-base/_common.scss +74 -74
- package/src/themes/theme-base/_components.scss +111 -111
- package/src/themes/theme-base/_mixins.scss +243 -243
- package/src/themes/theme-base/components/button/_button.scss +644 -644
- package/src/themes/theme-base/components/button/_speeddial.scss +91 -91
- package/src/themes/theme-base/components/button/_splitbutton.scss +358 -358
- package/src/themes/theme-base/components/data/_carousel.scss +39 -39
- package/src/themes/theme-base/components/data/_datascroller.scss +47 -47
- package/src/themes/theme-base/components/data/_datatable.scss +388 -388
- package/src/themes/theme-base/components/data/_dataview.scss +47 -47
- package/src/themes/theme-base/components/data/_filter.scss +137 -137
- package/src/themes/theme-base/components/data/_orderlist.scss +86 -86
- package/src/themes/theme-base/components/data/_organizationchart.scss +50 -50
- package/src/themes/theme-base/components/data/_paginator.scss +91 -91
- package/src/themes/theme-base/components/data/_picklist.scss +73 -73
- package/src/themes/theme-base/components/data/_timeline.scss +38 -38
- package/src/themes/theme-base/components/data/_tree.scss +184 -184
- package/src/themes/theme-base/components/data/_treetable.scss +431 -431
- package/src/themes/theme-base/components/file/_fileupload.scss +41 -41
- package/src/themes/theme-base/components/input/_autocomplete.scss +94 -94
- package/src/themes/theme-base/components/input/_calendar.scss +251 -251
- package/src/themes/theme-base/components/input/_cascadeselect.scss +107 -107
- package/src/themes/theme-base/components/input/_checkbox.scss +181 -181
- package/src/themes/theme-base/components/input/_chips.scss +102 -102
- package/src/themes/theme-base/components/input/_colorpicker.scss +17 -17
- package/src/themes/theme-base/components/input/_dropdown.scss +252 -252
- package/src/themes/theme-base/components/input/_editor.scss +122 -122
- package/src/themes/theme-base/components/input/_iconfield.scss +9 -9
- package/src/themes/theme-base/components/input/_inputgroup.scss +74 -74
- package/src/themes/theme-base/components/input/_inputicon.scss +14 -14
- package/src/themes/theme-base/components/input/_inputnumber.scss +4 -4
- package/src/themes/theme-base/components/input/_inputotp.scss +10 -10
- package/src/themes/theme-base/components/input/_inputswitch.scss +99 -99
- package/src/themes/theme-base/components/input/_inputtext.scss +101 -101
- package/src/themes/theme-base/components/input/_listbox.scss +138 -138
- package/src/themes/theme-base/components/input/_mention.scss +30 -30
- package/src/themes/theme-base/components/input/_multiselect.scss +278 -278
- package/src/themes/theme-base/components/input/_password.scss +32 -32
- package/src/themes/theme-base/components/input/_radiobutton.scss +169 -169
- package/src/themes/theme-base/components/input/_rating.scss +80 -80
- package/src/themes/theme-base/components/input/_selectbutton.scss +49 -49
- package/src/themes/theme-base/components/input/_slider.scss +49 -49
- package/src/themes/theme-base/components/input/_togglebutton.scss +99 -99
- package/src/themes/theme-base/components/input/_treeselect.scss +151 -151
- package/src/themes/theme-base/components/input/_tristatecheckbox.scss +46 -46
- package/src/themes/theme-base/components/menu/_breadcrumb.scss +42 -42
- package/src/themes/theme-base/components/menu/_contextmenu.scss +39 -39
- package/src/themes/theme-base/components/menu/_dock.scss +109 -109
- package/src/themes/theme-base/components/menu/_megamenu.scss +141 -141
- package/src/themes/theme-base/components/menu/_menu.scss +33 -33
- package/src/themes/theme-base/components/menu/_menubar.scss +216 -216
- package/src/themes/theme-base/components/menu/_panelmenu.scss +153 -153
- package/src/themes/theme-base/components/menu/_slidemenu.scss +60 -60
- package/src/themes/theme-base/components/menu/_steps.scss +57 -57
- package/src/themes/theme-base/components/menu/_tabmenu.scss +50 -50
- package/src/themes/theme-base/components/menu/_tieredmenu.scss +43 -43
- package/src/themes/theme-base/components/messages/_inlinemessage.scss +69 -69
- package/src/themes/theme-base/components/messages/_message.scss +107 -107
- package/src/themes/theme-base/components/messages/_toast.scss +100 -100
- package/src/themes/theme-base/components/misc/_avatar.scss +33 -33
- package/src/themes/theme-base/components/misc/_badge.scss +76 -76
- package/src/themes/theme-base/components/misc/_chip.scss +38 -38
- package/src/themes/theme-base/components/misc/_inplace.scss +17 -17
- package/src/themes/theme-base/components/misc/_metergroup.scss +80 -80
- package/src/themes/theme-base/components/misc/_progressbar.scss +17 -17
- package/src/themes/theme-base/components/misc/_scrolltop.scss +24 -24
- package/src/themes/theme-base/components/misc/_skeleton.scss +7 -7
- package/src/themes/theme-base/components/misc/_tag.scss +39 -39
- package/src/themes/theme-base/components/misc/_terminal.scss +12 -12
- package/src/themes/theme-base/components/multimedia/_galleria.scss +153 -153
- package/src/themes/theme-base/components/multimedia/_image.scss +53 -53
- package/src/themes/theme-base/components/overlay/_confirmpopup.scss +72 -72
- package/src/themes/theme-base/components/overlay/_dialog.scss +78 -78
- package/src/themes/theme-base/components/overlay/_overlaypanel.scss +64 -64
- package/src/themes/theme-base/components/overlay/_sidebar.scss +23 -23
- package/src/themes/theme-base/components/overlay/_tooltip.scss +33 -33
- package/src/themes/theme-base/components/panel/_accordion.scss +118 -118
- package/src/themes/theme-base/components/panel/_card.scss +30 -30
- package/src/themes/theme-base/components/panel/_divider.scss +30 -30
- package/src/themes/theme-base/components/panel/_fieldset.scss +47 -47
- package/src/themes/theme-base/components/panel/_panel.scss +47 -47
- package/src/themes/theme-base/components/panel/_scrollpanel.scss +10 -10
- package/src/themes/theme-base/components/panel/_splitter.scss +23 -23
- package/src/themes/theme-base/components/panel/_stepper.scss +136 -136
- package/src/themes/theme-base/components/panel/_tabview.scss +147 -147
- package/src/themes/theme-base/components/panel/_toolbar.scss +11 -11
- package/terser.config.cjs +25 -25
- package/todo.md +18 -18
- package/tools/build-themes.cjs +65 -65
- package/tools/copy-distribution-files.cjs +77 -77
- package/tools/minify.cjs +55 -55
- package/tsconfig.json +48 -48
- package/typedoc.json +12 -12
- package/.claude/settings.local.json +0 -7
|
@@ -1,236 +1,236 @@
|
|
|
1
|
-
/*
|
|
2
|
-
* Copyright (C) 2024 Automated Design Corp. All Rights Reserved.
|
|
3
|
-
* Created Date: 2024-01-16 14:17:02
|
|
4
|
-
* -----
|
|
5
|
-
* Last Modified: 2025-09-05 14:51:23
|
|
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, type EventEmitterContextType } from '../core/EventEmitterContext';
|
|
18
|
-
|
|
19
|
-
import type { 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 designed to display a value which can be a string, number, or null.
|
|
88
|
-
* It supports formatting numeric values using the `numerableFormat` function, and is capable of dynamic positioning
|
|
89
|
-
* and sizing within its parent container. The component integrates with an `EventEmitterContext` to listen for
|
|
90
|
-
* updates to its value based on a specified topic, making it ideal for real-time data display scenarios.
|
|
91
|
-
*
|
|
92
|
-
* The component can be absolutely positioned based on `x` and `y` props, and its size can be adjusted using
|
|
93
|
-
* `width` and `height` props. If `useAbsolutePositioning` is true, it will position itself based on the provided
|
|
94
|
-
* coordinates; otherwise, it will position relatively.
|
|
95
|
-
*
|
|
96
|
-
* ### Props:
|
|
97
|
-
* - `value`: The initial value to display, which can be updated via props or context events.
|
|
98
|
-
* - `x`, `y`: Coordinates for absolute positioning within the parent container.
|
|
99
|
-
* - `width`, `height`: Dimensions of the component. If height is not provided, it defaults to the width.
|
|
100
|
-
* - `format`: A string specifying the format for numeric values (see numerable.js documentation for format strings).
|
|
101
|
-
* - `formatOptions`: Additional formatting options as per numerable.js.
|
|
102
|
-
* - `className`: Custom class for CSS styling.
|
|
103
|
-
* - `useAbsolutePositioning`: Boolean to toggle absolute positioning.
|
|
104
|
-
* - `topic`: Optional string to subscribe to context updates for dynamic value changes.
|
|
105
|
-
*
|
|
106
|
-
* ### Usage Example:
|
|
107
|
-
* ```tsx
|
|
108
|
-
* import React from 'react';
|
|
109
|
-
* import ReactDOM from 'react-dom';
|
|
110
|
-
* import { ValueDisplay } from './components/ValueDisplay';
|
|
111
|
-
*
|
|
112
|
-
* const App = () => {
|
|
113
|
-
* return (
|
|
114
|
-
* <div>
|
|
115
|
-
* <ValueDisplay
|
|
116
|
-
* value={1234.56}
|
|
117
|
-
* x={100}
|
|
118
|
-
* y={200}
|
|
119
|
-
* width={150}
|
|
120
|
-
* height={50}
|
|
121
|
-
* format="0,0.00"
|
|
122
|
-
* className="numeric-display"
|
|
123
|
-
* useAbsolutePositioning={true}
|
|
124
|
-
* topic="priceUpdate"
|
|
125
|
-
* />
|
|
126
|
-
* </div>
|
|
127
|
-
* );
|
|
128
|
-
* };
|
|
129
|
-
*
|
|
130
|
-
* ReactDOM.render(<App />, document.getElementById('root'));
|
|
131
|
-
* ```
|
|
132
|
-
*
|
|
133
|
-
* In this example, `ValueDisplay` is used to show a numeric value formatted as a string with two decimal places.
|
|
134
|
-
* It is positioned absolutely at coordinates (100, 200) with a specified width and height. The component listens
|
|
135
|
-
* for updates on the "priceUpdate" topic to dynamically update its displayed value.
|
|
136
|
-
*/
|
|
137
|
-
class ValueDisplay extends Component<Props, State> {
|
|
138
|
-
|
|
139
|
-
/** Defines the context type to subscribe to changes using EventEmitter. */
|
|
140
|
-
static contextType = EventEmitterContext;
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
/** ID for the subscription to the topic, used to unsubscribe on component unmount. */
|
|
144
|
-
protected unsubscribeTopicId: number | null = null;
|
|
145
|
-
|
|
146
|
-
/**
|
|
147
|
-
* The constructor initializes the component state and binds the initial value.
|
|
148
|
-
* @param props The properties passed to the component, including initial value and other display options.
|
|
149
|
-
*/
|
|
150
|
-
constructor(props: Props) {
|
|
151
|
-
super(props);
|
|
152
|
-
this.state = {
|
|
153
|
-
subscribedValue: props.value,
|
|
154
|
-
fontSize: '100%' // Initial font size, adjust as needed
|
|
155
|
-
};
|
|
156
|
-
}
|
|
157
|
-
|
|
158
|
-
/**
|
|
159
|
-
* Upon mounting, the component subscribes to updates on the specified topic if it exists,
|
|
160
|
-
* updating its state with the new value when the topic publishes updates.
|
|
161
|
-
*/
|
|
162
|
-
componentDidMount() {
|
|
163
|
-
const { topic } = this.props;
|
|
164
|
-
if (topic) {
|
|
165
|
-
const { subscribe } = this.context as EventEmitterContextType;
|
|
166
|
-
this.unsubscribeTopicId = subscribe(topic, (value: any) => {
|
|
167
|
-
this.setState({ subscribedValue: value });
|
|
168
|
-
});
|
|
169
|
-
}
|
|
170
|
-
}
|
|
171
|
-
|
|
172
|
-
/**
|
|
173
|
-
* If the value prop changes, the component updates its state with the new value.
|
|
174
|
-
* This ensures that the component remains in sync with its props.
|
|
175
|
-
* @param prevProps The previous properties for comparison to detect changes.
|
|
176
|
-
*/
|
|
177
|
-
componentDidUpdate(prevProps: Props) {
|
|
178
|
-
// Check if the value prop has changed
|
|
179
|
-
if (this.props.value !== prevProps.value) {
|
|
180
|
-
// Update the state with the new value
|
|
181
|
-
this.setState({ subscribedValue: this.props.value });
|
|
182
|
-
}
|
|
183
|
-
}
|
|
184
|
-
|
|
185
|
-
/**
|
|
186
|
-
* Before the component is unmounted, it unsubscribes from the topic to prevent memory leaks
|
|
187
|
-
* and unnecessary updates from occurring.
|
|
188
|
-
*/
|
|
189
|
-
componentWillUnmount() {
|
|
190
|
-
if (this.unsubscribeTopicId) {
|
|
191
|
-
const { unsubscribe } = this.context as EventEmitterContextType;
|
|
192
|
-
unsubscribe(this.unsubscribeTopicId);
|
|
193
|
-
}
|
|
194
|
-
}
|
|
195
|
-
|
|
196
|
-
/**
|
|
197
|
-
* Renders the component with styling and formatting based on the provided properties and state.
|
|
198
|
-
* Supports absolute or relative positioning and scales the display based on the context's dimensions.
|
|
199
|
-
* @returns A styled `div` element displaying the formatted value.
|
|
200
|
-
*/
|
|
201
|
-
render() {
|
|
202
|
-
const { x, y, width, height, format, formatOptions, className, useAbsolutePositioning } = this.props;
|
|
203
|
-
const { subscribedValue, fontSize } = this.state;
|
|
204
|
-
const { scale, xOffset, yOffset } = this.context as IPositionContext;
|
|
205
|
-
|
|
206
|
-
const style: React.CSSProperties = {
|
|
207
|
-
position: useAbsolutePositioning ? 'absolute' : 'relative',
|
|
208
|
-
display: useAbsolutePositioning ? "" : "inline-block",
|
|
209
|
-
verticalAlign: 'middle',
|
|
210
|
-
fontSize: fontSize && scale > 1 ? `${scale * 100}%` : fontSize,
|
|
211
|
-
top: useAbsolutePositioning && y ? `${yOffset + scale * y}px` : undefined,
|
|
212
|
-
left: useAbsolutePositioning && x ? `${xOffset + scale * x}px` : undefined,
|
|
213
|
-
width: width ? `${width * scale}px` : undefined,
|
|
214
|
-
height: height ? `${height * scale}px` : undefined,
|
|
215
|
-
lineHeight: height ? `${height * scale}px` : undefined,
|
|
216
|
-
whiteSpace: 'nowrap',
|
|
217
|
-
};
|
|
218
|
-
|
|
219
|
-
// Determine how to display the value
|
|
220
|
-
let displayValue;
|
|
221
|
-
if (typeof subscribedValue === 'number' || (typeof subscribedValue === 'string' && !isNaN(Number(subscribedValue)))) {
|
|
222
|
-
displayValue = numerableFormat(subscribedValue, format, formatOptions);
|
|
223
|
-
} else {
|
|
224
|
-
displayValue = subscribedValue; // Directly use the string if it's not numeric
|
|
225
|
-
}
|
|
226
|
-
|
|
227
|
-
return (
|
|
228
|
-
<div className={clsx(className)} style={style}>
|
|
229
|
-
{displayValue}
|
|
230
|
-
</div>
|
|
231
|
-
);
|
|
232
|
-
}
|
|
233
|
-
|
|
234
|
-
}
|
|
235
|
-
|
|
236
|
-
export { ValueDisplay, type NumerableFormatOptions };
|
|
1
|
+
/*
|
|
2
|
+
* Copyright (C) 2024 Automated Design Corp. All Rights Reserved.
|
|
3
|
+
* Created Date: 2024-01-16 14:17:02
|
|
4
|
+
* -----
|
|
5
|
+
* Last Modified: 2025-09-05 14:51:23
|
|
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, type EventEmitterContextType } from '../core/EventEmitterContext';
|
|
18
|
+
|
|
19
|
+
import type { 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 designed to display a value which can be a string, number, or null.
|
|
88
|
+
* It supports formatting numeric values using the `numerableFormat` function, and is capable of dynamic positioning
|
|
89
|
+
* and sizing within its parent container. The component integrates with an `EventEmitterContext` to listen for
|
|
90
|
+
* updates to its value based on a specified topic, making it ideal for real-time data display scenarios.
|
|
91
|
+
*
|
|
92
|
+
* The component can be absolutely positioned based on `x` and `y` props, and its size can be adjusted using
|
|
93
|
+
* `width` and `height` props. If `useAbsolutePositioning` is true, it will position itself based on the provided
|
|
94
|
+
* coordinates; otherwise, it will position relatively.
|
|
95
|
+
*
|
|
96
|
+
* ### Props:
|
|
97
|
+
* - `value`: The initial value to display, which can be updated via props or context events.
|
|
98
|
+
* - `x`, `y`: Coordinates for absolute positioning within the parent container.
|
|
99
|
+
* - `width`, `height`: Dimensions of the component. If height is not provided, it defaults to the width.
|
|
100
|
+
* - `format`: A string specifying the format for numeric values (see numerable.js documentation for format strings).
|
|
101
|
+
* - `formatOptions`: Additional formatting options as per numerable.js.
|
|
102
|
+
* - `className`: Custom class for CSS styling.
|
|
103
|
+
* - `useAbsolutePositioning`: Boolean to toggle absolute positioning.
|
|
104
|
+
* - `topic`: Optional string to subscribe to context updates for dynamic value changes.
|
|
105
|
+
*
|
|
106
|
+
* ### Usage Example:
|
|
107
|
+
* ```tsx
|
|
108
|
+
* import React from 'react';
|
|
109
|
+
* import ReactDOM from 'react-dom';
|
|
110
|
+
* import { ValueDisplay } from './components/ValueDisplay';
|
|
111
|
+
*
|
|
112
|
+
* const App = () => {
|
|
113
|
+
* return (
|
|
114
|
+
* <div>
|
|
115
|
+
* <ValueDisplay
|
|
116
|
+
* value={1234.56}
|
|
117
|
+
* x={100}
|
|
118
|
+
* y={200}
|
|
119
|
+
* width={150}
|
|
120
|
+
* height={50}
|
|
121
|
+
* format="0,0.00"
|
|
122
|
+
* className="numeric-display"
|
|
123
|
+
* useAbsolutePositioning={true}
|
|
124
|
+
* topic="priceUpdate"
|
|
125
|
+
* />
|
|
126
|
+
* </div>
|
|
127
|
+
* );
|
|
128
|
+
* };
|
|
129
|
+
*
|
|
130
|
+
* ReactDOM.render(<App />, document.getElementById('root'));
|
|
131
|
+
* ```
|
|
132
|
+
*
|
|
133
|
+
* In this example, `ValueDisplay` is used to show a numeric value formatted as a string with two decimal places.
|
|
134
|
+
* It is positioned absolutely at coordinates (100, 200) with a specified width and height. The component listens
|
|
135
|
+
* for updates on the "priceUpdate" topic to dynamically update its displayed value.
|
|
136
|
+
*/
|
|
137
|
+
class ValueDisplay extends Component<Props, State> {
|
|
138
|
+
|
|
139
|
+
/** Defines the context type to subscribe to changes using EventEmitter. */
|
|
140
|
+
static contextType = EventEmitterContext;
|
|
141
|
+
|
|
142
|
+
|
|
143
|
+
/** ID for the subscription to the topic, used to unsubscribe on component unmount. */
|
|
144
|
+
protected unsubscribeTopicId: number | null = null;
|
|
145
|
+
|
|
146
|
+
/**
|
|
147
|
+
* The constructor initializes the component state and binds the initial value.
|
|
148
|
+
* @param props The properties passed to the component, including initial value and other display options.
|
|
149
|
+
*/
|
|
150
|
+
constructor(props: Props) {
|
|
151
|
+
super(props);
|
|
152
|
+
this.state = {
|
|
153
|
+
subscribedValue: props.value,
|
|
154
|
+
fontSize: '100%' // Initial font size, adjust as needed
|
|
155
|
+
};
|
|
156
|
+
}
|
|
157
|
+
|
|
158
|
+
/**
|
|
159
|
+
* Upon mounting, the component subscribes to updates on the specified topic if it exists,
|
|
160
|
+
* updating its state with the new value when the topic publishes updates.
|
|
161
|
+
*/
|
|
162
|
+
componentDidMount() {
|
|
163
|
+
const { topic } = this.props;
|
|
164
|
+
if (topic) {
|
|
165
|
+
const { subscribe } = this.context as EventEmitterContextType;
|
|
166
|
+
this.unsubscribeTopicId = subscribe(topic, (value: any) => {
|
|
167
|
+
this.setState({ subscribedValue: value });
|
|
168
|
+
});
|
|
169
|
+
}
|
|
170
|
+
}
|
|
171
|
+
|
|
172
|
+
/**
|
|
173
|
+
* If the value prop changes, the component updates its state with the new value.
|
|
174
|
+
* This ensures that the component remains in sync with its props.
|
|
175
|
+
* @param prevProps The previous properties for comparison to detect changes.
|
|
176
|
+
*/
|
|
177
|
+
componentDidUpdate(prevProps: Props) {
|
|
178
|
+
// Check if the value prop has changed
|
|
179
|
+
if (this.props.value !== prevProps.value) {
|
|
180
|
+
// Update the state with the new value
|
|
181
|
+
this.setState({ subscribedValue: this.props.value });
|
|
182
|
+
}
|
|
183
|
+
}
|
|
184
|
+
|
|
185
|
+
/**
|
|
186
|
+
* Before the component is unmounted, it unsubscribes from the topic to prevent memory leaks
|
|
187
|
+
* and unnecessary updates from occurring.
|
|
188
|
+
*/
|
|
189
|
+
componentWillUnmount() {
|
|
190
|
+
if (this.unsubscribeTopicId) {
|
|
191
|
+
const { unsubscribe } = this.context as EventEmitterContextType;
|
|
192
|
+
unsubscribe(this.unsubscribeTopicId);
|
|
193
|
+
}
|
|
194
|
+
}
|
|
195
|
+
|
|
196
|
+
/**
|
|
197
|
+
* Renders the component with styling and formatting based on the provided properties and state.
|
|
198
|
+
* Supports absolute or relative positioning and scales the display based on the context's dimensions.
|
|
199
|
+
* @returns A styled `div` element displaying the formatted value.
|
|
200
|
+
*/
|
|
201
|
+
render() {
|
|
202
|
+
const { x, y, width, height, format, formatOptions, className, useAbsolutePositioning } = this.props;
|
|
203
|
+
const { subscribedValue, fontSize } = this.state;
|
|
204
|
+
const { scale, xOffset, yOffset } = this.context as IPositionContext;
|
|
205
|
+
|
|
206
|
+
const style: React.CSSProperties = {
|
|
207
|
+
position: useAbsolutePositioning ? 'absolute' : 'relative',
|
|
208
|
+
display: useAbsolutePositioning ? "" : "inline-block",
|
|
209
|
+
verticalAlign: 'middle',
|
|
210
|
+
fontSize: fontSize && scale > 1 ? `${scale * 100}%` : fontSize,
|
|
211
|
+
top: useAbsolutePositioning && y ? `${yOffset + scale * y}px` : undefined,
|
|
212
|
+
left: useAbsolutePositioning && x ? `${xOffset + scale * x}px` : undefined,
|
|
213
|
+
width: width ? `${width * scale}px` : undefined,
|
|
214
|
+
height: height ? `${height * scale}px` : undefined,
|
|
215
|
+
lineHeight: height ? `${height * scale}px` : undefined,
|
|
216
|
+
whiteSpace: 'nowrap',
|
|
217
|
+
};
|
|
218
|
+
|
|
219
|
+
// Determine how to display the value
|
|
220
|
+
let displayValue;
|
|
221
|
+
if (typeof subscribedValue === 'number' || (typeof subscribedValue === 'string' && !isNaN(Number(subscribedValue)))) {
|
|
222
|
+
displayValue = numerableFormat(subscribedValue, format, formatOptions);
|
|
223
|
+
} else {
|
|
224
|
+
displayValue = subscribedValue; // Directly use the string if it's not numeric
|
|
225
|
+
}
|
|
226
|
+
|
|
227
|
+
return (
|
|
228
|
+
<div className={clsx(className)} style={style}>
|
|
229
|
+
{displayValue}
|
|
230
|
+
</div>
|
|
231
|
+
);
|
|
232
|
+
}
|
|
233
|
+
|
|
234
|
+
}
|
|
235
|
+
|
|
236
|
+
export { ValueDisplay, type NumerableFormatOptions };
|
|
@@ -1,32 +1,32 @@
|
|
|
1
|
-
/*
|
|
2
|
-
* Copyright (C) 2024 Automated Design Corp.. All Rights Reserved.
|
|
3
|
-
* Created Date: 2024-03-22 06:26:45
|
|
4
|
-
* -----
|
|
5
|
-
* Last Modified: 2024-03-22 07:07:50
|
|
6
|
-
* -----
|
|
7
|
-
*
|
|
8
|
-
*/
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
.value-indicator-container {
|
|
13
|
-
|
|
14
|
-
display: flex;
|
|
15
|
-
flex-direction: column;
|
|
16
|
-
background-color: var(--surface-ground);
|
|
17
|
-
border-color: var(--surface-border);
|
|
18
|
-
border-radius: var(--border-radius);
|
|
19
|
-
border-width: 1px;
|
|
20
|
-
border-style: solid;
|
|
21
|
-
justify-content: center;
|
|
22
|
-
align-items: center;
|
|
23
|
-
padding: 2mm;
|
|
24
|
-
flex-grow: 1; /* Allow the item to grow to fill available space */
|
|
25
|
-
flex-shrink: 0; /* Allow the item to shrink if necessary */
|
|
26
|
-
flex-basis: 0; /* Start with 0 width and then grow as needed, equal distribution */
|
|
27
|
-
min-width: 0; /* Prevents flex items from overflowing their container */
|
|
28
|
-
}
|
|
29
|
-
|
|
30
|
-
.value-indicator-label {
|
|
31
|
-
padding-bottom: 1mm;
|
|
1
|
+
/*
|
|
2
|
+
* Copyright (C) 2024 Automated Design Corp.. All Rights Reserved.
|
|
3
|
+
* Created Date: 2024-03-22 06:26:45
|
|
4
|
+
* -----
|
|
5
|
+
* Last Modified: 2024-03-22 07:07:50
|
|
6
|
+
* -----
|
|
7
|
+
*
|
|
8
|
+
*/
|
|
9
|
+
|
|
10
|
+
|
|
11
|
+
|
|
12
|
+
.value-indicator-container {
|
|
13
|
+
|
|
14
|
+
display: flex;
|
|
15
|
+
flex-direction: column;
|
|
16
|
+
background-color: var(--surface-ground);
|
|
17
|
+
border-color: var(--surface-border);
|
|
18
|
+
border-radius: var(--border-radius);
|
|
19
|
+
border-width: 1px;
|
|
20
|
+
border-style: solid;
|
|
21
|
+
justify-content: center;
|
|
22
|
+
align-items: center;
|
|
23
|
+
padding: 2mm;
|
|
24
|
+
flex-grow: 1; /* Allow the item to grow to fill available space */
|
|
25
|
+
flex-shrink: 0; /* Allow the item to shrink if necessary */
|
|
26
|
+
flex-basis: 0; /* Start with 0 width and then grow as needed, equal distribution */
|
|
27
|
+
min-width: 0; /* Prevents flex items from overflowing their container */
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
.value-indicator-label {
|
|
31
|
+
padding-bottom: 1mm;
|
|
32
32
|
}
|