@imperosoft/cris-webui-components 1.1.0-beta.0 → 1.1.0-beta.2
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/dist/index.d.mts +3 -1
- package/dist/index.d.ts +3 -1
- package/dist/index.js +79 -14
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +79 -14
- package/dist/index.mjs.map +1 -1
- package/package.json +2 -2
package/dist/index.d.mts
CHANGED
|
@@ -58,8 +58,10 @@ interface CrisButtonProps {
|
|
|
58
58
|
onPress?: () => void;
|
|
59
59
|
/** Custom release handler */
|
|
60
60
|
onRelease?: () => void;
|
|
61
|
+
/** Enable debug logging for this button */
|
|
62
|
+
debug?: boolean;
|
|
61
63
|
}
|
|
62
|
-
declare function CrisButton({ join, joinFeedback, joinEnable, joinVisible, text, textPressed, textSelected, icon, iconName, iconClass, iconSize, iconContainerSize, iconStyle, iconPosition, iconNameActive, iconClassActive, iconStyleActive, showControlFeedback, showLocalFeedback, suppressKeyClicks, smartId, className, classActive, classPressed, classDisabled, children, onPress, onRelease, }: CrisButtonProps): react_jsx_runtime.JSX.Element | null;
|
|
64
|
+
declare function CrisButton({ join, joinFeedback, joinEnable, joinVisible, text, textPressed, textSelected, icon, iconName, iconClass, iconSize, iconContainerSize, iconStyle, iconPosition, iconNameActive, iconClassActive, iconStyleActive, showControlFeedback, showLocalFeedback, suppressKeyClicks, smartId, className, classActive, classPressed, classDisabled, children, onPress, onRelease, debug, }: CrisButtonProps): react_jsx_runtime.JSX.Element | null;
|
|
63
65
|
|
|
64
66
|
interface CrisTextProps {
|
|
65
67
|
/** Serial join for indirect text */
|
package/dist/index.d.ts
CHANGED
|
@@ -58,8 +58,10 @@ interface CrisButtonProps {
|
|
|
58
58
|
onPress?: () => void;
|
|
59
59
|
/** Custom release handler */
|
|
60
60
|
onRelease?: () => void;
|
|
61
|
+
/** Enable debug logging for this button */
|
|
62
|
+
debug?: boolean;
|
|
61
63
|
}
|
|
62
|
-
declare function CrisButton({ join, joinFeedback, joinEnable, joinVisible, text, textPressed, textSelected, icon, iconName, iconClass, iconSize, iconContainerSize, iconStyle, iconPosition, iconNameActive, iconClassActive, iconStyleActive, showControlFeedback, showLocalFeedback, suppressKeyClicks, smartId, className, classActive, classPressed, classDisabled, children, onPress, onRelease, }: CrisButtonProps): react_jsx_runtime.JSX.Element | null;
|
|
64
|
+
declare function CrisButton({ join, joinFeedback, joinEnable, joinVisible, text, textPressed, textSelected, icon, iconName, iconClass, iconSize, iconContainerSize, iconStyle, iconPosition, iconNameActive, iconClassActive, iconStyleActive, showControlFeedback, showLocalFeedback, suppressKeyClicks, smartId, className, classActive, classPressed, classDisabled, children, onPress, onRelease, debug, }: CrisButtonProps): react_jsx_runtime.JSX.Element | null;
|
|
63
65
|
|
|
64
66
|
interface CrisTextProps {
|
|
65
67
|
/** Serial join for indirect text */
|
package/dist/index.js
CHANGED
|
@@ -118,8 +118,11 @@ function CrisButton({
|
|
|
118
118
|
classDisabled = "",
|
|
119
119
|
children,
|
|
120
120
|
onPress,
|
|
121
|
-
onRelease
|
|
121
|
+
onRelease,
|
|
122
|
+
debug = false
|
|
122
123
|
}) {
|
|
124
|
+
const log = debug ? (msg, data) => console.log(`[CrisButton:${join}] ${msg}`, data ?? "") : () => {
|
|
125
|
+
};
|
|
123
126
|
const [pressed, setPressed] = (0, import_react.useState)(false);
|
|
124
127
|
const pressedRef = (0, import_react.useRef)(false);
|
|
125
128
|
const touchingRef = (0, import_react.useRef)(false);
|
|
@@ -132,16 +135,19 @@ function CrisButton({
|
|
|
132
135
|
const isEnabled = joinEnable == null ? true : enabled;
|
|
133
136
|
const isVisible = joinVisible == null ? true : visible;
|
|
134
137
|
(0, import_react.useEffect)(() => {
|
|
138
|
+
log("visibility effect", { isVisible, pressedRef: pressedRef.current });
|
|
135
139
|
if (!isVisible && pressedRef.current) {
|
|
140
|
+
log("VISIBILITY RELEASE - button hidden while pressed");
|
|
136
141
|
pressedRef.current = false;
|
|
137
142
|
setPressed(false);
|
|
138
143
|
touchingRef.current = false;
|
|
139
144
|
touchStartedHereRef.current = false;
|
|
140
145
|
if (join != null && smartId == null) {
|
|
146
|
+
log("sending release via dSet(false)");
|
|
141
147
|
dSet(join, false);
|
|
142
148
|
}
|
|
143
149
|
}
|
|
144
|
-
}, [isVisible, join, smartId, dSet]);
|
|
150
|
+
}, [isVisible, join, smartId, dSet, log]);
|
|
145
151
|
const hasControlFeedback = showControlFeedback && feedbackJoin != null && feedback;
|
|
146
152
|
const hasPressedFeedback = showLocalFeedback && pressed && isEnabled;
|
|
147
153
|
const isActive = hasControlFeedback || hasPressedFeedback;
|
|
@@ -152,42 +158,69 @@ function CrisButton({
|
|
|
152
158
|
currentText = textSelected;
|
|
153
159
|
}
|
|
154
160
|
const handlePress = () => {
|
|
155
|
-
|
|
156
|
-
if (
|
|
161
|
+
log("handlePress called", { suppressKeyClicks, pressedRef: pressedRef.current, isEnabled });
|
|
162
|
+
if (suppressKeyClicks) {
|
|
163
|
+
log("BLOCKED: suppressKeyClicks");
|
|
164
|
+
return;
|
|
165
|
+
}
|
|
166
|
+
if (pressedRef.current) {
|
|
167
|
+
log("BLOCKED: already pressed");
|
|
168
|
+
return;
|
|
169
|
+
}
|
|
157
170
|
pressedRef.current = true;
|
|
158
171
|
setPressed(true);
|
|
159
|
-
if (!isEnabled)
|
|
172
|
+
if (!isEnabled) {
|
|
173
|
+
log("SKIPPED dSet: not enabled");
|
|
174
|
+
return;
|
|
175
|
+
}
|
|
160
176
|
onPress?.();
|
|
161
177
|
if (join != null && smartId == null) {
|
|
178
|
+
log("SENDING PRESS via dSet(true)");
|
|
162
179
|
dSet(join, true);
|
|
163
180
|
}
|
|
164
181
|
};
|
|
165
182
|
const handleRelease = () => {
|
|
166
|
-
|
|
167
|
-
if (
|
|
183
|
+
log("handleRelease called", { suppressKeyClicks, pressedRef: pressedRef.current, isEnabled });
|
|
184
|
+
if (suppressKeyClicks) {
|
|
185
|
+
log("BLOCKED: suppressKeyClicks");
|
|
186
|
+
return;
|
|
187
|
+
}
|
|
188
|
+
if (!pressedRef.current) {
|
|
189
|
+
log("BLOCKED: not pressed");
|
|
190
|
+
return;
|
|
191
|
+
}
|
|
168
192
|
pressedRef.current = false;
|
|
169
193
|
setPressed(false);
|
|
170
|
-
if (!isEnabled)
|
|
194
|
+
if (!isEnabled) {
|
|
195
|
+
log("SKIPPED dSet: not enabled");
|
|
196
|
+
return;
|
|
197
|
+
}
|
|
171
198
|
onRelease?.();
|
|
172
199
|
if (join != null && smartId == null) {
|
|
200
|
+
log("SENDING RELEASE via dSet(false)");
|
|
173
201
|
dSet(join, false);
|
|
174
202
|
}
|
|
175
203
|
};
|
|
176
204
|
const handleTouchStart = () => {
|
|
205
|
+
log("handleTouchStart");
|
|
177
206
|
touchStart();
|
|
178
207
|
touchingRef.current = true;
|
|
179
208
|
touchStartedHereRef.current = true;
|
|
180
209
|
handlePress();
|
|
181
210
|
};
|
|
182
211
|
const handleTouchEnd = () => {
|
|
212
|
+
log("handleTouchEnd", { touchStartedHereRef: touchStartedHereRef.current });
|
|
183
213
|
touchEnd();
|
|
184
214
|
touchingRef.current = true;
|
|
185
215
|
if (touchStartedHereRef.current) {
|
|
186
216
|
touchStartedHereRef.current = false;
|
|
187
217
|
handleRelease();
|
|
218
|
+
} else {
|
|
219
|
+
log("SKIPPED handleRelease: touch did not start here");
|
|
188
220
|
}
|
|
189
221
|
};
|
|
190
222
|
const handleTouchCancel = () => {
|
|
223
|
+
log("handleTouchCancel");
|
|
191
224
|
touchEnd();
|
|
192
225
|
touchingRef.current = true;
|
|
193
226
|
touchStartedHereRef.current = false;
|
|
@@ -805,7 +838,9 @@ function CrisOfflinePage({
|
|
|
805
838
|
className = ""
|
|
806
839
|
}) {
|
|
807
840
|
const connectionStatus = (0, import_cris_webui_ch5_core6.useConnectionStore)((state) => state.status);
|
|
841
|
+
const errorReason = (0, import_cris_webui_ch5_core6.useConnectionStore)((state) => state.errorReason);
|
|
808
842
|
const [hasSeenError, setHasSeenError] = (0, import_react3.useState)(false);
|
|
843
|
+
const [lastErrorReason, setLastErrorReason] = (0, import_react3.useState)(null);
|
|
809
844
|
const [certPageOpened, setCertPageOpened] = (0, import_react3.useState)(false);
|
|
810
845
|
const [retryCountdown, setRetryCountdown] = (0, import_react3.useState)(null);
|
|
811
846
|
const processorHost = processorHostProp ?? (typeof window !== "undefined" ? window.location.hostname : "localhost");
|
|
@@ -813,10 +848,13 @@ function CrisOfflinePage({
|
|
|
813
848
|
(0, import_react3.useEffect)(() => {
|
|
814
849
|
if (connectionStatus === "error") {
|
|
815
850
|
setHasSeenError(true);
|
|
851
|
+
setLastErrorReason(errorReason);
|
|
816
852
|
} else if (connectionStatus === "connected") {
|
|
817
853
|
setHasSeenError(false);
|
|
854
|
+
setLastErrorReason(null);
|
|
818
855
|
}
|
|
819
|
-
}, [connectionStatus]);
|
|
856
|
+
}, [connectionStatus, errorReason]);
|
|
857
|
+
const isTimeoutError = lastErrorReason === "timeout";
|
|
820
858
|
const loginUrl = `https://${processorHost}${loginPath}`;
|
|
821
859
|
const certUrl = `https://${processorHost}:${wsPort}/`;
|
|
822
860
|
const openCertPage = (0, import_react3.useCallback)(() => {
|
|
@@ -874,14 +912,36 @@ function CrisOfflinePage({
|
|
|
874
912
|
isDevMode,
|
|
875
913
|
isVC4,
|
|
876
914
|
processorHost: isDevMode ? processorHost : void 0,
|
|
877
|
-
hasAuthToken: isDevMode ? hasAuthToken : void 0
|
|
915
|
+
hasAuthToken: isDevMode ? hasAuthToken : void 0,
|
|
916
|
+
errorReason: lastErrorReason
|
|
878
917
|
};
|
|
879
918
|
return /* @__PURE__ */ (0, import_jsx_runtime6.jsx)("div", { className: `cris-offline-page absolute inset-0 bg-gray-900 flex flex-col items-center justify-center overflow-auto py-8 ${className}`, children: /* @__PURE__ */ (0, import_jsx_runtime6.jsxs)("div", { className: "text-center max-w-4xl px-4", children: [
|
|
880
919
|
/* @__PURE__ */ (0, import_jsx_runtime6.jsx)("div", { className: "mb-8", children: /* @__PURE__ */ (0, import_jsx_runtime6.jsx)("div", { className: `w-16 h-16 mx-auto rounded-full flex items-center justify-center ${isError ? "bg-red-500/20" : "bg-yellow-500/20"}`, children: /* @__PURE__ */ (0, import_jsx_runtime6.jsx)("div", { className: `w-8 h-8 rounded-full ${isError ? "bg-red-500" : "bg-yellow-500 animate-pulse"}` }) }) }),
|
|
881
|
-
/* @__PURE__ */ (0, import_jsx_runtime6.jsx)("h1", { className: "text-2xl font-bold text-white mb-2", children: isError ? "Connection Error" : "Connecting..." }),
|
|
882
|
-
/* @__PURE__ */ (0, import_jsx_runtime6.jsx)("p", { className: "text-gray-400", children: isError ? isDeployedOnProcessor ? "Redirecting to login page..." : "WebSocket connection failed. SSL certificate may need to be accepted." : "Establishing connection to control system" }),
|
|
883
|
-
/* @__PURE__ */ (0, import_jsx_runtime6.jsx)("div", { className: "mt-8", children: /* @__PURE__ */ (0, import_jsx_runtime6.jsx)("span", { className: `px-4 py-2 rounded-full text-sm font-medium ${isError ? "bg-red-500/20 text-red-400" : "bg-yellow-500/20 text-yellow-400"}`, children: isError ? isDevMode ? "Dev Mode - Auth Error" : isVC4 ? "VC4 - Not Authorized" : "Auth Error" : "Connecting" }) }),
|
|
884
|
-
isError && !isDeployedOnProcessor && /* @__PURE__ */ (0, import_jsx_runtime6.
|
|
920
|
+
/* @__PURE__ */ (0, import_jsx_runtime6.jsx)("h1", { className: "text-2xl font-bold text-white mb-2", children: isError ? isTimeoutError ? "Processor Unreachable" : "Connection Error" : "Connecting..." }),
|
|
921
|
+
/* @__PURE__ */ (0, import_jsx_runtime6.jsx)("p", { className: "text-gray-400", children: isError ? isDeployedOnProcessor ? "Redirecting to login page..." : isTimeoutError ? "Could not connect to the processor. Check the IP address and network connection." : "WebSocket connection failed. SSL certificate may need to be accepted." : "Establishing connection to control system" }),
|
|
922
|
+
/* @__PURE__ */ (0, import_jsx_runtime6.jsx)("div", { className: "mt-8", children: /* @__PURE__ */ (0, import_jsx_runtime6.jsx)("span", { className: `px-4 py-2 rounded-full text-sm font-medium ${isError ? "bg-red-500/20 text-red-400" : "bg-yellow-500/20 text-yellow-400"}`, children: isError ? isTimeoutError ? "Connection Timeout" : isDevMode ? "Dev Mode - Auth Error" : isVC4 ? "VC4 - Not Authorized" : "Auth Error" : "Connecting" }) }),
|
|
923
|
+
isError && !isDeployedOnProcessor && isTimeoutError && /* @__PURE__ */ (0, import_jsx_runtime6.jsxs)("div", { className: "mt-[2em] bg-orange-500/10 border border-orange-500/30 rounded-xl", style: { overflow: "visible", padding: "1.5em 1.5em 2em 1.5em" }, children: [
|
|
924
|
+
/* @__PURE__ */ (0, import_jsx_runtime6.jsxs)("p", { className: "text-orange-400 font-medium", style: { fontSize: "1.2em", marginBottom: "1em" }, children: [
|
|
925
|
+
"The processor at ",
|
|
926
|
+
/* @__PURE__ */ (0, import_jsx_runtime6.jsx)("span", { className: "text-white", children: processorHost }),
|
|
927
|
+
" is not responding."
|
|
928
|
+
] }),
|
|
929
|
+
/* @__PURE__ */ (0, import_jsx_runtime6.jsxs)("ul", { className: "text-gray-400 text-left mb-[1em]", style: { fontSize: "1em", listStyleType: "disc", paddingLeft: "1.5em" }, children: [
|
|
930
|
+
/* @__PURE__ */ (0, import_jsx_runtime6.jsx)("li", { children: "Verify the IP address is correct" }),
|
|
931
|
+
/* @__PURE__ */ (0, import_jsx_runtime6.jsx)("li", { children: "Check that the processor is powered on" }),
|
|
932
|
+
/* @__PURE__ */ (0, import_jsx_runtime6.jsx)("li", { children: "Ensure you are on the same network" })
|
|
933
|
+
] }),
|
|
934
|
+
/* @__PURE__ */ (0, import_jsx_runtime6.jsx)("div", { className: "flex gap-[1em] justify-center", style: { overflow: "visible" }, children: /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(
|
|
935
|
+
"button",
|
|
936
|
+
{
|
|
937
|
+
onClick: retryConnection,
|
|
938
|
+
className: "bg-orange-600 hover:bg-orange-500 text-white font-medium rounded-xl transition-colors",
|
|
939
|
+
style: { padding: "1em 2em", fontSize: "1.2em", whiteSpace: "nowrap", overflow: "visible" },
|
|
940
|
+
children: "Retry Connection"
|
|
941
|
+
}
|
|
942
|
+
) })
|
|
943
|
+
] }),
|
|
944
|
+
isError && !isDeployedOnProcessor && !isTimeoutError && /* @__PURE__ */ (0, import_jsx_runtime6.jsx)("div", { className: "mt-[2em] bg-blue-500/10 border border-blue-500/30 rounded-xl", style: { overflow: "visible", padding: "1.5em 1.5em 2em 1.5em" }, children: retryCountdown !== null ? /* @__PURE__ */ (0, import_jsx_runtime6.jsxs)("div", { className: "text-center", style: { overflow: "visible" }, children: [
|
|
885
945
|
/* @__PURE__ */ (0, import_jsx_runtime6.jsxs)("p", { className: "text-blue-400 font-medium", style: { fontSize: "1.4em", marginBottom: "1em" }, children: [
|
|
886
946
|
"Retrying connection in ",
|
|
887
947
|
retryCountdown,
|
|
@@ -985,6 +1045,11 @@ function CrisOfflinePage({
|
|
|
985
1045
|
envInfo.pathname,
|
|
986
1046
|
envInfo.search
|
|
987
1047
|
] })
|
|
1048
|
+
] }),
|
|
1049
|
+
envInfo.errorReason && /* @__PURE__ */ (0, import_jsx_runtime6.jsxs)("div", { children: [
|
|
1050
|
+
/* @__PURE__ */ (0, import_jsx_runtime6.jsx)("span", { className: "text-gray-500", children: "Error Reason:" }),
|
|
1051
|
+
" ",
|
|
1052
|
+
/* @__PURE__ */ (0, import_jsx_runtime6.jsx)("span", { className: envInfo.errorReason === "timeout" ? "text-orange-400" : "text-red-400", children: envInfo.errorReason })
|
|
988
1053
|
] })
|
|
989
1054
|
] })
|
|
990
1055
|
] })
|