@vention/machine-logic-ui-sdk 0.14.0 → 0.16.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/index.esm.js CHANGED
@@ -1,6 +1,6 @@
1
1
  import { jsx } from 'react/jsx-runtime';
2
2
  import 'react-simple-keyboard/build/css/index.css';
3
- import { useState, useRef, useEffect } from 'react';
3
+ import { useState, useRef, useEffect, createContext, useMemo, useContext } from 'react';
4
4
  import Keyboard from 'react-simple-keyboard';
5
5
  import mqtt from 'mqtt';
6
6
 
@@ -1815,6 +1815,20 @@ const VirtualKeyboard = () => {
1815
1815
  const [keyboardLayoutName, setKeyboardLayoutName] = useState(KeyboardLayoutName.DEFAULT);
1816
1816
  const [focusedTextInput, setFocusedTextInput] = useState();
1817
1817
  const virtualKeyboardRef = useRef(null);
1818
+ const keyboardContainerRef = useRef(null);
1819
+ useEffect(function handleClickOutsideListeners() {
1820
+ function handleClickOutside(event) {
1821
+ if (keyboardContainerRef.current && !keyboardContainerRef.current.contains(event.target)) {
1822
+ setIsKeyboardVisible(false);
1823
+ }
1824
+ }
1825
+ document.addEventListener("mousedown", handleClickOutside);
1826
+ document.addEventListener("touchstart", handleClickOutside);
1827
+ return () => {
1828
+ document.removeEventListener("mousedown", handleClickOutside);
1829
+ document.removeEventListener("touchstart", handleClickOutside);
1830
+ };
1831
+ }, []);
1818
1832
  useEffect(function showOrHideKeyboard() {
1819
1833
  // The keyboard will appear/disappear on mouse down
1820
1834
  // However, if the user is clicking something, like a submit button or the input itself, the mouse up will happen a few milliseconds after the keyboard is shown/hidden
@@ -1830,14 +1844,6 @@ const VirtualKeyboard = () => {
1830
1844
  clearTimeout(showTimeout);
1831
1845
  };
1832
1846
  }
1833
- const hideTimeout = setTimeout(() => {
1834
- var _a;
1835
- (_a = virtualKeyboardRef.current) === null || _a === void 0 ? void 0 : _a.destroy();
1836
- setIsKeyboardVisible(false);
1837
- }, effectDelayMs);
1838
- return () => {
1839
- clearTimeout(hideTimeout);
1840
- };
1841
1847
  }, [focusedTextInput]);
1842
1848
  useEffect(function scrollInputIntoViewAfterKeyboardAppears() {
1843
1849
  if (isKeyboardVisible && focusedTextInput !== undefined) {
@@ -1886,11 +1892,13 @@ const VirtualKeyboard = () => {
1886
1892
  capture: true
1887
1893
  });
1888
1894
  return () => {
1889
- focusedTextInput.removeEventListener("blur", unsetFocusedTextInput, {
1890
- capture: true
1891
- });
1895
+ if (!isKeyboardVisible) {
1896
+ focusedTextInput.removeEventListener("blur", unsetFocusedTextInput, {
1897
+ capture: true
1898
+ });
1899
+ }
1892
1900
  };
1893
- }, [focusedTextInput, initialInputValue]);
1901
+ }, [focusedTextInput, initialInputValue, isKeyboardVisible]);
1894
1902
  // Stay in sync with external changes originating from code or physical keyboard
1895
1903
  useEffect(function syncExternalChangesFromCodeOrKeyboard() {
1896
1904
  if (focusedTextInput === undefined) {
@@ -1909,6 +1917,9 @@ const VirtualKeyboard = () => {
1909
1917
  focusedTextInput.addEventListener("click", updateKeyboardInput, {
1910
1918
  capture: true
1911
1919
  });
1920
+ focusedTextInput.addEventListener("touchstart", updateKeyboardInput, {
1921
+ capture: true
1922
+ });
1912
1923
  focusedTextInput.addEventListener("touchend", updateKeyboardInput, {
1913
1924
  capture: true
1914
1925
  });
@@ -1919,6 +1930,9 @@ const VirtualKeyboard = () => {
1919
1930
  focusedTextInput.removeEventListener("click", updateKeyboardInput, {
1920
1931
  capture: true
1921
1932
  });
1933
+ focusedTextInput.removeEventListener("touchstart", updateKeyboardInput, {
1934
+ capture: true
1935
+ });
1922
1936
  focusedTextInput.removeEventListener("touchend", updateKeyboardInput, {
1923
1937
  capture: true
1924
1938
  });
@@ -1956,11 +1970,23 @@ const VirtualKeyboard = () => {
1956
1970
  break;
1957
1971
  }
1958
1972
  };
1973
+ const handleKeyboardContainerEvents = event => {
1974
+ event.stopPropagation();
1975
+ if (event.cancelable && event.type === "mousedown") {
1976
+ event.preventDefault();
1977
+ }
1978
+ if (focusedTextInput) {
1979
+ focusedTextInput.focus();
1980
+ }
1981
+ };
1959
1982
  if (!isKeyboardVisible) {
1960
1983
  return null;
1961
1984
  }
1962
1985
  return jsx("div", {
1963
1986
  id: "virtual_keyboard",
1987
+ ref: keyboardContainerRef,
1988
+ onMouseDown: handleKeyboardContainerEvents,
1989
+ onTouchStart: handleKeyboardContainerEvents,
1964
1990
  children: jsx(Keyboard, {
1965
1991
  keyboardRef: ref => {
1966
1992
  virtualKeyboardRef.current = ref;
@@ -1989,7 +2015,6 @@ const VirtualKeyboard = () => {
1989
2015
  layoutName: keyboardLayoutName,
1990
2016
  preventMouseDownDefault: true,
1991
2017
  stopMouseDownPropagation: true,
1992
- autoUseTouchEvents: true,
1993
2018
  display: KeyboardDisplay,
1994
2019
  newLineOnEnter: true
1995
2020
  })
@@ -2499,4 +2524,82 @@ const getMachineCodeProcessHttpUrl = processName => {
2499
2524
  return `${executionEngineHttpUrl}/v1/machineCode/services/${processName}`;
2500
2525
  };
2501
2526
 
2502
- export { MqttClient, VirtualKeyboard, connectToMqttAndGetClient, getExecutionEngineHttpUrl, getMachineCodeProcessHttpUrl, getMqttWsUrl, isOnEdge, isTouchScreenDevice };
2527
+ const defaultContext = {
2528
+ client: null,
2529
+ connectionStatus: "disconnected"
2530
+ };
2531
+ const mqttContext = /*#__PURE__*/createContext(defaultContext);
2532
+ const MqttProvider = props => {
2533
+ const [connectionStatus, setConnectionStatus] = useState("disconnected");
2534
+ const [mqttClient, setMqttClient] = useState(null);
2535
+ const contextValue = useMemo(() => ({
2536
+ client: mqttClient,
2537
+ connectionStatus
2538
+ }), [mqttClient, connectionStatus]);
2539
+ useEffect(function mqttConnection() {
2540
+ function connectToMqtt() {
2541
+ return __awaiter(this, void 0, void 0, function* () {
2542
+ const client = mqtt.connect(yield getMqttWsUrl());
2543
+ client.on("connect", () => {
2544
+ setConnectionStatus("connected");
2545
+ setMqttClient(client);
2546
+ });
2547
+ client.on("error", error => {
2548
+ setConnectionStatus("error");
2549
+ console.error("MQTT error:", error);
2550
+ });
2551
+ client.on("offline", () => {
2552
+ setConnectionStatus("disconnected");
2553
+ });
2554
+ client.on("end", () => {
2555
+ setConnectionStatus("disconnected");
2556
+ });
2557
+ return function cleanup() {
2558
+ setMqttClient(null);
2559
+ setConnectionStatus("disconnected");
2560
+ client.end();
2561
+ };
2562
+ });
2563
+ }
2564
+ connectToMqtt();
2565
+ }, []);
2566
+ return jsx(mqttContext.Provider, {
2567
+ value: contextValue,
2568
+ children: props.children
2569
+ });
2570
+ };
2571
+
2572
+ var MqttSandingTopics;
2573
+ (function (MqttSandingTopics) {
2574
+ MqttSandingTopics["SET_APP_STATE"] = "sandingMachineApp/setAppState";
2575
+ MqttSandingTopics["CALIBRATE"] = "sandingMachineApp/calibrate";
2576
+ MqttSandingTopics["STATE_APP"] = "sandingMachineApp/state/app";
2577
+ MqttSandingTopics["STATE_ROBOT"] = "sandingMachineApp/state/robot";
2578
+ MqttSandingTopics["STATE_STATION"] = "sandingMachineApp/state/station";
2579
+ MqttSandingTopics["CHANGE_SANDING_PAPER"] = "sandingMachineApp/state/changeSandingPaper";
2580
+ MqttSandingTopics["SANDING_PAPER_CHANGED"] = "sandingMachineApp/sandingPaperChanged";
2581
+ MqttSandingTopics["GET_INITIAL_STATE"] = "sandingMachineApp/getInitialState";
2582
+ MqttSandingTopics["NOTIFICATION_MESSAGES"] = "sandingMachineApp/notification/messages";
2583
+ })(MqttSandingTopics || (MqttSandingTopics = {}));
2584
+
2585
+ const useMqttSubscription = props => {
2586
+ const mqtt = useContext(mqttContext);
2587
+ const [message, setMessage] = useState();
2588
+ useEffect(function test() {
2589
+ var _a, _b;
2590
+ if (mqtt.connectionStatus !== "connected" || !mqtt.client) return;
2591
+ (_a = mqtt.client) === null || _a === void 0 ? void 0 : _a.subscribe(props.topic);
2592
+ // Using the on message is not optimal as for every subscription we will add a new listener
2593
+ // For the sake of simplicity we will keep it like this
2594
+ (_b = mqtt.client) === null || _b === void 0 ? void 0 : _b.on("message", (topic, message) => {
2595
+ if (topic === props.topic) setMessage(JSON.parse(message.toString()));
2596
+ });
2597
+ return function cleanup() {
2598
+ var _a;
2599
+ (_a = mqtt.client) === null || _a === void 0 ? void 0 : _a.unsubscribe(props.topic);
2600
+ };
2601
+ }, [mqtt, props.topic]);
2602
+ return message;
2603
+ };
2604
+
2605
+ export { MqttClient, MqttProvider, MqttSandingTopics, VirtualKeyboard, connectToMqttAndGetClient, getExecutionEngineHttpUrl, getMachineCodeProcessHttpUrl, getMqttWsUrl, isOnEdge, isTouchScreenDevice, mqttContext, useMqttSubscription };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@vention/machine-logic-ui-sdk",
3
- "version": "0.14.0",
3
+ "version": "0.16.0",
4
4
  "repository": {
5
5
  "type": "git",
6
6
  "url": "https://github.com/VentionCo/machine-cloud.git"
@@ -11,7 +11,7 @@
11
11
  },
12
12
  "license": "MIT",
13
13
  "dependencies": {
14
- "react-simple-keyboard": "3.7.153",
14
+ "react-simple-keyboard": "3.8.15",
15
15
  "mqtt": "5.10.1"
16
16
  },
17
17
  "peerDependencies": {
package/src/index.d.ts CHANGED
@@ -1,3 +1,6 @@
1
1
  export * from "./lib/components/virtual-keyboard/virtual-keyboard";
2
2
  export * from "./lib/utils/machine-logic-ui-sdk-utils";
3
3
  export * from "./lib/mqtt-browser/mqtt-client";
4
+ export * from "./lib/mqtt/mqtt-context";
5
+ export * from "./lib/mqtt/mqtt-types";
6
+ export * from "./lib/mqtt/use-mqtt-subscription";
@@ -39,3 +39,4 @@ export declare const KeyboardLayoutsByInputType: {
39
39
  readonly url: KeyboardLayoutObject;
40
40
  readonly textarea: KeyboardLayoutObject;
41
41
  };
42
+ export type InputType = keyof typeof KeyboardLayoutsByInputType;
@@ -0,0 +1,12 @@
1
+ import { ReactNode } from "react";
2
+ import { MqttClient } from "mqtt";
3
+ interface MqttContext {
4
+ client: MqttClient | null;
5
+ connectionStatus: "connected" | "disconnected" | "error";
6
+ }
7
+ export declare const mqttContext: import("react").Context<MqttContext>;
8
+ interface Props {
9
+ children: ReactNode;
10
+ }
11
+ export declare const MqttProvider: (props: Props) => import("react/jsx-runtime").JSX.Element;
12
+ export {};
@@ -0,0 +1,56 @@
1
+ export declare enum MqttSandingTopics {
2
+ SET_APP_STATE = "sandingMachineApp/setAppState",
3
+ CALIBRATE = "sandingMachineApp/calibrate",
4
+ STATE_APP = "sandingMachineApp/state/app",
5
+ STATE_ROBOT = "sandingMachineApp/state/robot",
6
+ STATE_STATION = "sandingMachineApp/state/station",
7
+ CHANGE_SANDING_PAPER = "sandingMachineApp/state/changeSandingPaper",
8
+ SANDING_PAPER_CHANGED = "sandingMachineApp/sandingPaperChanged",
9
+ GET_INITIAL_STATE = "sandingMachineApp/getInitialState",
10
+ NOTIFICATION_MESSAGES = "sandingMachineApp/notification/messages"
11
+ }
12
+ export type SandingApplicationState = "stop" | "start" | "home" | "freedrive";
13
+ export type SandingRobotState = "fault" | "ready";
14
+ type MqttSetAppStatePayload = {
15
+ state: SandingApplicationState;
16
+ };
17
+ type MqttCalibratePayload = object;
18
+ type MqttRobotStatePayload = {
19
+ state: SandingRobotState;
20
+ };
21
+ export type StationState = {
22
+ completedSteps: number;
23
+ totalSteps: number;
24
+ isActive: boolean;
25
+ isVacuumActivated: boolean;
26
+ isPanelInPlace: boolean;
27
+ };
28
+ export type MqttStationStatePayload = {
29
+ station1: StationState;
30
+ station2: StationState;
31
+ station3: StationState;
32
+ station4: StationState;
33
+ };
34
+ type MqttChangeSandingPaperPayload = object;
35
+ type MqttSandingPaperChangedPayload = object;
36
+ type MqttGetInitialStatePayload = object;
37
+ export type MqttNotificationPayload = {
38
+ id: string;
39
+ message: string;
40
+ type: "info" | "warn" | "error";
41
+ timestamp: number;
42
+ isRead?: boolean;
43
+ };
44
+ type MqttPayloadMapping = {
45
+ [MqttSandingTopics.SET_APP_STATE]: MqttSetAppStatePayload;
46
+ [MqttSandingTopics.CALIBRATE]: MqttCalibratePayload;
47
+ [MqttSandingTopics.STATE_APP]: MqttSetAppStatePayload;
48
+ [MqttSandingTopics.STATE_ROBOT]: MqttRobotStatePayload;
49
+ [MqttSandingTopics.STATE_STATION]: MqttStationStatePayload;
50
+ [MqttSandingTopics.CHANGE_SANDING_PAPER]: MqttChangeSandingPaperPayload;
51
+ [MqttSandingTopics.SANDING_PAPER_CHANGED]: MqttSandingPaperChangedPayload;
52
+ [MqttSandingTopics.GET_INITIAL_STATE]: MqttGetInitialStatePayload;
53
+ [MqttSandingTopics.NOTIFICATION_MESSAGES]: MqttNotificationPayload;
54
+ };
55
+ export type MqttPayloadByTopic<T extends MqttSandingTopics> = MqttPayloadMapping[T];
56
+ export {};
@@ -0,0 +1,6 @@
1
+ import { MqttSandingTopics, MqttPayloadByTopic } from "./mqtt-types";
2
+ interface Props<TMqttTopic> {
3
+ topic: TMqttTopic;
4
+ }
5
+ export declare const useMqttSubscription: <TMqttTopic extends MqttSandingTopics>(props: Props<TMqttTopic>) => MqttPayloadByTopic<TMqttTopic>;
6
+ export {};