@adcops/autocore-react 3.3.9 → 3.3.14

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.
Files changed (223) hide show
  1. package/LICENSE +58 -58
  2. package/additional-docs/AutoCoreTagContext.md +441 -441
  3. package/additional-docs/ButtonApiSpecs.md +48 -48
  4. package/additional-docs/GlobalEventEmitter.md +243 -243
  5. package/additional-docs/general_recommendations.md +22 -22
  6. package/additional-docs/react_performance_notes.md +94 -94
  7. package/dist/assets/svg/blockly_logo.svg +82 -82
  8. package/dist/assets/svg/distance.svg +40 -40
  9. package/dist/assets/svg/python_logo.svg +246 -246
  10. package/dist/assets/svg/rotation_ccw.svg +50 -50
  11. package/dist/assets/svg/rotation_ccw_a.svg +57 -57
  12. package/dist/assets/svg/rotation_ccw_b.svg +57 -57
  13. package/dist/assets/svg/rotation_ccw_c.svg +57 -57
  14. package/dist/assets/svg/rotation_cw.svg +49 -49
  15. package/dist/assets/svg/rotation_cw_a.svg +30 -30
  16. package/dist/assets/svg/rotation_cw_b.svg +30 -30
  17. package/dist/assets/svg/rotation_cw_c.svg +30 -30
  18. package/dist/assets/svg/speed.svg +39 -39
  19. package/dist/components/BlocklyEditor.css +93 -93
  20. package/dist/components/Indicator.js +1 -1
  21. package/dist/components/IndicatorRect.d.ts.map +1 -1
  22. package/dist/components/IndicatorRect.js +1 -1
  23. package/dist/components/JogPanel.css +41 -41
  24. package/dist/components/ProgressBarWithValue.css +27 -27
  25. package/dist/components/TextInput.js +1 -1
  26. package/dist/components/ToggleGroup.js +1 -1
  27. package/dist/components/ValueIndicator.css +29 -31
  28. package/dist/components/ValueInput.js +1 -1
  29. package/dist/components/osk.css +123 -123
  30. package/dist/core/AutoCoreTagContext.d.ts.map +1 -1
  31. package/dist/core/AutoCoreTagContext.js +1 -1
  32. package/dist/hub/HubBase.d.ts +3 -3
  33. package/dist/hub/HubBase.d.ts.map +1 -1
  34. package/dist/hub/HubBase.js +1 -1
  35. package/dist/themes/adc-dark/blue/theme.css +3 -0
  36. package/dist/themes/adc-dark/blue/theme.css.map +1 -1
  37. package/package.json +104 -104
  38. package/readme.md +343 -343
  39. package/src/assets/BlocklyLogo.tsx +27 -27
  40. package/src/assets/Distance.tsx +18 -18
  41. package/src/assets/JogLong.tsx +13 -13
  42. package/src/assets/JogMedium.tsx +13 -13
  43. package/src/assets/JogShort.tsx +13 -13
  44. package/src/assets/PythonLogo.tsx +83 -83
  45. package/src/assets/Rotation3D.tsx +13 -13
  46. package/src/assets/RotationCcw.tsx +33 -33
  47. package/src/assets/RotationCcwA.tsx +45 -45
  48. package/src/assets/RotationCcwB.tsx +45 -45
  49. package/src/assets/RotationCcwC.tsx +45 -45
  50. package/src/assets/RotationCw.tsx +31 -31
  51. package/src/assets/RotationCwA.tsx +42 -42
  52. package/src/assets/RotationCwB.tsx +42 -42
  53. package/src/assets/RotationCwC.tsx +42 -42
  54. package/src/assets/Run.tsx +13 -13
  55. package/src/assets/Speed.tsx +18 -18
  56. package/src/assets/SpeedFast.tsx +13 -13
  57. package/src/assets/SpeedMedium.tsx +13 -13
  58. package/src/assets/SpeedNone.tsx +13 -13
  59. package/src/assets/SpeedSlow.tsx +13 -13
  60. package/src/assets/Walk.tsx +13 -13
  61. package/src/assets/index.ts +22 -22
  62. package/src/assets/svg/blockly_logo.svg +82 -82
  63. package/src/assets/svg/distance.svg +40 -40
  64. package/src/assets/svg/python_logo.svg +246 -246
  65. package/src/assets/svg/rotation_ccw.svg +50 -50
  66. package/src/assets/svg/rotation_ccw_a.svg +57 -57
  67. package/src/assets/svg/rotation_ccw_b.svg +57 -57
  68. package/src/assets/svg/rotation_ccw_c.svg +57 -57
  69. package/src/assets/svg/rotation_cw.svg +49 -49
  70. package/src/assets/svg/rotation_cw_a.svg +30 -30
  71. package/src/assets/svg/rotation_cw_b.svg +30 -30
  72. package/src/assets/svg/rotation_cw_c.svg +30 -30
  73. package/src/assets/svg/speed.svg +39 -39
  74. package/src/components/AutoCoreDevPanel.tsx +414 -414
  75. package/src/components/BlocklyEditor.css +93 -93
  76. package/src/components/BlocklyEditor.tsx +609 -609
  77. package/src/components/CodeEditor.tsx +155 -155
  78. package/src/components/FileList.tsx +390 -390
  79. package/src/components/FileSelect.tsx +128 -128
  80. package/src/components/FitText.tsx +35 -35
  81. package/src/components/Indicator.tsx +188 -188
  82. package/src/components/IndicatorButton.tsx +214 -214
  83. package/src/components/IndicatorRect.tsx +170 -172
  84. package/src/components/JogPanel.css +41 -41
  85. package/src/components/JogPanel.tsx +461 -461
  86. package/src/components/Lamp.tsx +243 -243
  87. package/src/components/Osk.tsx +192 -192
  88. package/src/components/OskDialog.tsx +164 -164
  89. package/src/components/ProgressBarWithValue.css +27 -27
  90. package/src/components/ProgressBarWithValue.tsx +48 -48
  91. package/src/components/TextInput.tsx +195 -195
  92. package/src/components/ToggleGroup.tsx +322 -322
  93. package/src/components/ValueDisplay.tsx +236 -236
  94. package/src/components/ValueIndicator.css +29 -31
  95. package/src/components/ValueIndicator.tsx +135 -135
  96. package/src/components/ValueInput.tsx +368 -368
  97. package/src/components/osk.css +123 -123
  98. package/src/core/ActionMode.ts +19 -19
  99. package/src/core/AutoCoreTagContext.tsx +625 -614
  100. package/src/core/AutoCoreTagTypes.ts +334 -334
  101. package/src/core/CoreStreamTypes.ts +512 -512
  102. package/src/core/EventEmitterContext.tsx +434 -434
  103. package/src/core/IndicatorButtonState.ts +34 -34
  104. package/src/core/IndicatorColor.ts +35 -35
  105. package/src/core/MaskPatterns.ts +87 -87
  106. package/src/core/NumerableTypes.ts +80 -80
  107. package/src/core/PositionContext.ts +59 -59
  108. package/src/core/UniqueId.ts +41 -41
  109. package/src/core/ValueSimulator.ts +166 -166
  110. package/src/core/hoc.tsx +65 -65
  111. package/src/hooks/adsHooks.tsx +287 -287
  112. package/src/hooks/commandHooks.tsx +300 -300
  113. package/src/hooks/index.ts +12 -12
  114. package/src/hooks/useAutoCoreTag.ts +103 -103
  115. package/src/hooks/useScaledValue.tsx +99 -99
  116. package/src/hub/CommandMessage.ts +89 -89
  117. package/src/hub/DebugPanel.ts +307 -307
  118. package/src/hub/HubBase.ts +249 -236
  119. package/src/hub/HubSimulate.ts +124 -124
  120. package/src/hub/HubTauri.ts +140 -140
  121. package/src/hub/HubWebSocket.ts +250 -250
  122. package/src/hub/debug.ts +211 -211
  123. package/src/hub/index.ts +81 -81
  124. package/src/themes/adc-dark/_extensions.scss +166 -166
  125. package/src/themes/adc-dark/_variables.scss +913 -913
  126. package/src/themes/adc-dark/blue/_fonts.scss +23 -23
  127. package/src/themes/adc-dark/blue/adc_theme.scss +31 -31
  128. package/src/themes/adc-dark/blue/theme.scss +14 -14
  129. package/src/themes/theme-base/_colors.scss +17 -17
  130. package/src/themes/theme-base/_common.scss +78 -74
  131. package/src/themes/theme-base/_components.scss +111 -111
  132. package/src/themes/theme-base/_mixins.scss +243 -243
  133. package/src/themes/theme-base/components/button/_button.scss +644 -644
  134. package/src/themes/theme-base/components/button/_speeddial.scss +91 -91
  135. package/src/themes/theme-base/components/button/_splitbutton.scss +358 -358
  136. package/src/themes/theme-base/components/data/_carousel.scss +39 -39
  137. package/src/themes/theme-base/components/data/_datascroller.scss +47 -47
  138. package/src/themes/theme-base/components/data/_datatable.scss +388 -388
  139. package/src/themes/theme-base/components/data/_dataview.scss +47 -47
  140. package/src/themes/theme-base/components/data/_filter.scss +137 -137
  141. package/src/themes/theme-base/components/data/_orderlist.scss +86 -86
  142. package/src/themes/theme-base/components/data/_organizationchart.scss +50 -50
  143. package/src/themes/theme-base/components/data/_paginator.scss +91 -91
  144. package/src/themes/theme-base/components/data/_picklist.scss +73 -73
  145. package/src/themes/theme-base/components/data/_timeline.scss +38 -38
  146. package/src/themes/theme-base/components/data/_tree.scss +184 -184
  147. package/src/themes/theme-base/components/data/_treetable.scss +431 -431
  148. package/src/themes/theme-base/components/file/_fileupload.scss +41 -41
  149. package/src/themes/theme-base/components/input/_autocomplete.scss +94 -94
  150. package/src/themes/theme-base/components/input/_calendar.scss +251 -251
  151. package/src/themes/theme-base/components/input/_cascadeselect.scss +107 -107
  152. package/src/themes/theme-base/components/input/_checkbox.scss +181 -181
  153. package/src/themes/theme-base/components/input/_chips.scss +102 -102
  154. package/src/themes/theme-base/components/input/_colorpicker.scss +17 -17
  155. package/src/themes/theme-base/components/input/_dropdown.scss +252 -252
  156. package/src/themes/theme-base/components/input/_editor.scss +122 -122
  157. package/src/themes/theme-base/components/input/_iconfield.scss +9 -9
  158. package/src/themes/theme-base/components/input/_inputgroup.scss +74 -74
  159. package/src/themes/theme-base/components/input/_inputicon.scss +14 -14
  160. package/src/themes/theme-base/components/input/_inputnumber.scss +4 -4
  161. package/src/themes/theme-base/components/input/_inputotp.scss +10 -10
  162. package/src/themes/theme-base/components/input/_inputswitch.scss +99 -99
  163. package/src/themes/theme-base/components/input/_inputtext.scss +101 -101
  164. package/src/themes/theme-base/components/input/_listbox.scss +138 -138
  165. package/src/themes/theme-base/components/input/_mention.scss +30 -30
  166. package/src/themes/theme-base/components/input/_multiselect.scss +278 -278
  167. package/src/themes/theme-base/components/input/_password.scss +32 -32
  168. package/src/themes/theme-base/components/input/_radiobutton.scss +169 -169
  169. package/src/themes/theme-base/components/input/_rating.scss +80 -80
  170. package/src/themes/theme-base/components/input/_selectbutton.scss +49 -49
  171. package/src/themes/theme-base/components/input/_slider.scss +49 -49
  172. package/src/themes/theme-base/components/input/_togglebutton.scss +99 -99
  173. package/src/themes/theme-base/components/input/_treeselect.scss +151 -151
  174. package/src/themes/theme-base/components/input/_tristatecheckbox.scss +46 -46
  175. package/src/themes/theme-base/components/menu/_breadcrumb.scss +42 -42
  176. package/src/themes/theme-base/components/menu/_contextmenu.scss +39 -39
  177. package/src/themes/theme-base/components/menu/_dock.scss +109 -109
  178. package/src/themes/theme-base/components/menu/_megamenu.scss +141 -141
  179. package/src/themes/theme-base/components/menu/_menu.scss +33 -33
  180. package/src/themes/theme-base/components/menu/_menubar.scss +216 -216
  181. package/src/themes/theme-base/components/menu/_panelmenu.scss +153 -153
  182. package/src/themes/theme-base/components/menu/_slidemenu.scss +60 -60
  183. package/src/themes/theme-base/components/menu/_steps.scss +57 -57
  184. package/src/themes/theme-base/components/menu/_tabmenu.scss +50 -50
  185. package/src/themes/theme-base/components/menu/_tieredmenu.scss +43 -43
  186. package/src/themes/theme-base/components/messages/_inlinemessage.scss +69 -69
  187. package/src/themes/theme-base/components/messages/_message.scss +107 -107
  188. package/src/themes/theme-base/components/messages/_toast.scss +100 -100
  189. package/src/themes/theme-base/components/misc/_avatar.scss +33 -33
  190. package/src/themes/theme-base/components/misc/_badge.scss +76 -76
  191. package/src/themes/theme-base/components/misc/_chip.scss +38 -38
  192. package/src/themes/theme-base/components/misc/_inplace.scss +17 -17
  193. package/src/themes/theme-base/components/misc/_metergroup.scss +80 -80
  194. package/src/themes/theme-base/components/misc/_progressbar.scss +17 -17
  195. package/src/themes/theme-base/components/misc/_scrolltop.scss +24 -24
  196. package/src/themes/theme-base/components/misc/_skeleton.scss +7 -7
  197. package/src/themes/theme-base/components/misc/_tag.scss +39 -39
  198. package/src/themes/theme-base/components/misc/_terminal.scss +12 -12
  199. package/src/themes/theme-base/components/multimedia/_galleria.scss +153 -153
  200. package/src/themes/theme-base/components/multimedia/_image.scss +53 -53
  201. package/src/themes/theme-base/components/overlay/_confirmpopup.scss +72 -72
  202. package/src/themes/theme-base/components/overlay/_dialog.scss +78 -78
  203. package/src/themes/theme-base/components/overlay/_overlaypanel.scss +64 -64
  204. package/src/themes/theme-base/components/overlay/_sidebar.scss +23 -23
  205. package/src/themes/theme-base/components/overlay/_tooltip.scss +33 -33
  206. package/src/themes/theme-base/components/panel/_accordion.scss +118 -118
  207. package/src/themes/theme-base/components/panel/_card.scss +30 -30
  208. package/src/themes/theme-base/components/panel/_divider.scss +30 -30
  209. package/src/themes/theme-base/components/panel/_fieldset.scss +47 -47
  210. package/src/themes/theme-base/components/panel/_panel.scss +47 -47
  211. package/src/themes/theme-base/components/panel/_scrollpanel.scss +10 -10
  212. package/src/themes/theme-base/components/panel/_splitter.scss +23 -23
  213. package/src/themes/theme-base/components/panel/_stepper.scss +136 -136
  214. package/src/themes/theme-base/components/panel/_tabview.scss +147 -147
  215. package/src/themes/theme-base/components/panel/_toolbar.scss +11 -11
  216. package/terser.config.cjs +25 -25
  217. package/todo.md +18 -18
  218. package/tools/build-themes.cjs +65 -65
  219. package/tools/copy-distribution-files.cjs +77 -77
  220. package/tools/minify.cjs +55 -55
  221. package/tsconfig.json +48 -48
  222. package/typedoc.json +12 -12
  223. package/.claude/settings.local.json +0 -7
@@ -1,334 +1,334 @@
1
- /*
2
- * Copyright (C) 2025 Automated Design Corp.. All Rights Reserved.
3
- * Created Date: 2025-09-05 07:57:49
4
- * -----
5
- * Last Modified: 2026-01-29 09:31:54
6
- * -----
7
- *
8
- */
9
-
10
- /**
11
- * @module core/AutoCoreTagTypes
12
- *
13
- * Core type system for AutoCore's tag layer:
14
- * - Strongly-typed tag values (boolean/number/string/json)
15
- * - Optional **scales** for numeric unit conversion (e.g., mm ⇄ in)
16
- * - Optional **codecs** to present richer client-side types (Date/Map) while
17
- * keeping pure JSON across the wire (serde_json::Value on the server)
18
- */
19
-
20
- export type PrimitiveKind = "boolean" | "number" | "string" | "json";
21
-
22
- /** Strict JSON value (mirrors serde_json::Value) */
23
- type JsonPrimitive = string | number | boolean | null;
24
- export type JsonValue =
25
- | JsonPrimitive
26
- | { [key: string]: JsonValue }
27
- | JsonValue[];
28
-
29
- /**
30
- * Extended client-side value you *may* choose to present in the UI.
31
- * Use codecs to round-trip these as pure JSON to the server.
32
- */
33
- export type ExtendedJsonValue = JsonValue | Date | Map<string, JsonValue>;
34
-
35
- /**
36
- * Map a tag's declared primitive kind to the app-visible type.
37
- * - "json" becomes ExtendedJsonValue so UIs can work with Date/Map when desired.
38
- */
39
- export type TagValueOf<K extends PrimitiveKind> =
40
- K extends "boolean" ? boolean :
41
- K extends "number" ? number :
42
- K extends "string" ? string :
43
- ExtendedJsonValue;
44
-
45
- /**
46
- * Runtime binding for a single tag, as returned by hooks like `useAutoCoreTag`.
47
- * - `value` is app-visible (already scaled/decoded)
48
- * - `rawValue` is the last **unscaled, un-decoded** controller value received (server JSON)
49
- * - `write` expects app-visible value (provider will inverse-scale/encode)
50
- * - `tap` is typically for boolean momentaries (provider may pulse true→false)
51
- */
52
- export type TagBinding<T> = Readonly<{
53
- /** App-visible value (scaled/decoded). */
54
- value: T | undefined;
55
- /** Last raw value from the server (pre-scale, pre-codec). */
56
- rawValue: unknown | undefined;
57
- /** Write a new app-visible value (provider will inverse-scale/encode). */
58
- write: (displayValue: T) => Promise<void>;
59
- /** Momentary action; typically boolean true→false pulse. */
60
- tap: () => Promise<void>;
61
- /** True while initial read/bootstrapping is in progress. */
62
- isLoading: boolean;
63
- }>;
64
-
65
- /**
66
- * Options that control how subscription updates are delivered to the client.
67
- *
68
- * This implements the "hybrid" subscription model where:
69
- * - **Project configuration** defines limits and defaults (e.g., minimum sampling rate)
70
- * - **Client requests** can customize within those bounds
71
- *
72
- * ## Behavior
73
- *
74
- * - `undefined` values mean "use server default"
75
- * - Client requests are clamped to server limits (can't request faster than hardware supports)
76
- * - All filtering (deadband, on_change_only) is applied server-side before sending updates
77
- *
78
- * @example Basic rate limiting
79
- * ```typescript
80
- * {
81
- * tagName: "fastSensor",
82
- * domain: "MODBUS",
83
- * symbolName: "sensor.temperature",
84
- * valueType: "number",
85
- * subscriptionOptions: {
86
- * sampling_interval_ms: 500, // Limit to 2 updates/sec
87
- * on_change_only: true // Only send when value changes
88
- * }
89
- * }
90
- * ```
91
- *
92
- * @example Deadband filtering for noisy signals
93
- * ```typescript
94
- * {
95
- * tagName: "analogInput",
96
- * domain: "MODBUS",
97
- * symbolName: "ai.pressure",
98
- * valueType: "number",
99
- * subscriptionOptions: {
100
- * deadband_percent: 1.0 // Ignore changes < 1% of full scale
101
- * }
102
- * }
103
- * ```
104
- */
105
- export interface SubscriptionOptions {
106
- /**
107
- * Minimum interval between updates in milliseconds.
108
- *
109
- * The server will not send updates faster than this rate, even if the
110
- * underlying data changes more frequently. This helps prevent UI overload.
111
- *
112
- * - `undefined`: Use server default (typically from project configuration)
113
- * - If client requests faster than hardware polling rate, gets clamped to hardware rate
114
- *
115
- * @example `{ sampling_interval_ms: 100 }` - Max 10 updates/second
116
- */
117
- sampling_interval_ms?: number;
118
-
119
- /**
120
- * Only send updates when the value changes (vs periodic heartbeat).
121
- *
122
- * When `true`, the server only sends updates when the value differs from
123
- * the last sent value (after applying deadband filtering).
124
- *
125
- * When `false` or `undefined`, updates may be sent periodically even if unchanged.
126
- */
127
- on_change_only?: boolean;
128
-
129
- /**
130
- * Deadband as a percentage of full scale (0.0 to 100.0).
131
- *
132
- * Updates are suppressed unless the value changes by at least this
133
- * percentage of the full scale range. This reduces network traffic
134
- * for noisy signals.
135
- *
136
- * - `deadband_percent: 1.0` means ignore changes less than 1% of full scale
137
- * - Takes precedence over `deadband_absolute` if both are set
138
- *
139
- * @example `{ deadband_percent: 2.5 }` - Ignore changes < 2.5% of range
140
- */
141
- deadband_percent?: number;
142
-
143
- /**
144
- * Deadband as an absolute value change threshold.
145
- *
146
- * Updates are suppressed unless the value changes by at least this
147
- * absolute amount. Useful when you know the meaningful change threshold.
148
- *
149
- * - Only used if `deadband_percent` is not set
150
- *
151
- * @example `{ deadband_absolute: 5.0 }` - Ignore changes < 5 units
152
- */
153
- deadband_absolute?: number;
154
-
155
- /**
156
- * Queue size for buffering updates when the client is slow.
157
- *
158
- * If the client can't consume updates fast enough, this many updates
159
- * are queued before older ones are discarded.
160
- *
161
- * - `undefined`: Use server default (typically 1 - latest value only)
162
- * - Higher values useful for historical trending or burst handling
163
- */
164
- queue_size?: number;
165
-
166
-
167
- /**
168
- * Custom arguments specific for the specified domain.
169
- */
170
- args?: Record<string, unknown>;
171
- }
172
-
173
- /**
174
- * Configuration for a named scale group.
175
- * Apply by setting `scale: "<name>"` on numeric tags.
176
- */
177
- export interface ScaleConfig {
178
- /** Unique name for this scale group (e.g., "position", "load") */
179
- name: string;
180
- /** Current scale factor — incoming values ×= scale; outgoing values /= scale */
181
- scale: number;
182
- /** Units/label for display (e.g., "mm", "in", "lbs") */
183
- label: string;
184
- /** Optional description for debugging/documentation */
185
- description?: string;
186
- /**
187
- * Optional server tag that provides the scale dynamically.
188
- * (If used, your provider should subscribe and update `scale` when it changes.)
189
- */
190
- serverTag?: {
191
- domain: string;
192
- symbolName: string;
193
- };
194
- }
195
-
196
- /**
197
- * A codec lets a tag expose a richer client-side type while staying JSON on the wire.
198
- * Common examples:
199
- * - Date values: ISO string ⇄ Date
200
- * - Map-like blobs: object ⇄ Map<string, JsonValue>
201
- */
202
- export type TagCodec<TIn = unknown, TOut extends JsonValue = JsonValue> = {
203
- /** raw JSON (from server) → app-visible value */
204
- fromServer?: (raw: unknown) => TIn;
205
- /** app-visible value → pure JSON (to server) */
206
- toServer?: (value: TIn) => TOut;
207
- };
208
-
209
- /**
210
- * Tag configuration descriptor used to build a typed spec.
211
- *
212
- * @typeParam K - Literal tag name (use `as const` on your spec array)
213
- * @typeParam T - Primitive kind for type mapping (boolean/number/string/json)
214
- */
215
- export type TagConfig<
216
- K extends string = string,
217
- T extends PrimitiveKind = PrimitiveKind
218
- > = {
219
- /** Local key used by UI/consumers (unique within your spec) */
220
- tagName: K;
221
-
222
- /** Fully-Qualified Domain Name - the complete topic path.
223
- * Format: "domain.path.to.symbol" (e.g., "ads.plc1.gio.bControlPowerOk", "modbus.holding_registers.5")
224
- * The first segment is the domain, used for routing to the appropriate servelet.
225
- */
226
- fqdn: string;
227
-
228
- /** Declared primitive kind for typing and DevPanel rendering */
229
- valueType: T;
230
-
231
- /** Optional initial **raw** value before first server update */
232
- initialValue?: TagValueOf<T>;
233
-
234
-
235
- /**
236
- * Optional scale group for numeric tags.
237
- * If present, provider will:
238
- * - Multiply incoming numbers by the group's `scale`
239
- * - Divide outgoing numbers by the group's `scale`
240
- */
241
- scale?: string;
242
-
243
- /**
244
- * Optional codec to present richer UI types while keeping JSON on the wire.
245
- * Only commonly used with `valueType: "json"`.
246
- */
247
- codec?: TagCodec;
248
-
249
- /**
250
- * Optional subscription options to control how updates are delivered.
251
- *
252
- * These options implement the hybrid subscription model where you can
253
- * configure rate limiting, deadband filtering, and other delivery options
254
- * to prevent overwhelming the UI with high-frequency updates.
255
- *
256
- * @example Rate limit a fast-updating tag
257
- * ```typescript
258
- * {
259
- * tagName: "position",
260
- * subscriptionOptions: {
261
- * sampling_interval_ms: 100, // Max 10 updates/sec
262
- * on_change_only: true
263
- * }
264
- * }
265
- * ```
266
- *
267
- * @see SubscriptionOptions for all available options
268
- */
269
- subscriptionOptions?: SubscriptionOptions;
270
- };
271
-
272
- /** Extract the tag config for a particular tag name `K` from a `Spec` */
273
- export type ExtractByTag<
274
- Spec extends readonly TagConfig[],
275
- K
276
- > = Extract<Spec[number], { tagName: K }>;
277
-
278
- /**
279
- * Build a strongly-typed map of tagName → app-visible value type.
280
- * Use with `as const` specs to preserve literal tag names.
281
- */
282
- export type TagValueMap<Spec extends readonly TagConfig[]> = {
283
- [K in Spec[number]["tagName"]]: TagValueOf<ExtractByTag<Spec, K>["valueType"]>;
284
- };
285
-
286
- /**
287
- * Helper: binding type for a specific tag name from a spec.
288
- */
289
- export type BindingOf<
290
- Spec extends readonly TagConfig[],
291
- K extends Spec[number]["tagName"]
292
- > = TagBinding<TagValueMap<Spec>[K]>;
293
-
294
- /**
295
- * Enhanced context value with scale management.
296
- * Providers should:
297
- * - Buffer **raw** values in `rawValues` (pre-scale, pre-codec)
298
- * - Populate `values` from `rawValues` using current scales/codecs
299
- * - Inverse-scale/encode on write(t) before invoking backend
300
- */
301
- export interface BaseContextValue<VMap extends Record<string, any>> {
302
- /** Current app-visible tag values (already scaled/decoded). */
303
- values: Partial<VMap>;
304
-
305
- /** Last raw (controller) values, as received (pre-scale, pre-codec). */
306
- rawValues: Record<string, unknown>;
307
-
308
- /** Whether initial reads are pending. */
309
- isLoading: boolean;
310
-
311
- /**
312
- * Write a single tag value (app-visible → provider will inverse-scale/encode).
313
- * Strongly typed by tag name when used with a typed Context.
314
- */
315
- write: <K extends keyof VMap & string>(tagName: K, value: VMap[K]) => Promise<void>;
316
-
317
- /**
318
- * Trigger a momentary/toggle action for a tag.
319
- * Typically used for boolean "request" bits.
320
- */
321
- tap: <K extends keyof VMap & string>(tagName: K) => Promise<void>;
322
-
323
- /** Current scale configurations by name. */
324
- scales: Record<string, ScaleConfig>;
325
-
326
- /**
327
- * Update a scale group (factor and label). Providers should recompute affected tags from **raw**.
328
- *
329
- * @param scaleName - Name of the scale group (e.g., "position")
330
- * @param newScale - New scale factor (display = raw * newScale)
331
- * @param newLabel - New units label (e.g., "inches")
332
- */
333
- updateScale: (scaleName: string, newScale: number, newLabel: string) => Promise<void>;
334
- }
1
+ /*
2
+ * Copyright (C) 2025 Automated Design Corp.. All Rights Reserved.
3
+ * Created Date: 2025-09-05 07:57:49
4
+ * -----
5
+ * Last Modified: 2026-01-29 09:31:54
6
+ * -----
7
+ *
8
+ */
9
+
10
+ /**
11
+ * @module core/AutoCoreTagTypes
12
+ *
13
+ * Core type system for AutoCore's tag layer:
14
+ * - Strongly-typed tag values (boolean/number/string/json)
15
+ * - Optional **scales** for numeric unit conversion (e.g., mm ⇄ in)
16
+ * - Optional **codecs** to present richer client-side types (Date/Map) while
17
+ * keeping pure JSON across the wire (serde_json::Value on the server)
18
+ */
19
+
20
+ export type PrimitiveKind = "boolean" | "number" | "string" | "json";
21
+
22
+ /** Strict JSON value (mirrors serde_json::Value) */
23
+ type JsonPrimitive = string | number | boolean | null;
24
+ export type JsonValue =
25
+ | JsonPrimitive
26
+ | { [key: string]: JsonValue }
27
+ | JsonValue[];
28
+
29
+ /**
30
+ * Extended client-side value you *may* choose to present in the UI.
31
+ * Use codecs to round-trip these as pure JSON to the server.
32
+ */
33
+ export type ExtendedJsonValue = JsonValue | Date | Map<string, JsonValue>;
34
+
35
+ /**
36
+ * Map a tag's declared primitive kind to the app-visible type.
37
+ * - "json" becomes ExtendedJsonValue so UIs can work with Date/Map when desired.
38
+ */
39
+ export type TagValueOf<K extends PrimitiveKind> =
40
+ K extends "boolean" ? boolean :
41
+ K extends "number" ? number :
42
+ K extends "string" ? string :
43
+ ExtendedJsonValue;
44
+
45
+ /**
46
+ * Runtime binding for a single tag, as returned by hooks like `useAutoCoreTag`.
47
+ * - `value` is app-visible (already scaled/decoded)
48
+ * - `rawValue` is the last **unscaled, un-decoded** controller value received (server JSON)
49
+ * - `write` expects app-visible value (provider will inverse-scale/encode)
50
+ * - `tap` is typically for boolean momentaries (provider may pulse true→false)
51
+ */
52
+ export type TagBinding<T> = Readonly<{
53
+ /** App-visible value (scaled/decoded). */
54
+ value: T | undefined;
55
+ /** Last raw value from the server (pre-scale, pre-codec). */
56
+ rawValue: unknown | undefined;
57
+ /** Write a new app-visible value (provider will inverse-scale/encode). */
58
+ write: (displayValue: T) => Promise<void>;
59
+ /** Momentary action; typically boolean true→false pulse. */
60
+ tap: () => Promise<void>;
61
+ /** True while initial read/bootstrapping is in progress. */
62
+ isLoading: boolean;
63
+ }>;
64
+
65
+ /**
66
+ * Options that control how subscription updates are delivered to the client.
67
+ *
68
+ * This implements the "hybrid" subscription model where:
69
+ * - **Project configuration** defines limits and defaults (e.g., minimum sampling rate)
70
+ * - **Client requests** can customize within those bounds
71
+ *
72
+ * ## Behavior
73
+ *
74
+ * - `undefined` values mean "use server default"
75
+ * - Client requests are clamped to server limits (can't request faster than hardware supports)
76
+ * - All filtering (deadband, on_change_only) is applied server-side before sending updates
77
+ *
78
+ * @example Basic rate limiting
79
+ * ```typescript
80
+ * {
81
+ * tagName: "fastSensor",
82
+ * domain: "MODBUS",
83
+ * symbolName: "sensor.temperature",
84
+ * valueType: "number",
85
+ * subscriptionOptions: {
86
+ * sampling_interval_ms: 500, // Limit to 2 updates/sec
87
+ * on_change_only: true // Only send when value changes
88
+ * }
89
+ * }
90
+ * ```
91
+ *
92
+ * @example Deadband filtering for noisy signals
93
+ * ```typescript
94
+ * {
95
+ * tagName: "analogInput",
96
+ * domain: "MODBUS",
97
+ * symbolName: "ai.pressure",
98
+ * valueType: "number",
99
+ * subscriptionOptions: {
100
+ * deadband_percent: 1.0 // Ignore changes < 1% of full scale
101
+ * }
102
+ * }
103
+ * ```
104
+ */
105
+ export interface SubscriptionOptions {
106
+ /**
107
+ * Minimum interval between updates in milliseconds.
108
+ *
109
+ * The server will not send updates faster than this rate, even if the
110
+ * underlying data changes more frequently. This helps prevent UI overload.
111
+ *
112
+ * - `undefined`: Use server default (typically from project configuration)
113
+ * - If client requests faster than hardware polling rate, gets clamped to hardware rate
114
+ *
115
+ * @example `{ sampling_interval_ms: 100 }` - Max 10 updates/second
116
+ */
117
+ sampling_interval_ms?: number;
118
+
119
+ /**
120
+ * Only send updates when the value changes (vs periodic heartbeat).
121
+ *
122
+ * When `true`, the server only sends updates when the value differs from
123
+ * the last sent value (after applying deadband filtering).
124
+ *
125
+ * When `false` or `undefined`, updates may be sent periodically even if unchanged.
126
+ */
127
+ on_change_only?: boolean;
128
+
129
+ /**
130
+ * Deadband as a percentage of full scale (0.0 to 100.0).
131
+ *
132
+ * Updates are suppressed unless the value changes by at least this
133
+ * percentage of the full scale range. This reduces network traffic
134
+ * for noisy signals.
135
+ *
136
+ * - `deadband_percent: 1.0` means ignore changes less than 1% of full scale
137
+ * - Takes precedence over `deadband_absolute` if both are set
138
+ *
139
+ * @example `{ deadband_percent: 2.5 }` - Ignore changes < 2.5% of range
140
+ */
141
+ deadband_percent?: number;
142
+
143
+ /**
144
+ * Deadband as an absolute value change threshold.
145
+ *
146
+ * Updates are suppressed unless the value changes by at least this
147
+ * absolute amount. Useful when you know the meaningful change threshold.
148
+ *
149
+ * - Only used if `deadband_percent` is not set
150
+ *
151
+ * @example `{ deadband_absolute: 5.0 }` - Ignore changes < 5 units
152
+ */
153
+ deadband_absolute?: number;
154
+
155
+ /**
156
+ * Queue size for buffering updates when the client is slow.
157
+ *
158
+ * If the client can't consume updates fast enough, this many updates
159
+ * are queued before older ones are discarded.
160
+ *
161
+ * - `undefined`: Use server default (typically 1 - latest value only)
162
+ * - Higher values useful for historical trending or burst handling
163
+ */
164
+ queue_size?: number;
165
+
166
+
167
+ /**
168
+ * Custom arguments specific for the specified domain.
169
+ */
170
+ args?: Record<string, unknown>;
171
+ }
172
+
173
+ /**
174
+ * Configuration for a named scale group.
175
+ * Apply by setting `scale: "<name>"` on numeric tags.
176
+ */
177
+ export interface ScaleConfig {
178
+ /** Unique name for this scale group (e.g., "position", "load") */
179
+ name: string;
180
+ /** Current scale factor — incoming values ×= scale; outgoing values /= scale */
181
+ scale: number;
182
+ /** Units/label for display (e.g., "mm", "in", "lbs") */
183
+ label: string;
184
+ /** Optional description for debugging/documentation */
185
+ description?: string;
186
+ /**
187
+ * Optional server tag that provides the scale dynamically.
188
+ * (If used, your provider should subscribe and update `scale` when it changes.)
189
+ */
190
+ serverTag?: {
191
+ domain: string;
192
+ symbolName: string;
193
+ };
194
+ }
195
+
196
+ /**
197
+ * A codec lets a tag expose a richer client-side type while staying JSON on the wire.
198
+ * Common examples:
199
+ * - Date values: ISO string ⇄ Date
200
+ * - Map-like blobs: object ⇄ Map<string, JsonValue>
201
+ */
202
+ export type TagCodec<TIn = unknown, TOut extends JsonValue = JsonValue> = {
203
+ /** raw JSON (from server) → app-visible value */
204
+ fromServer?: (raw: unknown) => TIn;
205
+ /** app-visible value → pure JSON (to server) */
206
+ toServer?: (value: TIn) => TOut;
207
+ };
208
+
209
+ /**
210
+ * Tag configuration descriptor used to build a typed spec.
211
+ *
212
+ * @typeParam K - Literal tag name (use `as const` on your spec array)
213
+ * @typeParam T - Primitive kind for type mapping (boolean/number/string/json)
214
+ */
215
+ export type TagConfig<
216
+ K extends string = string,
217
+ T extends PrimitiveKind = PrimitiveKind
218
+ > = {
219
+ /** Local key used by UI/consumers (unique within your spec) */
220
+ tagName: K;
221
+
222
+ /** Fully-Qualified Domain Name - the complete topic path.
223
+ * Format: "domain.path.to.symbol" (e.g., "ads.plc1.gio.bControlPowerOk", "modbus.holding_registers.5")
224
+ * The first segment is the domain, used for routing to the appropriate servelet.
225
+ */
226
+ fqdn: string;
227
+
228
+ /** Declared primitive kind for typing and DevPanel rendering */
229
+ valueType: T;
230
+
231
+ /** Optional initial **raw** value before first server update */
232
+ initialValue?: TagValueOf<T>;
233
+
234
+
235
+ /**
236
+ * Optional scale group for numeric tags.
237
+ * If present, provider will:
238
+ * - Multiply incoming numbers by the group's `scale`
239
+ * - Divide outgoing numbers by the group's `scale`
240
+ */
241
+ scale?: string;
242
+
243
+ /**
244
+ * Optional codec to present richer UI types while keeping JSON on the wire.
245
+ * Only commonly used with `valueType: "json"`.
246
+ */
247
+ codec?: TagCodec;
248
+
249
+ /**
250
+ * Optional subscription options to control how updates are delivered.
251
+ *
252
+ * These options implement the hybrid subscription model where you can
253
+ * configure rate limiting, deadband filtering, and other delivery options
254
+ * to prevent overwhelming the UI with high-frequency updates.
255
+ *
256
+ * @example Rate limit a fast-updating tag
257
+ * ```typescript
258
+ * {
259
+ * tagName: "position",
260
+ * subscriptionOptions: {
261
+ * sampling_interval_ms: 100, // Max 10 updates/sec
262
+ * on_change_only: true
263
+ * }
264
+ * }
265
+ * ```
266
+ *
267
+ * @see SubscriptionOptions for all available options
268
+ */
269
+ subscriptionOptions?: SubscriptionOptions;
270
+ };
271
+
272
+ /** Extract the tag config for a particular tag name `K` from a `Spec` */
273
+ export type ExtractByTag<
274
+ Spec extends readonly TagConfig[],
275
+ K
276
+ > = Extract<Spec[number], { tagName: K }>;
277
+
278
+ /**
279
+ * Build a strongly-typed map of tagName → app-visible value type.
280
+ * Use with `as const` specs to preserve literal tag names.
281
+ */
282
+ export type TagValueMap<Spec extends readonly TagConfig[]> = {
283
+ [K in Spec[number]["tagName"]]: TagValueOf<ExtractByTag<Spec, K>["valueType"]>;
284
+ };
285
+
286
+ /**
287
+ * Helper: binding type for a specific tag name from a spec.
288
+ */
289
+ export type BindingOf<
290
+ Spec extends readonly TagConfig[],
291
+ K extends Spec[number]["tagName"]
292
+ > = TagBinding<TagValueMap<Spec>[K]>;
293
+
294
+ /**
295
+ * Enhanced context value with scale management.
296
+ * Providers should:
297
+ * - Buffer **raw** values in `rawValues` (pre-scale, pre-codec)
298
+ * - Populate `values` from `rawValues` using current scales/codecs
299
+ * - Inverse-scale/encode on write(t) before invoking backend
300
+ */
301
+ export interface BaseContextValue<VMap extends Record<string, any>> {
302
+ /** Current app-visible tag values (already scaled/decoded). */
303
+ values: Partial<VMap>;
304
+
305
+ /** Last raw (controller) values, as received (pre-scale, pre-codec). */
306
+ rawValues: Record<string, unknown>;
307
+
308
+ /** Whether initial reads are pending. */
309
+ isLoading: boolean;
310
+
311
+ /**
312
+ * Write a single tag value (app-visible → provider will inverse-scale/encode).
313
+ * Strongly typed by tag name when used with a typed Context.
314
+ */
315
+ write: <K extends keyof VMap & string>(tagName: K, value: VMap[K]) => Promise<void>;
316
+
317
+ /**
318
+ * Trigger a momentary/toggle action for a tag.
319
+ * Typically used for boolean "request" bits.
320
+ */
321
+ tap: <K extends keyof VMap & string>(tagName: K) => Promise<void>;
322
+
323
+ /** Current scale configurations by name. */
324
+ scales: Record<string, ScaleConfig>;
325
+
326
+ /**
327
+ * Update a scale group (factor and label). Providers should recompute affected tags from **raw**.
328
+ *
329
+ * @param scaleName - Name of the scale group (e.g., "position")
330
+ * @param newScale - New scale factor (display = raw * newScale)
331
+ * @param newLabel - New units label (e.g., "inches")
332
+ */
333
+ updateScale: (scaleName: string, newScale: number, newLabel: string) => Promise<void>;
334
+ }