Skip to content

Commit

Permalink
Merge pull request #33 from th3f0r3ign3r/main
Browse files Browse the repository at this point in the history
Added showLabel property
  • Loading branch information
vantezzen authored Sep 28, 2023
2 parents defc793 + 8c128bd commit 70aef76
Show file tree
Hide file tree
Showing 4 changed files with 92 additions and 13 deletions.
18 changes: 17 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -337,7 +337,7 @@ const formSchema = z.object({
z.object({
name: z.string(),
age: z.coerce.number(),
})
}),
)
// Optionally set a custom label - otherwise this will be inferred from the field name
.describe("Guests invited to the party"),
Expand Down Expand Up @@ -381,6 +381,22 @@ You can use the `inputProps` property to pass props to the input component. You
<input type="text" placeholder="Username" /* ... */ />
```
Disabling the label of an input can be done by using the `showLabel` property in `inputProps`.
```tsx
<AutoForm
fieldConfig={{
username: {
inputProps: {
type: "text",
placeholder: "Username",
showLabel: false,
},
},
}}
/>
```
#### Field type
By default, AutoForm will use the Zod type to determine which input component to use. You can override this by using the `fieldType` property.
Expand Down
2 changes: 2 additions & 0 deletions src/App.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -3,13 +3,15 @@ import Array from "./examples/Array";
import Basics from "./examples/Basics";
import ConfirmPassword from "./examples/ConfirmPassword";
import Controlled from "./examples/Controlled";
import InputWithoutLabel from "./examples/InputWithoutLabel";
import SubObject from "./examples/SubObject";

function App() {
return (
<>
<div className="mx-auto my-6 max-w-lg space-y-8">
<Basics />
<InputWithoutLabel />
<SubObject />
<Controlled />
<ConfirmPassword />
Expand Down
30 changes: 18 additions & 12 deletions src/components/ui/auto-form.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -88,12 +88,12 @@ function getDefaultValueInZodStack(schema: z.ZodAny): any {

if ("innerType" in typedSchema._def) {
return getDefaultValueInZodStack(
typedSchema._def.innerType as unknown as z.ZodAny
typedSchema._def.innerType as unknown as z.ZodAny,
);
}
if ("schema" in typedSchema._def) {
return getDefaultValueInZodStack(
(typedSchema._def as any).schema as z.ZodAny
(typedSchema._def as any).schema as z.ZodAny,
);
}
return undefined;
Expand All @@ -103,7 +103,7 @@ function getDefaultValueInZodStack(schema: z.ZodAny): any {
* Get all default values from a Zod schema.
*/
function getDefaultValues<Schema extends z.ZodObject<any, any>>(
schema: Schema
schema: Schema,
) {
const { shape } = schema;
type DefaultValuesType = DefaultValues<Partial<z.infer<Schema>>>;
Expand All @@ -114,7 +114,7 @@ function getDefaultValues<Schema extends z.ZodObject<any, any>>(

if (getBaseType(item) === "ZodObject") {
const defaultItems = getDefaultValues(
item as unknown as z.ZodObject<any, any>
item as unknown as z.ZodObject<any, any>,
);
for (const defaultItemKey of Object.keys(defaultItems)) {
const pathKey = `${key}.${defaultItemKey}` as keyof DefaultValuesType;
Expand All @@ -132,7 +132,7 @@ function getDefaultValues<Schema extends z.ZodObject<any, any>>(
}

function getObjectFormSchema(
schema: ZodObjectOrWrapped
schema: ZodObjectOrWrapped,
): z.ZodObject<any, any> {
if (schema._def.typeName === "ZodEffects") {
const typedSchema = schema as z.ZodEffects<z.ZodObject<any, any>>;
Expand All @@ -150,7 +150,7 @@ function zodToHtmlInputProps(
| z.ZodNumber
| z.ZodString
| z.ZodOptional<z.ZodNumber | z.ZodString>
| any
| any,
): React.InputHTMLAttributes<HTMLInputElement> {
if (["ZodOptional", "ZodNullable"].includes(schema._def.typeName)) {
const typedSchema = schema as z.ZodOptional<z.ZodNumber | z.ZodString>;
Expand Down Expand Up @@ -192,7 +192,9 @@ function zodToHtmlInputProps(

export type FieldConfigItem = {
description?: React.ReactNode;
inputProps?: React.InputHTMLAttributes<HTMLInputElement>;
inputProps?: React.InputHTMLAttributes<HTMLInputElement> & {
showLabel?: boolean;
};
fieldType?:
| keyof typeof INPUT_COMPONENTS
| React.FC<AutoFormInputComponentProps>;
Expand Down Expand Up @@ -228,14 +230,18 @@ function AutoFormInput({
fieldConfigItem,
fieldProps,
}: AutoFormInputComponentProps) {
const { showLabel: _showLabel, ...fieldPropsWithoutShowLabel } = fieldProps;
const showLabel = _showLabel === undefined ? true : _showLabel;
return (
<FormItem>
<FormLabel>
{label}
{isRequired && <span className="text-destructive"> *</span>}
</FormLabel>
{showLabel && (
<FormLabel>
{label}
{isRequired && <span className="text-destructive"> *</span>}
</FormLabel>
)}
<FormControl>
<Input type="text" {...fieldProps} />
<Input type="text" {...fieldPropsWithoutShowLabel} />
</FormControl>
{fieldConfigItem.description && (
<FormDescription>{fieldConfigItem.description}</FormDescription>
Expand Down
55 changes: 55 additions & 0 deletions src/examples/InputWithoutLabel.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,55 @@
import * as z from "zod";
import AutoForm from "../components/ui/auto-form";
import {
Card,
CardContent,
CardDescription,
CardHeader,
CardTitle,
} from "../components/ui/card";
import { Button } from "@/components/ui/button";

const formSchema = z.object({
username: z.string(),
});

function InputWithoutLabel() {
return (
<>
<div className="mx-auto my-6 max-w-lg">
<Card>
<CardHeader>
<CardTitle>Input Without Label</CardTitle>
<CardDescription>
This example shows how to use AutoForm input without label.
</CardDescription>
</CardHeader>

<CardContent>
<AutoForm
formSchema={formSchema}
fieldConfig={{
username: {
inputProps: {
showLabel: false,
placeholder: "Username",
},
renderParent: ({ children }) => (
<div className="flex items-end gap-3">
<div className="flex-1">{children}</div>
<div>
<Button type="button">Update</Button>
</div>
</div>
),
},
}}
></AutoForm>
</CardContent>
</Card>
</div>
</>
);
}

export default InputWithoutLabel;

0 comments on commit 70aef76

Please sign in to comment.