Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: [SC-67391] BoundForm component spike #1122

Draft
wants to merge 4 commits into
base: main
Choose a base branch
from

Conversation

blambillotte
Copy link
Contributor

@blambillotte blambillotte commented Mar 10, 2025

Spike to explore the concept of a BoundForm which codifies how a standard form-state "bound" form should be presented as expressed via "config" rather than relying on the correct combination of BoundFoo input and layout components.

Standard form layout designs: https://www.figma.com/design/OfJJm1CXHRGkrHNcPu2grY/2025-UX-Standardization?node-id=513-19012&t=UZAEe6GPqDn3sXsT-0

Simple Example

With the exception of more complex inputs like select fields that require passing in loaded select options/etc, simple inputs don't require any props to be passed to their input functions as the FormState field will be automatically passed to the BoundFoo input component based on the field name key.

<BoundFormComponent
   inputConfig={{
     rows: [
      { firstName: textField(), middleInitial: textField(), lastName: textField() },
      { bio: textAreaField() },
     ],
   }}
   formState={formState}
/>
image

Multi-Section Example

Sections can be defined with titles and option icons. Additionally, the form input functions are simply wrapping the Bound_ component equivalents and accept all of the same props. However we can selectively Omit<...> unsupported props to drive further consistency.

const inputConfig: BoundFormInputConfig<AuthorInput> = [
  {
    title: "Author Overview",
    icon: "userCircle",
    rows: [
      { firstName: textField(), middleInitial: textField(), lastName: textField() },
      { bio: textAreaField() },
      // We can support any custom JSX node, TODO to come up with a better example
      // { height: <div>Example custom component</div> },
    ],
  },
  {
    title: "More Details",
    icon: "openBook",
    rows: [
      {
        favoriteSport: selectField({
          options: sportsOptions,
          // Opportunity here to not require label & value getters if using conventional `HasNameAndId`
          getOptionLabel: (o) => o.name,
          getOptionValue: (o) => o.id,
        }),
        favoriteColors: multiSelectField({
          options: colorOptions,
          getOptionLabel: (o) => o.name,
          getOptionValue: (o) => o.id,
        }),
        heightInInches: numberField({ label: "Height (in inches)" }),
        birthday: dateField(),
      },
      { isAvailable: checkboxField({ label: "Is Retired" }) },
    ],
  },
];
<BoundFormComponent inputConfig={inputConfig} formState={formState} />
image

Additional Advantages

There's also an opportunity to bake in UX nice-to-haves that generally aren't worth the time on each feature like improved loading states. Because we express the shape of the form via the config, we can match the loading state skeleton loaders to the form layout. Demo

);
}

export function selectField<O, V extends Value>(props: Omit<BoundSelectFieldProps<O, V>, "field">) {
Copy link
Contributor Author

@blambillotte blambillotte Mar 10, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Would need to make wrappers for the existing BoundFoo components out there. Right now I'm just omitting the field property since that gets mapped within the component internals, but we could also further lock down what props are allowed given the point is to standardize the display of the form as much as possible.

@ogrodnek ogrodnek marked this pull request as ready for review March 10, 2025 23:58
@blambillotte blambillotte marked this pull request as draft March 11, 2025 00:01
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

1 participant