Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
35 commits
Select commit Hold shift + click to select a range
5596f23
Replaced base input with MUI TextField
NatLeung96 Mar 31, 2025
f4c0b38
Updated branch with main-dev branch
NatLeung96 Apr 3, 2025
ebdb4b8
Updated theme tokens and changed border colours
NatLeung96 Apr 3, 2025
1de8ba7
Move static styling to styled API
NatLeung96 Apr 7, 2025
338fd16
Added alignment props to parser
NatLeung96 Apr 7, 2025
8640e8a
Handle alignment props
NatLeung96 Apr 7, 2025
6d2c240
Updated test and created snapshot
NatLeung96 Apr 7, 2025
5159245
Removed redundant input component files
NatLeung96 Apr 7, 2025
f106025
Removed redundant reference to component file
NatLeung96 Apr 7, 2025
6572c5c
Removed redundant horizontalAlignment and verticalAlignment props fro…
NatLeung96 Apr 10, 2025
eacf481
Added textAlignV as ChoicePropOpt and removed unnecessary switch stat…
NatLeung96 Apr 10, 2025
94ebd6f
Added if-else for vertical alignment
NatLeung96 Apr 10, 2025
0fd8d05
Changed default background to teal (#80FFFF)
NatLeung96 Apr 10, 2025
5d521d1
Removed redundant border parsing
NatLeung96 Apr 10, 2025
f455a35
Changed color of hover and focussed borders to blue
NatLeung96 Apr 10, 2025
88af1b9
Added custom border
NatLeung96 Apr 10, 2025
ecb81aa
Added multiLine to parser
NatLeung96 Apr 11, 2025
ec9ae54
Changed default blue border colour
NatLeung96 Apr 11, 2025
02ac247
TextField displays existing PV value if available
NatLeung96 Apr 11, 2025
71606cc
Reformatted prop type declaration and disabled cursor when disabled
NatLeung96 Apr 11, 2025
882d807
Updated tests, snapshots, and type definitions
NatLeung96 Apr 11, 2025
94a836e
Updated slidecontrol test
NatLeung96 Apr 11, 2025
eb34c0b
Updated input snapshot
NatLeung96 Apr 11, 2025
4244394
Corrected writePV function call
NatLeung96 Apr 11, 2025
960d50f
Removed redundant CSS file
NatLeung96 Apr 11, 2025
a67d8f1
Added blur on Enter
NatLeung96 Apr 11, 2025
4eeb112
Removed comment
NatLeung96 Apr 11, 2025
1d4fe41
Got border thicknesses to change on hover and focus
NatLeung96 Apr 11, 2025
a1f1f8f
Changed border width values for hover and focussed
NatLeung96 Apr 11, 2025
f682060
Updated snapshot
NatLeung96 Apr 11, 2025
4c714a3
Reorganised widgetprop definitions and updated test
NatLeung96 Apr 14, 2025
e756812
Added useEffect to set initial text value when PV connection is estab…
NatLeung96 Apr 14, 2025
cff1723
Updated pvName variable in slideControl
NatLeung96 Apr 14, 2025
d9b81b0
Updated slideControl test
NatLeung96 Apr 14, 2025
60647dd
Added multiline functionality
NatLeung96 Apr 14, 2025
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 0 additions & 1 deletion src/index.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,6 @@
export * from "./redux";
export * from "./misc";
export * from "./connection";
export * from "./ui/components";
export * from "./ui/widgets";
export * from "./ui/hooks";
export * from "./types";
Expand Down
1 change: 0 additions & 1 deletion src/ui/components/index.ts

This file was deleted.

51 changes: 0 additions & 51 deletions src/ui/components/input/input.tsx

This file was deleted.

3 changes: 2 additions & 1 deletion src/ui/widgets/EmbeddedDisplay/bobParser.ts
Original file line number Diff line number Diff line change
Expand Up @@ -380,7 +380,8 @@ export function parseBob(
rotation: ["rotation", bobParseNumber],
styleOpt: ["style", bobParseNumber],
lineColor: ["line_color", opiParseColor],
rotationStep: ["rotation_step", bobParseNumber]
rotationStep: ["rotation_step", bobParseNumber],
multiLine: ["multi_line", opiParseBoolean]
};

const complexParsers = {
Expand Down
35 changes: 35 additions & 0 deletions src/ui/widgets/Input/__snapshots__/input.test.tsx.snap
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
// Vitest Snapshot v1, https://vitest.dev/guide/snapshot.html

exports[`<Input /> > renders an input 1`] = `
<DocumentFragment>
<div
class="MuiFormControl-root MuiTextField-root css-1x2hah6-MuiFormControl-root-MuiTextField-root"
>
<div
class="MuiInputBase-root MuiOutlinedInput-root MuiInputBase-colorPrimary MuiInputBase-formControl css-quhxjy-MuiInputBase-root-MuiOutlinedInput-root"
>
<input
aria-invalid="false"
class="MuiInputBase-input MuiOutlinedInput-input css-16wblaj-MuiInputBase-input-MuiOutlinedInput-input"
id=":r0:"
type="text"
value="hello"
/>
<fieldset
aria-hidden="true"
class="MuiOutlinedInput-notchedOutline css-1ll44ll-MuiOutlinedInput-notchedOutline"
>
<legend
class="css-w4cd9x"
>
<span
class="notranslate"
>
</span>
</legend>
</fieldset>
</div>
</div>
</DocumentFragment>
`;
14 changes: 0 additions & 14 deletions src/ui/widgets/Input/input.module.css

This file was deleted.

8 changes: 2 additions & 6 deletions src/ui/widgets/Input/input.test.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,6 @@ import { DAlarm } from "../../../types/dtypes";
import { dstring } from "../../../testResources";

let input: JSX.Element;

beforeEach((): void => {
input = (
<SmartInputComponent
Expand All @@ -19,10 +18,7 @@ beforeEach((): void => {
});
describe("<Input />", (): void => {
it("renders an input", (): void => {
const { getByDisplayValue } = render(input);
const renderedInput = getByDisplayValue("hello");
expect(renderedInput).toBeInTheDocument();
expect(renderedInput).toHaveStyle("color: var(--warning)");
expect(renderedInput.className).toContain("readonly");
const { asFragment } = render(input);
expect(asFragment()).toMatchSnapshot();
});
});
213 changes: 139 additions & 74 deletions src/ui/widgets/Input/input.tsx
Original file line number Diff line number Diff line change
@@ -1,102 +1,167 @@
import React from "react";
import React, { useEffect, useState } from "react";

import classes from "./input.module.css";
import { writePv } from "../../hooks/useSubscription";
import { commonCss, Widget } from "../widget";
import { Widget } from "../widget";
import { PVInputComponent, PVWidgetPropType } from "../widgetProps";
import { registerWidget } from "../register";
import {
InferWidgetProps,
FontPropOpt,
ChoicePropOpt,
ColorPropOpt,
BoolPropOpt
BoolPropOpt,
BorderPropOpt,
StringPropOpt
} from "../propTypes";
import { Font } from "../../../types/font";
import { Color } from "../../../types/color";
import { AlarmQuality, DType } from "../../../types/dtypes";
import { InputComponent } from "../../components/input/input";
import { TextField as MuiTextField, styled } from "@mui/material";
import { diamondTheme } from "../../../diamondTheme";

export interface InputProps {
pvName: string;
value: string;
readonly: boolean;
foregroundColor?: Color;
backgroundColor?: Color;
transparent: boolean;
alarm: AlarmQuality;
alarmSensitive: boolean;
onKeyDown: (event: React.KeyboardEvent<HTMLInputElement>) => void;
onChange: (event: React.ChangeEvent<HTMLInputElement>) => void;
onBlur: (event: React.ChangeEvent<HTMLInputElement>) => void;
onClick: (event: React.MouseEvent<HTMLInputElement>) => void;
font?: Font;
textAlign?: "left" | "center" | "right";
}
const InputComponentProps = {
pvName: StringPropOpt,
font: FontPropOpt,
foregroundColor: ColorPropOpt,
backgroundColor: ColorPropOpt,
transparent: BoolPropOpt,
alarmSensitive: BoolPropOpt,
enabled: BoolPropOpt,
textAlign: ChoicePropOpt(["left", "center", "right"]),
textAlignV: ChoicePropOpt(["top", "center", "bottom"]),
border: BorderPropOpt,
multiLine: BoolPropOpt
};

export const SmartInputComponent = (
props: PVInputComponent & {
font?: Font;
foregroundColor?: Color;
backgroundColor?: Color;
transparent?: boolean;
alarmSensitive?: boolean;
textAlign?: "left" | "center" | "right";
const TextField = styled(MuiTextField)({
"&.MuiFormControl-root": {
height: "100%",
width: "100%",
display: "block"
},
"& .MuiInputBase-root": {
height: "100%",
width: "100%"
},
"& .MuiOutlinedInput-root": {
"&:hover fieldset": {
borderWidth: "1px",
borderColor: "#1976D2"
},
"&.Mui-focused fieldset": {
borderWidth: "2px",
borderColor: "#1976D2"
},
"&.Mui-disabled": {
cursor: "not-allowed",
pointerEvents: "all !important"
}
}
});

export const SmartInputComponent = (
props: PVInputComponent & InferWidgetProps<typeof InputComponentProps>
): JSX.Element => {
const {
enabled = true,
transparent = false,
textAlign = "left",
textAlignV = "center",
value = null,
multiLine = false
} = props;

const font = props.font?.css() ?? diamondTheme.typography;

const alarmQuality = props.value?.getAlarm().quality ?? AlarmQuality.VALID;
let allClasses = classes.Input;
const style = commonCss(props);
if (props.textAlign) {
style.textAlign = props.textAlign;
}
style.color = props.foregroundColor?.toString();
style.backgroundColor = props.backgroundColor?.toString();
// Transparent prop overrides backgroundColor.
if (props.transparent) {
style["backgroundColor"] = "transparent";
}
if (props.readonly) {
allClasses += ` ${classes.readonly}`;
const foregroundColor = props.alarmSensitive
? function () {
switch (alarmQuality) {
case AlarmQuality.UNDEFINED:
case AlarmQuality.INVALID:
case AlarmQuality.CHANGING:
return "var(--invalid)";
case AlarmQuality.WARNING:
return "var(--alarm)";
case AlarmQuality.ALARM:
return "var(--alarm)";
case AlarmQuality.VALID:
return (
props.foregroundColor?.toString() ??
diamondTheme.palette.primary.contrastText
);
}
}
: (props.foregroundColor?.toString() ??
diamondTheme.palette.primary.contrastText);

let alignmentV = "center";
if (textAlignV === "top") {
alignmentV = "start";
} else if (textAlignV === "bottom") {
alignmentV = "end";
}
if (props.alarmSensitive) {
switch (alarmQuality) {
case AlarmQuality.UNDEFINED:
case AlarmQuality.INVALID:
case AlarmQuality.CHANGING:
style.color = "var(--invalid)";
break;
case AlarmQuality.WARNING:
style.color = "var(--alarm)";
break;
case AlarmQuality.ALARM:
style.color = "var(--alarm)";
break;

const backgroundColor = transparent
? "transparent"
: (props.backgroundColor?.toString() ?? "#80FFFF");

const [inputValue, setInputValue] = useState(value?.getStringValue() ?? "");

useEffect(() => {
if (value) {
setInputValue(value.getStringValue() ?? "");
}
}
function onEnter(value: string): void {
writePv(props.pvName, new DType({ stringValue: value }));
}
}, [value]);

const onKeyPress = (event: React.KeyboardEvent<HTMLInputElement>) => {
if (multiLine) {
if (event.key === "Enter" && event.ctrlKey) {
writePv(props.pvName, new DType({ stringValue: inputValue }));
event.currentTarget.blur();
}
} else {
if (event.key === "Enter") {
writePv(props.pvName, new DType({ stringValue: inputValue }));
event.currentTarget.blur();
}
}
};

return (
<InputComponent
value={DType.coerceString(props.value)}
readonly={props.readonly}
onEnter={onEnter}
style={style}
className={allClasses}
<TextField
disabled={!enabled}
value={inputValue}
multiline={multiLine}
variant="outlined"
type="text"
slotProps={{
input: {
onKeyDown: onKeyPress
}
}}
onChange={event => setInputValue(event.target.value)}
sx={{
"& .MuiInputBase-input": {
textAlign: textAlign,
padding: "4px",
fontFamily: font
},
"& .MuiInputBase-root": {
alignItems: alignmentV,
color: foregroundColor,
backgroundColor: backgroundColor
},
"& fieldset": {
borderWidth: props.border?.width ?? "0px",
borderColor: props.border?.color.toString() ?? "#0000003B"
}
}}
/>
);
};

const InputWidgetProps = {
...PVWidgetPropType,
font: FontPropOpt,
foregroundColor: ColorPropOpt,
backgroundColor: ColorPropOpt,
transparent: BoolPropOpt,
alarmSensitive: BoolPropOpt,
textAlign: ChoicePropOpt(["left", "center", "right"])
...InputComponentProps,
...PVWidgetPropType
};

export const Input = (
Expand Down
2 changes: 1 addition & 1 deletion src/ui/widgets/SlideControl/slideControl.test.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ test("slideControl", () => {
value={ddouble(5)}
connected={true}
readonly={false}
pvName="dummy"
pvName="pv"
max={10}
min={0}
></SlideControlComponent>
Expand Down