swordev / suid

A port of Material-UI (MUI) built with SolidJS.
https://suid.io
MIT License
673 stars 48 forks source link

Modular Forms seems incompatible with SUID #193

Open NightmanCZ90 opened 1 year ago

NightmanCZ90 commented 1 year ago

Hello, I started SolidJS project with SUID and for forms I wanted to use Modular Forms for forms validation. But I got stuck on an issue, when passed field props do not match with TextField's props. Below is an example of TextField usage with Modular Forms.

It seems that your event handlers design does not match up with the default ones (for ).

       <Form of={loginForm} onSubmit={handleSubmit}>
          <Field
            of={loginForm}
            name="email"
          >
            {(field) =>
                <TextField
                  {...field.props}
                  type="email"
                  // Reassign onInput and onChange, overwrite events
                  onInput={(e) => field.props.onInput({ ...e, currentTarget: { ...e.currentTarget, value: e.target.value } }) }
                  onChange={(e) => field.props.onInput(e)}
                  error={Boolean(field.error)}
                  helperText={field.error}
                  value={field.value || ''}
                />}
          </Field>
          <div class="signin-form--button">
            <Button
              type="submit"
              fullWidth
              color="secondary"
              variant="contained"
            >
              Sign in
            </Button>
          </div>
        </Form>

So far I have used this workaround below. But my question is whether there is a correct way to use these libraries together?

import { FieldElement } from "@modular-forms/solid";
import { JSX } from "solid-js";

export const remapFieldProps = (fieldProps: {
  name: string;
  ref: (element: FieldElement) => void;
  onInput: JSX.EventHandler<FieldElement, InputEvent>;
  onChange: JSX.EventHandler<FieldElement, Event>;
  onBlur: JSX.EventHandler<FieldElement, FocusEvent>;
}) => ({
  name: fieldProps.name,
  inputRef: fieldProps.ref,
  onBlur: fieldProps.onBlur,
  onChange: (e: any) => { fieldProps.onChange(e); fieldProps.onInput(e) }
});

=====================
<Field
  of={loginForm}
  name="email"
  validate={[
     required('Please enter your email.'),
     email('Please enter a valid email address.')
  ]}
>
  {(field) =>
    <TextField
      inputProps={{ ...remapFieldProps(field.props) }}
      type="email"
      value={field.value || ''}
      error={Boolean(field.error)}
      helperText={field.error}
    />}
</Field>
NightmanCZ90 commented 1 year ago

Cannot use SUID (Material UI) components #27

juanrgm commented 1 year ago

Could you share a link with the code at stackblitz?

If you want to use uncontrolled components (controlled by @modular-forms/solid) you should not use the value and onInput properties together.

fabian-hiller commented 1 year ago

@juanrgm you are right. Thanks for your input. The following code example works:

<Field of={form} name="email">
  {(field) => (
    <TextField
      variant="outlined"
      inputProps={{
        ...field.props,
        onChange: field.props.onInput,
      }}
    />
  )}
</Field>

For what reason do you use the name onChange instead of onInput as usual in SolidJS? And then what is the default onChange event of SolidJS on the input element?

juanrgm commented 1 year ago

For what reason do you use the name onChange instead of onInput as usual in SolidJS? And then what is the default onChange event of SolidJS on the input element?

Because the concept controlled component does not exist natively, it's inherited from React, where the behavior of the native onChange is replaced for supporting the controlled value.

fabian-hiller commented 1 year ago

I understand the background with React. However, the name has nothing to do with whether the field can be controlled or am I wrong? onInput might make more sense for the SolidJS implementation since that's the name most users expect.

juanrgm commented 1 year ago

All controlled components follow the same pattern (value, defaultsValue, onChange).

I would need a proof of concept in React with MUI to see if there are any differences with SUID (example: input event is not fired after change).