Open chrisvxd opened 10 months ago
This is the way we currently model our page data, maybe its worth also considering multiple tabs within the right panel e.g content, styles, etc
On the above Option 2 definitely reads better to me. Option 1 sort of feels like a ceremony that can be skipped. https://github.com/measuredco/puck/assets/1926968/ad9c3e97-512d-43e7-95ef-e729db571b2f
Interesting! I've spoken to @monospaced and I think we leaning the other way towards Option 1 (renderFields
).
In terms of ceremony, you could merge the fields
and renderFields
APIs when using renderFields
to reduce repetition.
But this model also means we can support tabs and other compositional UI in the future:
export const Heading: ComponentConfig<HeadingProps> = {
renderFields: () => {
return (
<Tabs>
<Tabs.Tab label="Main tab">
<Field name="text" type="text" />
<Field name="level" type="select" options={levelOptions} />
<Fieldset title="Style">
<Field name="size" type="select" options={sizeOptions} />
<Field name="align" type="radio" options={alignOptions} />
<Field name="padding" type="text" />
</Fieldset>
</Tabs.Tab>
<Tabs.Tab label="Secondary tab">
Content here
</Tabs.Tab>
</Tabs>
);
},
};
Going with renderFields
. Marking as ready for dev.
It's been sometime since we decided on option 1, and we may wish to revisit that decision.
Throwing my 2 cents into the discussion. Consider the following component config for "field groups" that follows a very similar pattern to how component categories are configured:
export const Heading: ComponentConfig<HeadingProps> = {
fields: {
heading: {
type: "text",
},
level: {
type: "select",
label: "Level (1-6)",
options: [
{ label: "Heading 1", value: "1" },
{ label: "Heading 2", value: "2" },
{ label: "Heading 3", value: "3" },
{ label: "Heading 4", value: "4" },
{ label: "Heading 5", value: "5" },
{ label: "Heading 6", value: "6" },
],
},
textColor: {
type: "custom",
render: TextColorField,
},
backgroundColor: {
type: "custom",
render: BackgroundColorField,
},
fontFamily: {
type: "custom",
render: FontFamilyField,
},
fontSize: {
type: "custom",
render: FontSizeField,
},
fontStyle: {
type: "custom",
render: FontStyleField,
},
// ...more fields
},
fieldGroups: {
basics: {
title: "Basics",
fields: ["heading", "level"],
},
typography: {
title: "Typography",
fields: ["fontFamily", "fontSize", "fontStyle"],
},
other: {
title: "Other",
},
},
defaultProps: {},
render() {},
}
This is backwards compatible since nothing changes within the fields
config object. When no fieldGroups
object is provided it just renders as-is.
Sidenote: the reason I prefer fieldGroups
over fieldset
is that fieldset
is ambiguous to me because it is an existing HTML element.
Another advantage of this approach is that you can guarantee the order of the fields within a group by using the fieldGroups.{field}.fields
array. More modern versions of JavaScript don't seem to have too many inconsistencies, but I've been burned in the past assuming the order would be consistent when using objects when it wasn't. Another option (probably outside of this topic) is to introduce an order
prop that could be used to specify the order of each field, fieldGroup, etc within the config.
To take this a step further, the tabs concept can also be implemented with an optional tabs
addition to the config.
export const Heading: ComponentConfig<HeadingProps> = {
fields: {
heading: {
type: "text",
},
level: {
type: "select",
label: "Level (1-6)",
options: [
{ label: "Heading 1", value: "1" },
{ label: "Heading 2", value: "2" },
{ label: "Heading 3", value: "3" },
{ label: "Heading 4", value: "4" },
{ label: "Heading 5", value: "5" },
{ label: "Heading 6", value: "6" },
],
},
textColor: {
type: "custom",
render: TextColorField,
},
backgroundColor: {
type: "custom",
render: BackgroundColorField,
},
fontFamily: {
type: "custom",
render: FontFamilyField,
},
fontSize: {
type: "custom",
render: FontSizeField,
},
fontStyle: {
type: "custom",
render: FontStyleField,
},
// ...more fields
},
fieldGroups: {
basics: {
title: "Basics",
fields: ["heading", "level"],
},
typography: {
title: "Typography",
fields: ["fontFamily", "fontSize", "fontStyle"],
},
other: {
title: "Other",
},
},
+ tabs: {
+ settings: {
+ title: "Settings",
+ groups: ["basics", "typography"],
+ },
+ other: {
+ title: "Other",
+ groups: ["other"],
+ },
+ },
defaultProps: {},
render() {},
}
Each of these different configs can be overridden using the overrides
API:
fieldGroup
: Render individual field group - takes group's key
, title
and rendered children
fieldsTab
: Render individual tab: takes the tab's key
, title
and rendered children
Currently, we have no way to create groups of fields. #62 adds
object
support, and spun out this discussion.Proposals
Option 1
Add
renderFields
methodExample adding a Style fieldset to Heading
Option 2
Change
fields
API or add newfieldsets
APIOption 3
Something else; could be some combination of the above or another proposal.
Related #62