-
Notifications
You must be signed in to change notification settings - Fork 1
How to make a Widget
This page describes how to create widgets for use in CS-Web-Proto, taking advantage of the work we have done to provide a base interface and connection to PVs.
We recommend using functional components. This a style for writing React components in which functions return JSX Elements. It encourages stateless components which can be easily tested and have clear links between input and output. This also makes components easier to test and compose.
Find out more about functional components here and here.
Think about all the things which your component needs to render properly. Try to minimise this as much as possible. For a label, you might only need text.
All widgets accept a style object, as this allows runtime injection of parameters such as positioning and text color.
For a basic widget, this might look like:
import React from "react";
const MyComponent = (props: {
text: string | number;
style?: object;
}): JSX.Element =>
<div style={props.style}>
{props.text}
</div>
);
If you want to add classes to your component, use CSS module. This provides you with the capability to swap out CSS classes dynamically depending on the input.
You should also add a global class to your component with a simple name. This allows configuration of the styles from a global stylesheet and themes.
import React from "react";
import classes from "./mycomponent.module.css"
const MyComponent = (props: {
text: string | number;
style?: object;
}): JSX.Element =>
<div className={`Component ${classes.component}` style={props.style}>
{props.text}
</div>
);
To turn your component into a CS-Web-Proto Widget, import Widget and WidgetInterface from the Widget component files:
import { Widget, WidgetInterface } from "../Widget/widget";
Think about what special things your component does which are not captured in WidgetInterface. WidgetInterface takes care of positioning, style and macros. In the example, the text prop is special and needs to be added. Include this as its own interface specific to your component:
interface MyWidgetProps {
text: string | number;
}
Now combine your component with the Widget by including it with the basewidget prop and merging the interfaces:
const MyWidget = ( props: MyWidgetProps & WidgetInterface ): JSX.Element => <Widget baseWidget={MyComponent} {...props} />;
Congratulations! You now have a Widget which you can export and include in all your CS-Web-Proto screens!
Include the extra information which is handled by Widget when you instantiate your widget:
<MyWidget text={"This is my widget!"} containerStyling={{position: "relative"}} />
Great! The process is very similar but there are a few things to be aware of.
PV components may use the following props to get information about the PV they are connected to:
- pvName - get a string with the name of the PV
- rawPvName - string ofthe PV name before any macro substitution took place
- connected - boolean on whether or not the PV has been connected to
- value - VType with latest PV data
- readonly - bool on if the PV is readonly to the client
You may use any number of these props when defining your component. If you don't need any of them you might be better off with a standard Widget (see above).
Import PVWidget and PVWidgetInterface in place of the normal widget imports and merge your components interface with PVWidgetInterface. The PV props listed above do not need to be included in your compnent props.
Now, combine your component with PVWidget and export it. A brief example is given below:
import React from "react";
import classes from "./label.module.css";
import { PVWidget, PVWidgetInterface } from "../Widget/widget";
const MyPVComponent = (props: {
connected: bool;
style?: object;
}): JSX.Element => (
// Simple component to display text - defaults to black text and dark grey background
<div className={`Component ${classes.component}` style={props.style}>
{props.connected ? "Connected!" : "Not Connected"}
</div>
);
export const MyPVWidget = (
props: PVWidgetInterface
): JSX.Element => <{PVWidget baseWidget={MyPVComponent} {...props} />;
When instantiating your PVWidget, you only need to supply the pvName parameter and the PVWidget will provide the rest of the information via some Higher Order Components which are working behind the scenes:
<MyPVWidget pvName={"loc://pv1"} containerStyling={{position: "relative"}} />
The component which converts JSON into a screen fromJson. It maintains a dictionary of text: widgets. To add your widget, import your widget into this file and add it to the dictionary with a useful name.
Examples are given in Typescript but the aim is to develop the project using prop-types which will make it fully interoperable with standard Javascript components.