mirror of
https://github.com/rowyio/rowy.git
synced 2025-12-29 00:16:39 +01:00
migrate from @material-ui/pickers to @mui/lab
This commit is contained in:
@@ -1,16 +1,13 @@
|
||||
import { useTheme } from "@mui/material";
|
||||
import { Skeleton } from "@mui/material";
|
||||
import { SkeletonProps } from "@mui/lab";
|
||||
import { Skeleton, SkeletonProps } from "@mui/material";
|
||||
|
||||
export default function FieldSkeleton(props: SkeletonProps) {
|
||||
const theme = useTheme();
|
||||
return (
|
||||
<Skeleton
|
||||
variant="rectangular"
|
||||
width="100%"
|
||||
height={56}
|
||||
height={32}
|
||||
animation="wave"
|
||||
style={{ borderRadius: theme.shape.borderRadius }}
|
||||
sx={{ borderRadius: 1 }}
|
||||
{...props}
|
||||
/>
|
||||
);
|
||||
|
||||
@@ -73,7 +73,7 @@ export default function Form({ values }: IFormProps) {
|
||||
getValues={getValues}
|
||||
/>
|
||||
|
||||
<Grid container spacing={4} direction="column" wrap="nowrap">
|
||||
<Grid container spacing={3} direction="column" wrap="nowrap">
|
||||
{fields.map((field, i) => {
|
||||
// Derivative/aggregate field support
|
||||
let type = field.type;
|
||||
|
||||
@@ -23,7 +23,7 @@ export const useFieldStyles = makeStyles((theme) =>
|
||||
createStyles({
|
||||
root: {
|
||||
borderRadius: theme.shape.borderRadius,
|
||||
padding: theme.spacing(0.75, 1, 0.75, 1.5),
|
||||
padding: theme.spacing(0.5, 1),
|
||||
|
||||
backgroundColor: theme.palette.action.input,
|
||||
boxShadow: `0 0 0 1px ${
|
||||
|
||||
@@ -24,9 +24,7 @@ export default function EmptyTable() {
|
||||
<Typography>
|
||||
There is existing data in the Firestore collection:
|
||||
<br />
|
||||
<Typography component="span" sx={{ fontFamily: "mono" }}>
|
||||
{tableState?.tablePath}
|
||||
</Typography>
|
||||
<code>{tableState?.tablePath}</code>
|
||||
</Typography>
|
||||
</div>
|
||||
|
||||
@@ -58,9 +56,7 @@ export default function EmptyTable() {
|
||||
<Typography>
|
||||
There is no data in the Firestore collection:
|
||||
<br />
|
||||
<Typography component="span" sx={{ fontFamily: "mono" }}>
|
||||
{tableState?.tablePath}
|
||||
</Typography>
|
||||
<code>{tableState?.tablePath}</code>
|
||||
</Typography>
|
||||
</div>
|
||||
|
||||
@@ -139,7 +135,6 @@ export default function EmptyTable() {
|
||||
maxWidth: 480,
|
||||
margin: "0 auto",
|
||||
textAlign: "center",
|
||||
userSelect: "none",
|
||||
}}
|
||||
>
|
||||
{contents}
|
||||
|
||||
@@ -79,11 +79,10 @@ export const useStyles = makeStyles((theme) =>
|
||||
position: "relative",
|
||||
},
|
||||
|
||||
"& .rdg-cell-frozen": {
|
||||
position: "sticky",
|
||||
},
|
||||
"& .rdg-cell-frozen-last": {
|
||||
// boxShadow:
|
||||
// theme.palette.mode === "light"
|
||||
// ? "2px 0 4px 0px rgba(0, 0, 0, .08)"
|
||||
// : "2px 0 4px 0px rgba(0, 0, 0, .67)",
|
||||
boxShadow: theme.shadows[2]
|
||||
.replace(/, 0 (\d+px)/g, ", $1 0")
|
||||
.split("),")
|
||||
@@ -144,8 +143,8 @@ export const useStyles = makeStyles((theme) =>
|
||||
},
|
||||
|
||||
".cell-collapse-padding": {
|
||||
margin: theme.spacing(0, -1.5),
|
||||
width: `calc(100% + ${theme.spacing(3)})`,
|
||||
margin: theme.spacing(0, -1.25),
|
||||
width: `calc(100% + ${theme.spacing(1.25 * 2)})`,
|
||||
},
|
||||
},
|
||||
})
|
||||
|
||||
@@ -1,17 +1,16 @@
|
||||
import { IBasicCellProps } from "../types";
|
||||
import { format } from "date-fns";
|
||||
import { DATE_FORMAT } from "constants/dates";
|
||||
import { DateIcon } from ".";
|
||||
|
||||
export default function Date_({ value }: IBasicCellProps) {
|
||||
export default function Date_({
|
||||
value,
|
||||
format: formatProp,
|
||||
}: IBasicCellProps & { format?: string }) {
|
||||
if (!!value && "toDate" in value) {
|
||||
try {
|
||||
const formatted = format(value.toDate(), DATE_FORMAT);
|
||||
const formatted = format(value.toDate(), formatProp || DATE_FORMAT);
|
||||
return (
|
||||
<>
|
||||
<DateIcon style={{ marginRight: 5 }} />
|
||||
{formatted}
|
||||
</>
|
||||
<span style={{ fontVariantNumeric: "tabular-nums" }}>{formatted}</span>
|
||||
);
|
||||
} catch (e) {
|
||||
return null;
|
||||
|
||||
@@ -1,20 +1,39 @@
|
||||
import { ISettingsProps } from "../types";
|
||||
|
||||
import Subheading from "components/Table/ColumnMenu/Subheading";
|
||||
import { Typography, Link } from "@mui/material";
|
||||
import InlineOpenInNewIcon from "components/InlineOpenInNewIcon";
|
||||
|
||||
import MultiSelect from "@rowy/multiselect";
|
||||
import { DATE_FORMAT } from "constants/dates";
|
||||
import { EXTERNAL_LINKS } from "constants/externalLinks";
|
||||
|
||||
export default function Settings({ handleChange, config }: ISettingsProps) {
|
||||
return (
|
||||
<>
|
||||
<Subheading>Date Config</Subheading>
|
||||
<MultiSelect
|
||||
options={["yyyy/MM/dd", "dd/MM/yyyy", "MM/dd/yyyy"]}
|
||||
options={[DATE_FORMAT, "yyyy/MM/dd", "dd/MM/yyyy", "MM/dd/yyyy"]}
|
||||
itemRenderer={(option) => (
|
||||
<Typography sx={{ fontFamily: "mono" }}>{option.label}</Typography>
|
||||
)}
|
||||
label="Format"
|
||||
freeText={false}
|
||||
multiple={false}
|
||||
freeText
|
||||
clearable={false}
|
||||
searchable={false}
|
||||
value={config.format ?? DATE_FORMAT}
|
||||
onChange={handleChange("format")}
|
||||
multiple={false}
|
||||
TextFieldProps={{
|
||||
helperText: (
|
||||
<Link
|
||||
href={EXTERNAL_LINKS.dateFormat}
|
||||
target="_blank"
|
||||
rel="noopener noreferrer"
|
||||
>
|
||||
Date format reference
|
||||
<InlineOpenInNewIcon />
|
||||
</Link>
|
||||
),
|
||||
}}
|
||||
/>
|
||||
</>
|
||||
);
|
||||
|
||||
@@ -1,58 +1,68 @@
|
||||
import { Controller } from "react-hook-form";
|
||||
import { ISideDrawerFieldProps } from "../types";
|
||||
|
||||
import { useTheme } from "@mui/material";
|
||||
import LocalizationProvider from "@mui/lab/LocalizationProvider";
|
||||
import AdapterDateFns from "@mui/lab/AdapterDateFns";
|
||||
import DatePicker from "@mui/lab/DatePicker";
|
||||
import { TextField } from "@mui/material";
|
||||
|
||||
import { transformValue, sanitizeValue } from "./utils";
|
||||
import { DATE_FORMAT } from "constants/dates";
|
||||
import { DateIcon } from ".";
|
||||
|
||||
export interface IDateProps extends ISideDrawerFieldProps {}
|
||||
|
||||
export default function Date_({ column, control }: IDateProps) {
|
||||
const theme = useTheme();
|
||||
const format = column.config?.format ?? DATE_FORMAT;
|
||||
|
||||
return (
|
||||
<LocalizationProvider dateAdapter={AdapterDateFns}>
|
||||
<Controller
|
||||
control={control}
|
||||
name={column.key}
|
||||
render={({ onChange, value }) => {
|
||||
const transformedValue = transformValue(value);
|
||||
<Controller
|
||||
control={control}
|
||||
name={column.key}
|
||||
render={({ onChange, value }) => {
|
||||
const transformedValue = transformValue(value);
|
||||
|
||||
const handleChange = (date: Date | null) => {
|
||||
const sanitized = sanitizeValue(date);
|
||||
if (sanitized === undefined) return;
|
||||
onChange(sanitized);
|
||||
};
|
||||
const handleChange = (date: Date | null) => {
|
||||
const sanitized = sanitizeValue(date);
|
||||
if (sanitized === undefined) return;
|
||||
onChange(sanitized);
|
||||
};
|
||||
|
||||
return <></>;
|
||||
// TODO:
|
||||
// <DatePicker
|
||||
// inputFormat={column.config?.format ?? DATE_FORMAT}
|
||||
// {...props}
|
||||
// renderInput={(props) => (
|
||||
// <TextField
|
||||
// {...props}
|
||||
// fullWidth
|
||||
// margin="none"
|
||||
// placeholder={column.config?.format ?? DATE_FORMAT}
|
||||
// // TODO: InputAdornmentProps={{
|
||||
// // style: { marginRight: theme.spacing(-1) },
|
||||
// // }}
|
||||
// // TODO: move this out to side drawer
|
||||
// id={`sidedrawer-field-${column.key}`}
|
||||
// onBlur={onBlur}
|
||||
// label=""
|
||||
// hiddenLabel
|
||||
// />
|
||||
// )}
|
||||
// value={transformedValue}
|
||||
// onChange={handleChange}
|
||||
// disabled={disabled}
|
||||
// />
|
||||
}}
|
||||
/>
|
||||
</LocalizationProvider>
|
||||
return (
|
||||
<DatePicker
|
||||
renderInput={(props) => (
|
||||
<TextField
|
||||
{...props}
|
||||
fullWidth
|
||||
label=""
|
||||
hiddenLabel
|
||||
aria-label={column.name as string}
|
||||
InputProps={{
|
||||
...props.InputProps,
|
||||
endAdornment: props.InputProps?.endAdornment || (
|
||||
<DateIcon color="action" />
|
||||
),
|
||||
}}
|
||||
sx={{
|
||||
"& .MuiInputBase-input": {
|
||||
fontVariantNumeric: "tabular-nums",
|
||||
},
|
||||
"& .MuiInputAdornment-root": { m: 0 },
|
||||
}}
|
||||
// Touch mode: make the whole field clickable
|
||||
onClick={props.inputProps?.onClick as any}
|
||||
/>
|
||||
)}
|
||||
label={column.name}
|
||||
value={transformedValue}
|
||||
onChange={handleChange}
|
||||
inputFormat={format}
|
||||
mask={format.replace(/[A-Za-z]/g, "_")}
|
||||
clearable
|
||||
OpenPickerButtonProps={{ size: "small" }}
|
||||
components={{ OpenPickerIcon: DateIcon }}
|
||||
disableOpenPicker={false}
|
||||
/>
|
||||
);
|
||||
}}
|
||||
/>
|
||||
);
|
||||
}
|
||||
|
||||
@@ -1,124 +1,115 @@
|
||||
import { useDebouncedCallback } from "use-debounce";
|
||||
import { IHeavyCellProps } from "../types";
|
||||
|
||||
import { makeStyles, createStyles } from "@mui/styles";
|
||||
import MobileDatePicker from "@mui/lab/MobileDatePicker";
|
||||
import DatePicker from "@mui/lab/DatePicker";
|
||||
import { TextField } from "@mui/material";
|
||||
|
||||
import { transformValue } from "./utils";
|
||||
|
||||
// import DateFnsUtils from "@date-io/date-fns";
|
||||
// import {
|
||||
// MuiPickersUtilsProvider,
|
||||
// KeyboardDatePicker,
|
||||
// DatePickerProps,
|
||||
// } from "@material-ui/pickers";
|
||||
|
||||
import { useProjectContext } from "contexts/ProjectContext";
|
||||
import { transformValue, sanitizeValue } from "./utils";
|
||||
import { DATE_FORMAT } from "constants/dates";
|
||||
import BasicCell from "./BasicCell";
|
||||
import { DateIcon } from ".";
|
||||
|
||||
const useStyles = makeStyles((theme) =>
|
||||
createStyles({
|
||||
root: { height: "100%" },
|
||||
inputBase: {
|
||||
height: "100%",
|
||||
color: "inherit",
|
||||
},
|
||||
|
||||
inputAdornment: {
|
||||
height: "100%",
|
||||
marginLeft: theme.spacing(9 / 8),
|
||||
marginRight: theme.spacing(0.25),
|
||||
},
|
||||
|
||||
input: {
|
||||
...theme.typography.body2,
|
||||
fontSize: "0.75rem",
|
||||
color: "inherit",
|
||||
height: "100%",
|
||||
padding: theme.spacing(1.5, 0),
|
||||
},
|
||||
|
||||
dateTabIcon: {
|
||||
color: theme.palette.primary.contrastText,
|
||||
},
|
||||
|
||||
disabledCell: {
|
||||
color: theme.palette.text.disabled,
|
||||
display: "flex",
|
||||
alignItems: "center",
|
||||
},
|
||||
})
|
||||
);
|
||||
|
||||
export default function Date_({ column, value, disabled }: IHeavyCellProps) {
|
||||
const classes = useStyles();
|
||||
const { updateCell } = useProjectContext();
|
||||
|
||||
export default function Date_({
|
||||
column,
|
||||
value,
|
||||
disabled,
|
||||
onSubmit,
|
||||
}: IHeavyCellProps) {
|
||||
const format = column.config?.format ?? DATE_FORMAT;
|
||||
const transformedValue = transformValue(value);
|
||||
|
||||
// const [handleDateChange] = useDebouncedCallback<DatePickerProps["onChange"]>(
|
||||
// (date) => {
|
||||
// const sanitized = sanitizeValue(date);
|
||||
// if (sanitized === undefined) return;
|
||||
|
||||
// onSubmit(sanitized);
|
||||
// if (dataGridRef?.current?.selectCell)
|
||||
// dataGridRef.current.selectCell({ rowIdx, idx: column.idx });
|
||||
// },
|
||||
// 500
|
||||
// );
|
||||
const [handleDateChange] = useDebouncedCallback((date: Date | null) => {
|
||||
const sanitized = sanitizeValue(date);
|
||||
if (sanitized === undefined) return;
|
||||
onSubmit(sanitized);
|
||||
}, 500);
|
||||
|
||||
if (disabled)
|
||||
return (
|
||||
<div className={classes.disabledCell}>
|
||||
<BasicCell
|
||||
value={value}
|
||||
type={(column as any).type}
|
||||
name={column.key}
|
||||
/>
|
||||
</div>
|
||||
<BasicCell
|
||||
value={value}
|
||||
type={(column as any).type}
|
||||
name={column.key}
|
||||
format={format}
|
||||
/>
|
||||
);
|
||||
|
||||
return (
|
||||
<MobileDatePicker
|
||||
<DatePicker
|
||||
renderInput={(props) => (
|
||||
<TextField
|
||||
{...props}
|
||||
fullWidth
|
||||
variant="standard"
|
||||
label=""
|
||||
hiddenLabel
|
||||
aria-label={column.name as string}
|
||||
InputProps={{
|
||||
disableUnderline: true,
|
||||
classes: { root: classes.inputBase, input: classes.input },
|
||||
...props.InputProps,
|
||||
endAdornment: props.InputProps?.endAdornment || (
|
||||
<DateIcon
|
||||
className="row-hover-iconButton"
|
||||
sx={{
|
||||
borderRadius: 1,
|
||||
p: (32 - 24) / 2 / 8,
|
||||
boxSizing: "content-box",
|
||||
mr: 0.5,
|
||||
}}
|
||||
/>
|
||||
),
|
||||
}}
|
||||
// InputAdornmentProps={{
|
||||
// position: "start",
|
||||
// classes: { root: classes.inputAdornment },
|
||||
// }}
|
||||
className="cell-collapse-padding"
|
||||
sx={{
|
||||
width: "100%",
|
||||
height: "100%",
|
||||
|
||||
"& .MuiInputBase-root": {
|
||||
height: "100%",
|
||||
font: "inherit", // Prevent text jumping
|
||||
letterSpacing: "inherit", // Prevent text jumping
|
||||
|
||||
".rdg-cell &": {
|
||||
background: "none !important",
|
||||
boxShadow: "none",
|
||||
borderRadius: 0,
|
||||
padding: 0,
|
||||
|
||||
"&::after": { width: "100%", left: 0 },
|
||||
},
|
||||
},
|
||||
"& .MuiInputBase-input": {
|
||||
height: "100%",
|
||||
font: "inherit", // Prevent text jumping
|
||||
letterSpacing: "inherit", // Prevent text jumping
|
||||
fontVariantNumeric: "tabular-nums",
|
||||
|
||||
".rdg-cell &": {
|
||||
padding: "var(--cell-padding)",
|
||||
pr: 0,
|
||||
},
|
||||
},
|
||||
"& .MuiInputAdornment-root": { m: 0 },
|
||||
}}
|
||||
// Prevent react-data-grid showing NullEditor, which unmounts this field
|
||||
onDoubleClick={(e) => e.stopPropagation()}
|
||||
onKeyDown={(e) => e.stopPropagation()}
|
||||
// Touch mode: make the whole field clickable
|
||||
onClick={props.inputProps?.onClick as any}
|
||||
/>
|
||||
)}
|
||||
label={column.name}
|
||||
value={transformedValue}
|
||||
onChange={console.log}
|
||||
// onChange={handleDateChange}
|
||||
// onClick={(e) => e.stopPropagation()}
|
||||
// format={column.config?.format ?? DATE_FORMAT}
|
||||
onChange={handleDateChange}
|
||||
inputFormat={format}
|
||||
mask={format.replace(/[A-Za-z]/g, "_")}
|
||||
clearable
|
||||
// keyboardIcon={<DateIcon />}
|
||||
// className={clsx("cell-collapse-padding", classes.root)}
|
||||
// inputVariant="standard"
|
||||
// InputProps={{
|
||||
// disableUnderline: true,
|
||||
// classes: { root: classes.inputBase, input: classes.input },
|
||||
// }}
|
||||
// InputAdornmentProps={{
|
||||
// position: "start",
|
||||
// classes: { root: classes.inputAdornment },
|
||||
// }}
|
||||
// KeyboardButtonProps={{
|
||||
// size: "small",
|
||||
// classes: { root: !disabled ? "row-hover-iconButton" : undefined },
|
||||
// }}
|
||||
// DialogProps={{ onClick: (e) => e.stopPropagation() }}
|
||||
// disabled={disabled}
|
||||
OpenPickerButtonProps={{
|
||||
size: "small",
|
||||
className: "row-hover-iconButton",
|
||||
edge: false,
|
||||
sx: { mr: 0.5 },
|
||||
}}
|
||||
components={{ OpenPickerIcon: DateIcon }}
|
||||
disableOpenPicker={false}
|
||||
/>
|
||||
);
|
||||
}
|
||||
|
||||
@@ -3,6 +3,7 @@ import { IFieldConfig, FieldType } from "components/fields/types";
|
||||
import withHeavyCell from "../_withTableCell/withHeavyCell";
|
||||
import { parse, format } from "date-fns";
|
||||
import { DATE_FORMAT } from "constants/dates";
|
||||
|
||||
import DateIcon from "@mui/icons-material/TodayOutlined";
|
||||
import BasicCell from "./BasicCell";
|
||||
import NullEditor from "components/Table/editors/NullEditor";
|
||||
@@ -15,7 +16,7 @@ const SideDrawerField = lazy(
|
||||
import("./SideDrawerField" /* webpackChunkName: "SideDrawerField-Date" */)
|
||||
);
|
||||
const Settings = lazy(
|
||||
() => import("./Settings" /* webpackChunkName: "Settings-ConnectTable" */)
|
||||
() => import("./Settings" /* webpackChunkName: "Settings-Date" */)
|
||||
);
|
||||
|
||||
export const config: IFieldConfig = {
|
||||
@@ -26,8 +27,7 @@ export const config: IFieldConfig = {
|
||||
initialValue: null,
|
||||
initializable: true,
|
||||
icon: <DateIcon />,
|
||||
description:
|
||||
"Date displayed and input by default as YYYY/MM/DD or input using a picker module.",
|
||||
description: `Date displayed by default as ${DATE_FORMAT}.`,
|
||||
TableCell: withHeavyCell(BasicCell, TableCell),
|
||||
TableEditor: NullEditor as any,
|
||||
SideDrawerField,
|
||||
|
||||
@@ -1,17 +1,16 @@
|
||||
import { IBasicCellProps } from "../types";
|
||||
import { format } from "date-fns";
|
||||
import { DATE_TIME_FORMAT } from "constants/dates";
|
||||
import { DateTimeIcon } from ".";
|
||||
|
||||
export default function DateTime({ value }: IBasicCellProps) {
|
||||
export default function DateTime({
|
||||
value,
|
||||
format: formatProp,
|
||||
}: IBasicCellProps & { format?: string }) {
|
||||
if (!!value && "toDate" in value) {
|
||||
try {
|
||||
const formatted = format(value.toDate(), DATE_TIME_FORMAT);
|
||||
const formatted = format(value.toDate(), formatProp || DATE_TIME_FORMAT);
|
||||
return (
|
||||
<>
|
||||
<DateTimeIcon style={{ marginRight: 5 }} />
|
||||
{formatted}
|
||||
</>
|
||||
<span style={{ fontVariantNumeric: "tabular-nums" }}>{formatted}</span>
|
||||
);
|
||||
} catch (e) {
|
||||
return null;
|
||||
|
||||
46
src/components/fields/DateTime/Settings.tsx
Normal file
46
src/components/fields/DateTime/Settings.tsx
Normal file
@@ -0,0 +1,46 @@
|
||||
import { ISettingsProps } from "../types";
|
||||
|
||||
import { Typography, Link } from "@mui/material";
|
||||
import InlineOpenInNewIcon from "components/InlineOpenInNewIcon";
|
||||
|
||||
import MultiSelect from "@rowy/multiselect";
|
||||
import { DATE_TIME_FORMAT } from "constants/dates";
|
||||
import { EXTERNAL_LINKS } from "constants/externalLinks";
|
||||
|
||||
export default function Settings({ handleChange, config }: ISettingsProps) {
|
||||
return (
|
||||
<>
|
||||
<MultiSelect
|
||||
options={[
|
||||
DATE_TIME_FORMAT,
|
||||
"yyyy/MM/dd HH:mm",
|
||||
"dd/MM/yyyy HH:mm",
|
||||
"dd/MM/yyyy hh:mm aa",
|
||||
"MM/dd/yyyy hh:mm aa",
|
||||
]}
|
||||
itemRenderer={(option) => (
|
||||
<Typography sx={{ fontFamily: "mono" }}>{option.label}</Typography>
|
||||
)}
|
||||
label="Format"
|
||||
multiple={false}
|
||||
freeText
|
||||
clearable={false}
|
||||
searchable={false}
|
||||
value={config.format ?? DATE_TIME_FORMAT}
|
||||
onChange={handleChange("format")}
|
||||
TextFieldProps={{
|
||||
helperText: (
|
||||
<Link
|
||||
href={EXTERNAL_LINKS.dateFormat}
|
||||
target="_blank"
|
||||
rel="noopener noreferrer"
|
||||
>
|
||||
Date format reference
|
||||
<InlineOpenInNewIcon />
|
||||
</Link>
|
||||
),
|
||||
}}
|
||||
/>
|
||||
</>
|
||||
);
|
||||
}
|
||||
@@ -1,74 +1,68 @@
|
||||
import { Controller } from "react-hook-form";
|
||||
import { ISideDrawerFieldProps } from "../types";
|
||||
|
||||
import { useTheme } from "@mui/material";
|
||||
// import {
|
||||
// KeyboardDateTimePicker,
|
||||
// KeyboardDateTimePickerProps,
|
||||
// } from "@material-ui/pickers";
|
||||
import DatePicker from "@mui/lab/DatePicker";
|
||||
import { TextField } from "@mui/material";
|
||||
|
||||
// import { MuiPickersUtilsProvider } from "@material-ui/pickers";
|
||||
// import DateFnsUtils from "@date-io/date-fns";
|
||||
import { transformValue, sanitizeValue } from "../Date/utils";
|
||||
import { DATE_TIME_FORMAT } from "constants/dates";
|
||||
import { DateTimeIcon } from ".";
|
||||
|
||||
export interface IDateTimeProps extends ISideDrawerFieldProps {
|
||||
// ,Omit<
|
||||
// KeyboardDateTimePickerProps,
|
||||
// "name" | "onChange" | "value" | "disabled"
|
||||
// >
|
||||
}
|
||||
|
||||
export default function DateTime({}: IDateTimeProps) {
|
||||
const theme = useTheme();
|
||||
|
||||
return <></>;
|
||||
|
||||
// TODO: return (
|
||||
// <Controller
|
||||
// control={control}
|
||||
// name={column.key}
|
||||
// render={({ onChange, onBlur, value }) => {
|
||||
// const transformedValue = transformValue(value);
|
||||
|
||||
// const handleChange = (date: Date | null) => {
|
||||
// const sanitized = sanitizeValue(date);
|
||||
// if (sanitized === undefined) return;
|
||||
// onChange(sanitized);
|
||||
// };
|
||||
|
||||
// return (
|
||||
// <MuiPickersUtilsProvider utils={DateFnsUtils}>
|
||||
// <KeyboardDateTimePicker
|
||||
// variant="inline"
|
||||
// inputVariant="filled"
|
||||
// fullWidth
|
||||
// margin="none"
|
||||
// format={DATE_TIME_FORMAT}
|
||||
// placeholder={DATE_TIME_FORMAT}
|
||||
// InputAdornmentProps={{
|
||||
// style: { marginRight: theme.spacing(-1) },
|
||||
// }}
|
||||
// keyboardIcon={<TimeIcon />}
|
||||
// {...props}
|
||||
// value={transformedValue}
|
||||
// onChange={handleChange}
|
||||
// onBlur={onBlur}
|
||||
// label=""
|
||||
// hiddenLabel
|
||||
// id={`sidedrawer-field-${column.key}`}
|
||||
// dateRangeIcon={
|
||||
// <DateRangeIcon
|
||||
// style={{ color: theme.palette.primary.contrastText }}
|
||||
// />
|
||||
// }
|
||||
// timeIcon={
|
||||
// <TimeIcon
|
||||
// style={{ color: theme.palette.primary.contrastText }}
|
||||
// />
|
||||
// }
|
||||
// disabled={disabled}
|
||||
// />
|
||||
// </MuiPickersUtilsProvider>
|
||||
// );
|
||||
// }}
|
||||
// />
|
||||
// );
|
||||
export interface IDateProps extends ISideDrawerFieldProps {}
|
||||
|
||||
export default function Date_({ column, control }: IDateProps) {
|
||||
const format = column.config?.format ?? DATE_TIME_FORMAT;
|
||||
|
||||
return (
|
||||
<Controller
|
||||
control={control}
|
||||
name={column.key}
|
||||
render={({ onChange, value }) => {
|
||||
const transformedValue = transformValue(value);
|
||||
|
||||
const handleChange = (date: Date | null) => {
|
||||
const sanitized = sanitizeValue(date);
|
||||
if (sanitized === undefined) return;
|
||||
onChange(sanitized);
|
||||
};
|
||||
|
||||
return (
|
||||
<DatePicker
|
||||
renderInput={(props) => (
|
||||
<TextField
|
||||
{...props}
|
||||
fullWidth
|
||||
label=""
|
||||
hiddenLabel
|
||||
aria-label={column.name as string}
|
||||
InputProps={{
|
||||
...props.InputProps,
|
||||
endAdornment: props.InputProps?.endAdornment || (
|
||||
<DateTimeIcon color="action" />
|
||||
),
|
||||
}}
|
||||
sx={{
|
||||
"& .MuiInputBase-input": {
|
||||
fontVariantNumeric: "tabular-nums",
|
||||
},
|
||||
"& .MuiInputAdornment-root": { m: 0 },
|
||||
}}
|
||||
// Touch mode: make the whole field clickable
|
||||
onClick={props.inputProps?.onClick as any}
|
||||
/>
|
||||
)}
|
||||
label={column.name}
|
||||
value={transformedValue}
|
||||
onChange={handleChange}
|
||||
inputFormat={format}
|
||||
mask={format.replace(/[A-Za-z]/g, "_")}
|
||||
clearable
|
||||
OpenPickerButtonProps={{ size: "small" }}
|
||||
components={{ OpenPickerIcon: DateTimeIcon }}
|
||||
disableOpenPicker={false}
|
||||
/>
|
||||
);
|
||||
}}
|
||||
/>
|
||||
);
|
||||
}
|
||||
|
||||
@@ -1,105 +1,116 @@
|
||||
import { useDebouncedCallback } from "use-debounce";
|
||||
import { IHeavyCellProps } from "../types";
|
||||
|
||||
import { makeStyles, createStyles } from "@mui/styles";
|
||||
import DateTimePicker from "@mui/lab/MobileDateTimePicker";
|
||||
import { TextField } from "@mui/material";
|
||||
|
||||
import { transformValue } from "../Date/utils";
|
||||
|
||||
// import {
|
||||
// MuiPickersUtilsProvider,
|
||||
// KeyboardDateTimePicker,
|
||||
// DatePickerProps,
|
||||
// } from "@material-ui/pickers";
|
||||
|
||||
import { useProjectContext } from "contexts/ProjectContext";
|
||||
import { transformValue, sanitizeValue } from "../Date/utils";
|
||||
import { DATE_TIME_FORMAT } from "constants/dates";
|
||||
import BasicCell from "./BasicCell";
|
||||
import { DateTimeIcon } from ".";
|
||||
|
||||
const useStyles = makeStyles((theme) =>
|
||||
createStyles({
|
||||
root: { height: "100%" },
|
||||
inputBase: {
|
||||
height: "100%",
|
||||
color: "inherit",
|
||||
},
|
||||
|
||||
inputAdornment: {
|
||||
height: "100%",
|
||||
marginLeft: theme.spacing(9 / 8),
|
||||
marginRight: theme.spacing(0.25),
|
||||
},
|
||||
|
||||
input: {
|
||||
...theme.typography.body2,
|
||||
fontSize: "0.75rem",
|
||||
color: "inherit",
|
||||
height: "100%",
|
||||
padding: theme.spacing(1.5, 0),
|
||||
},
|
||||
|
||||
dateTabIcon: {
|
||||
color: theme.palette.primary.contrastText,
|
||||
},
|
||||
|
||||
disabledCell: {
|
||||
color: theme.palette.text.disabled,
|
||||
display: "flex",
|
||||
alignItems: "center",
|
||||
},
|
||||
})
|
||||
);
|
||||
|
||||
export default function DateTime({ column, value }: IHeavyCellProps) {
|
||||
const classes = useStyles();
|
||||
const {} = useProjectContext();
|
||||
|
||||
export default function DateTime({
|
||||
column,
|
||||
value,
|
||||
disabled,
|
||||
onSubmit,
|
||||
}: IHeavyCellProps) {
|
||||
const transformedValue = transformValue(value);
|
||||
|
||||
// const [handleDateChange] = useDebouncedCallback<DatePickerProps["onChange"]>(
|
||||
// (date) => {
|
||||
// const sanitized = sanitizeValue(date);
|
||||
// if (sanitized === undefined) return;
|
||||
const [handleDateChange] = useDebouncedCallback((date: Date | null) => {
|
||||
const sanitized = sanitizeValue(date);
|
||||
if (sanitized === undefined) return;
|
||||
onSubmit(sanitized);
|
||||
}, 500);
|
||||
|
||||
// onSubmit(sanitized);
|
||||
// if (dataGridRef?.current?.selectCell)
|
||||
// dataGridRef.current.selectCell({ rowIdx, idx: column.idx });
|
||||
// },
|
||||
// 500
|
||||
// );
|
||||
const format = column.config?.format ?? DATE_TIME_FORMAT;
|
||||
|
||||
if (disabled)
|
||||
return (
|
||||
<BasicCell
|
||||
value={value}
|
||||
type={(column as any).type}
|
||||
name={column.key}
|
||||
format={format}
|
||||
/>
|
||||
);
|
||||
|
||||
// if (disabled)
|
||||
return (
|
||||
<div className={classes.disabledCell}>
|
||||
<BasicCell value={value} type={(column as any).type} name={column.key} />
|
||||
</div>
|
||||
);
|
||||
<DateTimePicker
|
||||
renderInput={(props) => (
|
||||
<TextField
|
||||
{...props}
|
||||
fullWidth
|
||||
label=""
|
||||
hiddenLabel
|
||||
aria-label={column.name as string}
|
||||
InputProps={{
|
||||
...props.InputProps,
|
||||
endAdornment: props.InputProps?.endAdornment || (
|
||||
<DateTimeIcon
|
||||
className="row-hover-iconButton"
|
||||
sx={{
|
||||
borderRadius: 1,
|
||||
p: (32 - 24) / 2 / 8,
|
||||
boxSizing: "content-box",
|
||||
mr: 0.5,
|
||||
}}
|
||||
/>
|
||||
),
|
||||
}}
|
||||
className="cell-collapse-padding"
|
||||
sx={{
|
||||
width: "100%",
|
||||
height: "100%",
|
||||
|
||||
// return (
|
||||
// <MuiPickersUtilsProvider utils={DateFnsUtils}>
|
||||
// <KeyboardDateTimePicker
|
||||
// value={transformedValue}
|
||||
// onChange={handleDateChange}
|
||||
// onClick={(e) => e.stopPropagation()}
|
||||
// format={DATE_TIME_FORMAT}
|
||||
// fullWidth
|
||||
// clearable
|
||||
// keyboardIcon={<DateTimeIcon />}
|
||||
// className={clsx("cell-collapse-padding", classes.root)}
|
||||
// inputVariant="standard"
|
||||
// InputProps={{
|
||||
// disableUnderline: true,
|
||||
// classes: { root: classes.inputBase, input: classes.input },
|
||||
// }}
|
||||
// InputAdornmentProps={{
|
||||
// position: "start",
|
||||
// classes: { root: classes.inputAdornment },
|
||||
// }}
|
||||
// KeyboardButtonProps={{
|
||||
// size: "small",
|
||||
// classes: { root: "row-hover-iconButton" },
|
||||
// }}
|
||||
// DialogProps={{ onClick: (e) => e.stopPropagation() }}
|
||||
// dateRangeIcon={<DateRangeIcon className={classes.dateTabIcon} />}
|
||||
// timeIcon={<TimeIcon className={classes.dateTabIcon} />}
|
||||
// />
|
||||
// </MuiPickersUtilsProvider>
|
||||
// );
|
||||
"& .MuiInputBase-root": {
|
||||
height: "100%",
|
||||
font: "inherit", // Prevent text jumping
|
||||
letterSpacing: "inherit", // Prevent text jumping
|
||||
|
||||
".rdg-cell &": {
|
||||
background: "none !important",
|
||||
boxShadow: "none",
|
||||
borderRadius: 0,
|
||||
padding: 0,
|
||||
|
||||
"&::after": { width: "100%", left: 0 },
|
||||
},
|
||||
},
|
||||
"& .MuiInputBase-input": {
|
||||
height: "100%",
|
||||
font: "inherit", // Prevent text jumping
|
||||
letterSpacing: "inherit", // Prevent text jumping
|
||||
fontVariantNumeric: "tabular-nums",
|
||||
|
||||
".rdg-cell &": {
|
||||
padding: "var(--cell-padding)",
|
||||
pr: 0,
|
||||
},
|
||||
},
|
||||
"& .MuiInputAdornment-root": { m: 0 },
|
||||
}}
|
||||
// Prevent react-data-grid showing NullEditor, which unmounts this field
|
||||
onDoubleClick={(e) => e.stopPropagation()}
|
||||
onKeyDown={(e) => e.stopPropagation()}
|
||||
// Touch mode: make the whole field clickable
|
||||
onClick={props.inputProps?.onClick as any}
|
||||
/>
|
||||
)}
|
||||
label={column.name}
|
||||
value={transformedValue}
|
||||
onChange={handleDateChange}
|
||||
inputFormat={format}
|
||||
mask={format.replace(/[A-Za-z]/g, "_")}
|
||||
clearable
|
||||
OpenPickerButtonProps={{
|
||||
size: "small",
|
||||
className: "row-hover-iconButton",
|
||||
edge: false,
|
||||
sx: { mr: 0.5 },
|
||||
}}
|
||||
components={{ OpenPickerIcon: DateTimeIcon }}
|
||||
disableOpenPicker={false}
|
||||
/>
|
||||
);
|
||||
}
|
||||
|
||||
@@ -1,7 +1,8 @@
|
||||
import { lazy } from "react";
|
||||
import { IFieldConfig, FieldType } from "components/fields/types";
|
||||
import withHeavyCell from "../_withTableCell/withHeavyCell";
|
||||
import { parseJSON } from "date-fns";
|
||||
import { parseJSON, format } from "date-fns";
|
||||
import { DATE_TIME_FORMAT } from "constants/dates";
|
||||
|
||||
import DateTimeIcon from "@mui/icons-material/AccessTime";
|
||||
import BasicCell from "./BasicCell";
|
||||
@@ -16,21 +17,26 @@ const SideDrawerField = lazy(
|
||||
"./SideDrawerField" /* webpackChunkName: "SideDrawerField-DateTime" */
|
||||
)
|
||||
);
|
||||
const Settings = lazy(
|
||||
() => import("./Settings" /* webpackChunkName: "Settings-DateTime" */)
|
||||
);
|
||||
|
||||
export const config: IFieldConfig = {
|
||||
type: FieldType.dateTime,
|
||||
name: "Time & Date",
|
||||
name: "Date & Time",
|
||||
group: "Date & Time",
|
||||
dataType: "firebase.firestore.Timestamp",
|
||||
initialValue: null,
|
||||
initializable: true,
|
||||
icon: <DateTimeIcon />,
|
||||
description:
|
||||
"Time and Date can be written as YYYY/MM/DD hh:mm (am/pm) or input using a picker module.",
|
||||
description: `Date & Time displayed by default as ${DATE_TIME_FORMAT}.`,
|
||||
TableCell: withHeavyCell(BasicCell, TableCell),
|
||||
TableEditor: NullEditor as any,
|
||||
SideDrawerField,
|
||||
settings: Settings,
|
||||
csvImportParser: (value) => parseJSON(value).getTime(),
|
||||
csvExportFormatter: (value: any, config?: any) =>
|
||||
format(value.toDate(), config?.format ?? DATE_TIME_FORMAT),
|
||||
};
|
||||
export default config;
|
||||
|
||||
|
||||
@@ -18,7 +18,6 @@ export default function Email({
|
||||
variant="filled"
|
||||
fullWidth
|
||||
margin="none"
|
||||
placeholder={column.name as string}
|
||||
onChange={onChange}
|
||||
onBlur={onBlur}
|
||||
value={value}
|
||||
|
||||
@@ -18,7 +18,6 @@ export default function LongText({
|
||||
variant="filled"
|
||||
fullWidth
|
||||
margin="none"
|
||||
placeholder={column.name as string}
|
||||
onChange={onChange}
|
||||
onBlur={onBlur}
|
||||
value={value}
|
||||
|
||||
@@ -20,7 +20,6 @@ export default function Number_({
|
||||
variant="filled"
|
||||
fullWidth
|
||||
margin="none"
|
||||
placeholder={column.name as string}
|
||||
onChange={handleChange}
|
||||
onBlur={onBlur}
|
||||
value={value}
|
||||
|
||||
@@ -47,7 +47,6 @@ export default function Percentage({
|
||||
variant="filled"
|
||||
fullWidth
|
||||
margin="none"
|
||||
placeholder={column.name as string}
|
||||
onChange={handleChange}
|
||||
onBlur={onBlur}
|
||||
value={typeof value === "number" ? value * 100 : value}
|
||||
|
||||
@@ -18,7 +18,6 @@ export default function Phone({
|
||||
variant="filled"
|
||||
fullWidth
|
||||
margin="none"
|
||||
placeholder={column.name as string}
|
||||
onChange={onChange}
|
||||
onBlur={onBlur}
|
||||
value={value}
|
||||
|
||||
@@ -18,7 +18,6 @@ export default function ShortText({
|
||||
variant="filled"
|
||||
fullWidth
|
||||
margin="none"
|
||||
placeholder={column.name as string}
|
||||
onChange={onChange}
|
||||
onBlur={onBlur}
|
||||
value={value}
|
||||
|
||||
@@ -20,7 +20,6 @@ export default function Url({
|
||||
variant="filled"
|
||||
fullWidth
|
||||
margin="none"
|
||||
placeholder={column.name as string}
|
||||
onChange={onChange}
|
||||
onBlur={onBlur}
|
||||
value={value}
|
||||
|
||||
@@ -1,2 +1,2 @@
|
||||
export const DATE_FORMAT = "yyyy-MM-dd";
|
||||
export const DATE_TIME_FORMAT = DATE_FORMAT + " hh:mm a";
|
||||
export const DATE_TIME_FORMAT = DATE_FORMAT + " HH:mm";
|
||||
|
||||
@@ -33,4 +33,6 @@ export const EXTERNAL_LINKS = {
|
||||
rowyRunDocs: meta.homepage.replace("//", "//docs.") + "/rowyRun",
|
||||
|
||||
rowyAppHostName: "rowy.app",
|
||||
|
||||
dateFormat: "https://date-fns.org/v2.24.0/docs/format",
|
||||
};
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
import { Theme, ThemeOptions } from "@mui/material/styles";
|
||||
import type {} from "@mui/lab/themeAugmentation";
|
||||
import { toRem } from "./typography";
|
||||
|
||||
import RadioIcon from "theme/RadioIcon";
|
||||
@@ -352,10 +353,10 @@ export const components = (theme: Theme): ThemeOptions => {
|
||||
display: "block",
|
||||
position: "absolute",
|
||||
top: (32 - 16) / 2,
|
||||
bottom: (32 - 16) / 2,
|
||||
left: 0,
|
||||
|
||||
width: 3,
|
||||
height: 16,
|
||||
borderRadius: 1.5,
|
||||
backgroundColor: theme.palette.primary.main,
|
||||
},
|
||||
@@ -869,6 +870,24 @@ export const components = (theme: Theme): ThemeOptions => {
|
||||
bar: { borderRadius: theme.shape.borderRadius },
|
||||
},
|
||||
},
|
||||
|
||||
MuiYearPicker: {
|
||||
styleOverrides: {
|
||||
root: {
|
||||
"& .PrivatePickersYear-yearButton": {
|
||||
...theme.typography.button,
|
||||
fontSize: "1rem",
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
MuiPickersDay: {
|
||||
styleOverrides: {
|
||||
root: {
|
||||
background: "none",
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
};
|
||||
};
|
||||
|
||||
Reference in New Issue
Block a user