Skip to content

Commit

Permalink
fix: make Field types required based on type
Browse files Browse the repository at this point in the history
  • Loading branch information
chrisvxd committed Oct 26, 2023
1 parent 898504e commit daf36ac
Show file tree
Hide file tree
Showing 7 changed files with 104 additions and 46 deletions.
61 changes: 47 additions & 14 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -454,17 +454,57 @@ The `Config` object describes which components Puck should render, how they shou

A `Field` represents a user input field shown in the Puck interface.

- **type** (`text` | `textarea` | `number` | `select` | `radio` | `external` | `array` | `custom`): The input type to render
### All Fields

- **label** (`text` [optional]): A label for the input. Will use the key if not provided.
- **arrayFields** (`object`): Object describing sub-fields for items in an `array` input
- **[fieldName]** (`Field`): The Field objects describing the input data for each item
- **getItemSummary** (`(object, number) => string` [optional]): Function to get the name of each item when using the `array` or `external` field types
- **defaultItemProps** (`object` [optional]): Default props to pass to each new item added, when using a `array` field type
- **options** (`object[]`): array of items to render for select or radio inputs

### Text Fields

- **type** (`"text"`)

### Textarea Fields

- **type** (`"textarea"`)

### Number Fields

- **type** (`"number"`)

### Select Fields

- **type** (`"select"`)
- **options** (`object[]`): array of items to render
- **label** (`string`)
- **value** (`string` | `number` | `boolean`)
- **adaptor** (`Adaptor`): Content adaptor if using the `external` input type

### Radio Fields

- **type** (`"radio"`)
- **options** (`object[]`): array of items to render
- **label** (`string`)
- **value** (`string` | `number` | `boolean`)

### Array Fields

- **type** (`"array"`)
- **arrayFields** (`object`): Object describing sub-fields for each item
- **[fieldName]** (`Field`): The Field objects describing the input data for each item
- **getItemSummary** (`(object, number) => string` [optional]): Function to get the label of each item
- **defaultItemProps** (`object` [optional]): Default props to pass to each new item added, when using a `array` field type

### External Fields

External fields can be used to load content from an external content repository, like Strapi.js, using an `Adaptor`.

- **type** (`"external"`)
- **adaptor** (`Adaptor`): Content adaptor responsible for fetching data to show in the table
- **name** (`string`): The human-readable name of the adaptor
- **fetchList** (`(adaptorParams: object) => object`): Fetch a list of content and return an array
- **adaptorParams** (`object`): Paramaters passed to the adaptor

### Custom Fields

- **type** (`"custom"`)
- **render** (`Component`): Render a custom field. Receives the props:
- **field** (`Field`): Field configuration
- **name** (`string`): Name of the field
Expand Down Expand Up @@ -499,13 +539,6 @@ The `Data` object stores the puck page data.
- **props** (object):
- **[prop]** (string): User defined data from component fields

### `Adaptor`

An `Adaptor` can be used to load content from an external content repository, like Strapi.js.

- **name** (`string`): The human-readable name of the adaptor
- **fetchList** (`(adaptorParams: object) => object`): Fetch a list of content and return an array

### `Plugin`

Plugins that can be used to enhance Puck.
Expand Down
4 changes: 2 additions & 2 deletions packages/core/components/ExternalInput/index.tsx
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
import { useMemo, useEffect, useState } from "react";
import styles from "./styles.module.css";
import getClassNameFactory from "../../lib/get-class-name-factory";
import { Field } from "../../types/Config";
import { ExternalField } from "../../types/Config";
import { Link } from "react-feather";

const getClassName = getClassNameFactory("ExternalInput", styles);
Expand All @@ -11,7 +11,7 @@ export const ExternalInput = ({
onChange,
value = null,
}: {
field: Field;
field: ExternalField;
onChange: (value: any) => void;
value: any;
}) => {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -63,7 +63,7 @@ export const ArrayField = ({
setArrayState({ items: newItems });
}, [value]);

if (!field.arrayFields) {
if (field.type !== "array" || !field.arrayFields) {
return null;
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ export const ExternalField = ({
name,
label,
}: InputProps) => {
if (!field.adaptor) {
if (field.type !== "external" || !field.adaptor) {
return null;
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ export const RadioField = ({
value,
name,
}: InputProps) => {
if (!field.options) {
if (field.type !== "radio" || !field.options) {
return null;
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ export const SelectField = ({
value,
name,
}: InputProps) => {
if (!field.options) {
if (field.type !== "select" || !field.options) {
return null;
}

Expand Down
77 changes: 51 additions & 26 deletions packages/core/types/Config.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -16,39 +16,64 @@ type WithPuckProps<Props> = Props & {
};
};

export type Field<
Props extends { [key: string]: any } = { [key: string]: any }
> = {
type:
| "text"
| "textarea"
| "number"
| "select"
| "array"
| "external"
| "radio"
| "custom";
export type BaseField = {
label?: string;
adaptor?: Adaptor;
adaptorParams?: object;
arrayFields?: {
[SubPropName in keyof Props]: Field<Props[SubPropName][0]>;
};

export type TextField = BaseField & {
type: "text" | "number" | "textarea";
};

export type SelectField = BaseField & {
type: "select" | "radio";
options: {
label: string;
value: string | number | boolean;
}[];
};

export type ArrayField<
Props extends { [key: string]: any } = { [key: string]: any }
> = BaseField & {
type: "array";
arrayFields: {
[SubPropName in keyof Props[0]]: Field<Props[0][SubPropName]>;
};
getItemSummary?: (item: Props, index?: number) => string;
defaultItemProps?: Props;
render?: (props: {
field: Field;
defaultItemProps?: Props[0];
getItemSummary?: (item: Props[0], index?: number) => string;
};

export type ExternalField<
Props extends { [key: string]: any } = { [key: string]: any }
> = BaseField & {
type: "external";
adaptor: Adaptor;
adaptorParams?: object;
getItemSummary: (item: Props, index?: number) => string;
};

export type CustomField<
Props extends { [key: string]: any } = { [key: string]: any }
> = BaseField & {
type: "custom";
render: (props: {
field: CustomField;
name: string;
value: any;
onChange: (value: any) => void;
onChange: (value: Props) => void;
readOnly?: boolean;
}) => ReactElement;
options?: {
label: string;
value: string | number | boolean;
}[];
};

export type Field<
Props extends { [key: string]: any } = { [key: string]: any }
> =
| TextField
| SelectField
| ArrayField<Props>
| ExternalField<Props>
| CustomField;

export type DefaultRootProps = {
children: ReactNode;
title: string;
Expand All @@ -64,7 +89,7 @@ export type Fields<
[PropName in keyof Omit<
Required<ComponentProps>,
"children" | "editMode"
>]: Field<ComponentProps[PropName][0]>;
>]: Field<ComponentProps[PropName]>;
};

export type Content<
Expand Down

0 comments on commit daf36ac

Please sign in to comment.