2022-10-25 18:26:48 +00:00
|
|
|
import { PrimitiveAtom, useAtom } from "jotai";
|
|
|
|
import { SyntheticEvent, useState } from "react";
|
2022-10-24 07:40:14 +00:00
|
|
|
import styled from "styled-components";
|
2022-10-24 07:10:52 +00:00
|
|
|
|
2022-10-25 18:26:48 +00:00
|
|
|
export interface Props<T> {
|
|
|
|
valueAtom: PrimitiveAtom<T>;
|
2022-10-24 19:00:16 +00:00
|
|
|
formatter?: (arg: T) => string;
|
|
|
|
inputType?: string;
|
|
|
|
validator: (arg: string) => T | null;
|
2022-10-24 07:18:22 +00:00
|
|
|
}
|
|
|
|
|
2022-10-24 07:40:14 +00:00
|
|
|
const ClickableContainer = styled.span`
|
2022-10-24 08:49:22 +00:00
|
|
|
display: inline-block;
|
|
|
|
padding: 4px 10px;
|
|
|
|
margin: 4px;
|
|
|
|
border: 1px solid #eee;
|
|
|
|
border-radius: 5px;
|
|
|
|
|
2022-10-24 07:40:14 +00:00
|
|
|
&:hover {
|
|
|
|
background-color: #eee;
|
|
|
|
}
|
|
|
|
`;
|
|
|
|
|
2022-10-24 08:49:22 +00:00
|
|
|
const EditingBox = styled.input`
|
|
|
|
display: inline-block;
|
|
|
|
padding: 4px 10px;
|
|
|
|
margin: 4px;
|
|
|
|
border: 1px solid #eee;
|
|
|
|
border-radius: 5px;
|
|
|
|
`;
|
|
|
|
|
2022-10-25 18:26:48 +00:00
|
|
|
export default function EditBox<T>({
|
2022-10-24 19:00:16 +00:00
|
|
|
valueAtom,
|
|
|
|
formatter,
|
|
|
|
inputType,
|
|
|
|
validator,
|
|
|
|
}: Props<T>) {
|
2022-10-24 07:10:52 +00:00
|
|
|
const [value, setValue] = useAtom(valueAtom);
|
|
|
|
const [valueInput, setValueInput] = useState("");
|
|
|
|
const [editing, setEditing] = useState(false);
|
|
|
|
|
2022-10-24 07:18:22 +00:00
|
|
|
const startEditing = (_: any) => {
|
2022-10-25 18:26:48 +00:00
|
|
|
setValueInput(String(value));
|
2022-10-24 07:10:52 +00:00
|
|
|
setEditing(true);
|
|
|
|
};
|
|
|
|
|
2022-10-25 18:26:48 +00:00
|
|
|
const finalize = (e: SyntheticEvent) => {
|
2022-10-24 07:10:52 +00:00
|
|
|
e.preventDefault();
|
2022-10-24 19:00:16 +00:00
|
|
|
const validateResult = validator(valueInput);
|
|
|
|
if (validateResult !== null) {
|
|
|
|
setValue(validateResult);
|
2022-10-24 07:10:52 +00:00
|
|
|
setEditing(false);
|
|
|
|
}
|
|
|
|
};
|
|
|
|
|
|
|
|
if (editing) {
|
|
|
|
return (
|
|
|
|
<form onSubmit={finalize} style={{ display: "inline" }}>
|
2022-10-24 08:49:22 +00:00
|
|
|
<EditingBox
|
2022-10-24 07:10:52 +00:00
|
|
|
autoFocus={true}
|
2022-10-24 19:00:16 +00:00
|
|
|
type={inputType ?? "text"}
|
2022-10-24 07:10:52 +00:00
|
|
|
step="0.01"
|
|
|
|
value={valueInput}
|
|
|
|
onBlur={finalize}
|
2022-10-25 18:26:48 +00:00
|
|
|
onInput={(e) => setValueInput(e.currentTarget.value)}
|
2022-10-24 07:10:52 +00:00
|
|
|
/>
|
|
|
|
</form>
|
|
|
|
);
|
|
|
|
} else {
|
2022-10-24 07:40:14 +00:00
|
|
|
return (
|
|
|
|
<ClickableContainer onClick={startEditing}>
|
2022-10-25 18:26:48 +00:00
|
|
|
{formatter ? formatter(value) : String(value)}
|
2022-10-24 07:40:14 +00:00
|
|
|
</ClickableContainer>
|
|
|
|
);
|
2022-10-24 07:10:52 +00:00
|
|
|
}
|
|
|
|
}
|