Skip to content

Commit

Permalink
Added descriptions for AutoComponents
Browse files Browse the repository at this point in the history
  • Loading branch information
MillanWangGadget committed Oct 18, 2024
1 parent fce894e commit 70fdb0f
Show file tree
Hide file tree
Showing 46 changed files with 1,409 additions and 642 deletions.
5 changes: 5 additions & 0 deletions packages/react/.changeset/fuzzy-nails-do.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
"@gadgetinc/react": patch
---

Added descriptions for AutoComponents
22 changes: 18 additions & 4 deletions packages/react/src/auto/interfaces/AutoRelationshipInputProps.tsx
Original file line number Diff line number Diff line change
@@ -1,14 +1,28 @@
import type { ReactNode } from "react";
import type { Control } from "../../useActionForm.js";
import { ControllableWithReactHookForm, InputLabel } from "../shared/AutoInputTypes.js";

export interface AutoRelationshipInputProps {
export interface AutoRelationshipInputProps extends ControllableWithReactHookForm {
/**
* The API identifier of the field
*/
field: string;
control?: Control<any>;

/**
* Controls how records on the related model are displayed as options in the relationship field input component
* When using a string, the string will indicate the field on the related model record to be displayed as the option label
* When using a function, the function will be called with the record to return a ReactNode to be displayed as the option label
*/
optionLabel?: OptionLabel;
label?: string;

/**
* The label of the field input component
*/
label?: InputLabel;
}

/**
* Type for the option label when displaying a list of records from a related model
* When using a string, the string will indicate the field on the related model record to be displayed as the option label
* When using a function, the function will be called with the record to return a ReactNode to be displayed as the option label
*/
export type OptionLabel = string | ((record: Record<string, any>) => ReactNode);
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,19 @@ import { autoInput } from "../../AutoInput.js";
// lazy import for smaller bundle size by default
const LazyLoadedMUIAutoRichTextInput = React.lazy(() => import("./MUIAutoRichTextInput.js"));

/**
* A rich text input component for use within <AutoForm></AutoForm> components.
* Requires `"@mdxeditor/editor"` as a peer dependency to be rendered
* @example
* ```tsx
* <AutoForm action={api.modelA.create}>
* <AutoRichTextInput field="richTextField" />
* </AutoForm>
* ```
* @param props.field - The RichText field API identifier
* @param props.label - The label of the RichText input component
* @returns The rich text input component
*/
export const MUIAutoRichTextInput = autoInput((props: AutoRichTextInputProps) => {
return (
<>
Expand Down
53 changes: 36 additions & 17 deletions packages/react/src/auto/mui/inputs/MUIAutoBooleanInput.tsx
Original file line number Diff line number Diff line change
@@ -1,28 +1,47 @@
import type { CheckboxProps } from "@mui/material";
import { Checkbox } from "@mui/material";
import React from "react";
import { useController, type Control } from "../../../useActionForm.js";
import { useController } from "../../../useActionForm.js";
import { autoInput } from "../../AutoInput.js";
import { useFieldMetadata } from "../../hooks/useFieldMetadata.js";
import { AutoBooleanInputProps, InputLabel } from "../../shared/AutoInputTypes.js";
import { MUIAutoFormControl } from "./MUIAutoFormControl.js";

export const MUIAutoBooleanInput = autoInput(
(props: { field: string; control?: Control<any>; label?: string } & Partial<CheckboxProps>) => {
const { field: fieldApiIdentifier, label, control, ...rest } = props;
export interface MUIAutoBooleanInputProps extends AutoBooleanInputProps, Partial<CheckboxProps> {
/**
* The label of the checkbox
*/
label?: InputLabel;
}

const { path } = useFieldMetadata(fieldApiIdentifier);
/**
* A checkbox input for boolean inputs for use within <AutoForm></AutoForm> components
* @example
* ```tsx
* <AutoForm action={api.modelA.create}>
* <AutoBooleanInput field="isActive" />
* </AutoForm>
* ```
* @param props.field - The API identifier of the Boolean field
* @param props.label - The label of the checkbox
*
* @returns The checkbox input component
*/
export const MUIAutoBooleanInput = autoInput((props: MUIAutoBooleanInputProps) => {
const { field: fieldApiIdentifier, label, control, ...rest } = props;

const { field: fieldProps } = useController({
control,
name: path,
});
const { path } = useFieldMetadata(fieldApiIdentifier);

const { value: _value, ...restFieldProps } = fieldProps;
const { field: fieldProps } = useController({
control,
name: path,
});

return (
<MUIAutoFormControl field={props.field} label={label}>
<Checkbox {...restFieldProps} checked={fieldProps.value} {...rest} />
</MUIAutoFormControl>
);
}
);
const { value: _value, ...restFieldProps } = fieldProps;

return (
<MUIAutoFormControl field={props.field} label={label as string}>
<Checkbox {...restFieldProps} checked={fieldProps.value} {...rest} />
</MUIAutoFormControl>
);
});
61 changes: 36 additions & 25 deletions packages/react/src/auto/mui/inputs/MUIAutoDateTimePicker.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -6,38 +6,49 @@ import type { GadgetDateTimeConfig } from "../../../internal/gql/graphql.js";
import { useController } from "../../../useActionForm.js";
import { autoInput } from "../../AutoInput.js";
import { useFieldMetadata } from "../../hooks/useFieldMetadata.js";
import { AutoDateTimeInputProps } from "../../shared/AutoInputTypes.js";

export const MUIAutoDateTimePicker = autoInput(
(props: { field: string; value?: Date; onChange?: (value: Date) => void; error?: string; label?: string }) => {
const localTz = Intl.DateTimeFormat().resolvedOptions().timeZone;
const { path, metadata } = useFieldMetadata(props.field);
const config = metadata.configuration;
const isRequired = metadata.requiredArgumentForInput;
const label = (props.label ?? metadata.name) + (isRequired ? " *" : "");
/**
* A date and time picker for use within <AutoForm></AutoForm> components
* @example
* ```tsx
* <AutoForm action={api.modelA.create}>
* <AutoDateTimePicker field="dueDate" />
* </AutoForm>
* ```
* @param props.field - The API identifier of the DateTime field
* @param props.label - The label of the date and time picker
* @returns The date and time picker component
*/
export const MUIAutoDateTimePicker = autoInput((props: AutoDateTimeInputProps) => {
const localTz = Intl.DateTimeFormat().resolvedOptions().timeZone;
const { path, metadata } = useFieldMetadata(props.field);
const config = metadata.configuration;
const isRequired = metadata.requiredArgumentForInput;
const label = (props.label ?? metadata.name) + (isRequired ? " *" : "");

const { field: fieldProps, fieldState } = useController({ name: path });
const { field: fieldProps, fieldState } = useController({ name: path });

return (
<Box sx={{ display: "flex" }}>
<DatePicker
label={label}
slotProps={{ textField: { error: !!fieldState.error, helperText: fieldState.error?.message } }}
return (
<Box sx={{ display: "flex" }}>
<DatePicker
label={label}
slotProps={{ textField: { error: !!fieldState.error, helperText: fieldState.error?.message } }}
onChange={(newValue: string | number | Date | null) => {
props.onChange?.(zonedTimeToUtc(new Date(newValue ?? ""), localTz));
fieldProps.onChange(zonedTimeToUtc(new Date(newValue ?? ""), localTz));
}}
/>
{(config as GadgetDateTimeConfig).includeTime && (
<TimePicker
onChange={(newValue: string | number | Date | null) => {
props.onChange?.(zonedTimeToUtc(new Date(newValue ?? ""), localTz));
fieldProps.onChange(zonedTimeToUtc(new Date(newValue ?? ""), localTz));
}}
/>
{(config as GadgetDateTimeConfig).includeTime && (
<TimePicker
onChange={(newValue: string | number | Date | null) => {
props.onChange?.(zonedTimeToUtc(new Date(newValue ?? ""), localTz));
fieldProps.onChange(zonedTimeToUtc(new Date(newValue ?? ""), localTz));
}}
/>
)}
</Box>
);
}
);
)}
</Box>
);
});

export default MUIAutoDateTimePicker;
35 changes: 20 additions & 15 deletions packages/react/src/auto/mui/inputs/MUIAutoEncryptedStringInput.tsx
Original file line number Diff line number Diff line change
@@ -1,20 +1,25 @@
import type { TextFieldProps } from "@mui/material";
import { IconButton } from "@mui/material";
import { IconButton, type TextFieldProps } from "@mui/material";
import React, { useState } from "react";
import type { Control } from "../../../useActionForm.js";
import { autoInput } from "../../AutoInput.js";
import type { AutoEncryptedStringInputProps } from "../../shared/AutoInputTypes.js";
import { MUIAutoTextInput } from "./MUIAutoTextInput.js";

export const MUIAutoEncryptedStringInput = autoInput(
(
props: {
field: string; // The field API identifier
control?: Control<any>;
} & Partial<TextFieldProps>
) => {
const [isShown, setIsShown] = useState(false);
const showHideToggleButton = <IconButton onClick={() => setIsShown(!isShown)}>{isShown ? `🔒` : `👁️`}</IconButton>;
type MUIAutoEncryptedStringInputProps = AutoEncryptedStringInputProps & Partial<TextFieldProps>;
/**
* An encrypted string input for use within <AutoForm></AutoForm> components.
* @example
* ```tsx
* <AutoForm action={api.modelA.create}>
* <AutoEncryptedStringInput field="encryptedStringField" />
* </AutoForm>
* ```
* @param props.field - The API identifier for the EncryptedString field.
* @param props.label - The label of the EncryptedString field.
* @returns The AutoEncryptedStringInput component.
*/
export const MUIAutoEncryptedStringInput = autoInput((props: MUIAutoEncryptedStringInputProps) => {
const [isShown, setIsShown] = useState(false);
const showHideToggleButton = <IconButton onClick={() => setIsShown(!isShown)}>{isShown ? `🔒` : `👁️`}</IconButton>;

return <MUIAutoTextInput InputProps={{ endAdornment: showHideToggleButton }} type={isShown ? "text" : "password"} {...props} />;
}
);
return <MUIAutoTextInput InputProps={{ endAdornment: showHideToggleButton }} type={isShown ? "text" : "password"} {...props} />;
});
15 changes: 14 additions & 1 deletion packages/react/src/auto/mui/inputs/MUIAutoEnumInput.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,20 @@ import { Autocomplete, TextField } from "@mui/material";
import React from "react";
import { autoInput } from "../../AutoInput.js";
import { useEnumInputController } from "../../hooks/useEnumInputController.js";
import { AutoEnumInputProps } from "../../shared/AutoInputTypes.js";

/**
* An enum option picker for use within <AutoForm></AutoForm> components.
* @example
* ```tsx
* <AutoForm action={api.modelA.create}>
* <AutoEnumInput field="enumField" />
* </AutoForm>
* ```
* @param props.field - The API identifier for the Enum field.
* @param props.label - The label of the input.
* @returns The AutoEnumInput component.
*/
export const MUIAutoEnumInput = autoInput(
<
Value,
Expand All @@ -12,7 +25,7 @@ export const MUIAutoEnumInput = autoInput(
FreeSolo extends boolean | undefined = false,
ChipComponent extends React.ElementType = ChipTypeMap["defaultComponent"]
>(
props: { field: string; label?: string } & Partial<AutocompleteProps<Value, Multiple, DisableClearable, FreeSolo, ChipComponent>>
props: AutoEnumInputProps & Partial<AutocompleteProps<Value, Multiple, DisableClearable, FreeSolo, ChipComponent>>
) => {
const { allowMultiple, selectedOptions, onSelectionChange, allOptions, label } = useEnumInputController(props);

Expand Down
23 changes: 19 additions & 4 deletions packages/react/src/auto/mui/inputs/MUIAutoFileInput.tsx
Original file line number Diff line number Diff line change
@@ -1,14 +1,14 @@
import { Button, styled } from "@mui/material";
import React from "react";
import type { Control } from "../../../useActionForm.js";
import { autoInput } from "../../AutoInput.js";
import { useFileInputController } from "../../hooks/useFileInputController.js";
import { AutoFileInputProps, InputLabel } from "../../shared/AutoInputTypes.js";
import { MUIAutoFormControl } from "./MUIAutoFormControl.js";

export interface MUIFileInputProps {
label?: string;
label?: InputLabel;
value?: File;
onChange: (value: File) => void;
onChange?: (value: File) => void;
}
const VisuallyHiddenInput = styled("input")({
clip: "rect(0 0 0 0)",
Expand All @@ -22,7 +22,22 @@ const VisuallyHiddenInput = styled("input")({
width: 1,
});

export const MUIAutoFileInput = autoInput((props: { field: string; control?: Control<any>; label?: string }) => {
export type MUIAutoFileInputProps = AutoFileInputProps & MUIFileInputProps;

/**
* A file input for use within <AutoForm></AutoForm> components
* @example
* ```tsx
* <AutoForm action={api.modelA.create}>
* <AutoFileInput field="fileField" />
* </AutoForm>
* ```
* @param props.field - The API identifier of the File field
* @param props.label - The label of the File field
* @param props.onChange - called when the file input changes
* @returns The file input component
*/
export const MUIAutoFileInput = autoInput((props: MUIAutoFileInputProps) => {
const { field: fieldApiIdentifier, control, label } = props;
const { onFileUpload, metadata } = useFileInputController({
field: fieldApiIdentifier,
Expand Down
10 changes: 9 additions & 1 deletion packages/react/src/auto/mui/inputs/MUIAutoFormControl.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -4,8 +4,16 @@ import React from "react";
import { useController } from "../../../useActionForm.js";
import { autoInput } from "../../AutoInput.js";
import { useFieldMetadata } from "../../hooks/useFieldMetadata.js";
import { InputLabel } from "../../shared/AutoInputTypes.js";

export const MUIAutoFormControl = autoInput((props: { field: string; children: ReactElement; label?: string }) => {
/**
* A form control wrapper used to wrap MUI form input components.
* @param props.field - The field API identifier
* @param props.label - The label of the form control input component
* @param props.children - The child elements to be rendered within the form control
* @returns The form control component
*/
export const MUIAutoFormControl = autoInput((props: { field: string; children: ReactElement; label?: InputLabel }) => {
const { path, metadata } = useFieldMetadata(props.field);
const {
fieldState: { error },
Expand Down
26 changes: 17 additions & 9 deletions packages/react/src/auto/mui/inputs/MUIAutoHiddenInput.tsx
Original file line number Diff line number Diff line change
@@ -1,14 +1,22 @@
import React from "react";
import { autoInput } from "../../AutoInput.js";
import { useHiddenInput } from "../../hooks/useHiddenInput.js";
import { AutoHiddenInputProps } from "../../shared/AutoInputTypes.js";

export const MUIAutoHiddenInput = autoInput(
(props: {
field: string; // The field API identifier
value: any;
}) => {
const fieldProps = useHiddenInput(props);
/**
* A hidden input for use within <AutoForm></AutoForm> components. The value is included in form submission without rendering a visible input.
* @example
* ```tsx
* <AutoForm action={api.modelA.create}>
* <AutoHiddenInput field="fieldA" value="Value included in submission for fieldA" />
* </AutoForm>
* ```
* @param props.field - The field API identifier
* @param props.value - The value to be included in form submission
* @returns The hidden input component
*/
export const MUIAutoHiddenInput = autoInput((props: AutoHiddenInputProps) => {
const fieldProps = useHiddenInput(props);

return <input type="hidden" {...fieldProps} />;
}
);
return <input type="hidden" {...fieldProps} />;
});
Loading

0 comments on commit 70fdb0f

Please sign in to comment.