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: make Fable.Form.Simple pluggable #54

Merged
merged 41 commits into from
Oct 20, 2024
Merged

Conversation

MangelMaxime
Copy link
Owner

@MangelMaxime MangelMaxime commented Sep 6, 2024

Beta versions are already out, so you can give it a try 🎉

  • Fable.Form - 3.0.0-beta-001
  • Fable.Form.Simple - 5.0.0-beta-001
  • Fable.Form.Simple.Bulma - 5.0.0-beta-001

Upgrade form previous version:

  1. Change Form.Form<Values, Msg, _> = or Form.Form<Values, Msg, IReactProperty> = to Form<Values, Msg> =

  2. Add FieldId = "replace-me" to all the attributes that fails to compile.

    FieldId should be unique across your form

If you want to create a custom field you can looks at:

  • CheckboxField - Showcase how a standard field looks (simple code)
  • SignatureField - Showcase how you can make a more complex field (showcase using a ReactComponent)

API is not final yet, but looking at how things went I don't think the expose API will change too much. 🤞


Would be nice to have done before making a stable release:

  • Update the documentation
    • Keep a reference to old documentation if possible by copy/pasting files
    • Explains how to create a custom field
  • Explore exposing an attributes builder API to avoid having to defined empty list or default values when we don't want to. It also allows to add new features to Attributes without breaking the user code because such new features will have a default value. For example, if we add Add help policy #26
  • Add Base.disableIf  #45
  • Add IsLoading to the field config #44 (look what can be done here)
  • Add help policy #26
  • Look into using Fable.Form for FuncUI to check what could be done
  • Looks into removing Elmish dependency to make Fable.Form more flexible (related to Explore if Fable.Form can be used with React hooks #21)
  • Look into making Fable.Form.Simple renderer agnostic
  • Add readOnly support (it works similarly to disable)
  • Add an example, of how to use Record to store the field state instead of just a primitive (could be an autocomplete text for example, to have a show/hide boolean for the list of choices)
  • Add an example of using a record for handling the value of a field instead of just a primitive
  • Look to make select, option, etc. works with any types and not just (string * string)
  • Showcase, how one can customise the rendering of a field

Won't do:

  • Look into using TypeScript to create a field

    After looking into it, it is in theory possible to use TypeScript to create field. But it requires, access to the generate code by Fable.

    The reason, is that even if most of the new API is testing things by the shape of it. Some of the API needs to call internal API:

     let form<'Values, 'Field, 'Output>
         : ((InnerField<'Values> -> 'Field)
               -> Base.FieldConfig<Attributes, string, 'Values, 'Output>
               -> Base.Form<'Values, 'Output, 'Field>) =
         Base.field String.IsNullOrEmpty
         
         // Base.field cannot be shadowed because it is the hearth of Fable.Form

    Things like StandardRenderFieldConfig needs to have access to:

     type Error =
         /// <summary>
         /// Used to represents an empty field
         /// </summary>
         | RequiredFieldIsEmpty
         /// <summary>
         /// Used to represents an error due a validation failed like when parsing a field value.
         /// </summary>
         | ValidationFailed of string
         /// <summary>
         /// Used to represents an external error
         /// <para>For example, it is used when doing server side validation</para>
         /// </summary>
         | External of string

    And the list goes on. I think for now, this is not worth it looking into it. This could be revisited once Fable is able to consume pre-compiled packages from NPM for example.

    Or we expose the require API via a global module for usage in TypeScript code. I will left that to explore for others

@MangelMaxime MangelMaxime marked this pull request as draft September 6, 2024 16:58
@MangelMaxime MangelMaxime force-pushed the feature/pluggable branch 2 times, most recently from 19e12dc to e1cb605 Compare September 8, 2024 15:40
[Fable.Form]

=== changelog ===
* Field attributes now needs to inherit from `IAttributes`
* Refactor `Base.fill` to explicitly take a `values` argument instead of returning a lambda

    ```fsharp
    val fill:
        Form<'Values,'Output,'Field>
        -> 'Values -> FilledForm<'Output,'Field>
    ```

    ```fsharp
    val fill:
        Form<'Values,'Output,'Field> ->
        values: 'Values
        -> FilledForm<'Output,'Field>
    ```
=== changelog ===
[Fable.Form.Simple]

=== changelog ===
`Fable.Form.Simple` is now field agnostic. It only contains logic on how a Form should be represented and how it behaves.

* Change `Form.View.custom` to take an additional `renderForm` and `renderField` functions
* Remove all `Form.xxx` functions (they moved to Fable.Form.Simple.Bulma)
    * `Form.succeed`
    * `Form.append`
    * `Form.disable`
    * `Form.andThen`
    * `Form.optional`
    * `Form.textField`
    * `Form.passwordField`
    * `Form.colorField`
    * `Form.dateField`
    * `Form.dateTimeLocalField`
    * `Form.numberField`
    * `Form.searchField`
    * `Form.telField`
    * `Form.timeField`
    * `Form.emailField`
    * `Form.textareaField`
    * `Form.checkboxField`
    * `Form.radioField`
    * `Form.selectField`
    * `Form.fileField`
    * `Form.group`
    * `Form.section`
    * `Form.fill`
    * `Form.rec mapFieldValues`
    * `Form.list`
    * `Form.meta`
    * `Form.mapValues`
=== changelog ===
[Fable.Form.Simple.Bulma]

=== changelog ===
It is now easy to create custom form fields.

The drawback right now is that customising only the view requires a little more work than before. But I think the trade-off is worth it.

Before, people needed to fork `Fable.Form.Simple` and `Fable.Form.Simple.Bulma` to add custom fields. Now, they just need to implements `IField` API and it is done.

* Define how fields are represented thanks to the `IField`, `StandardRenderFieldConfig`, `IStandardField`, `IGenericField` and more.
* Add `FieldId` to most of field attributes because using only the label to detect field error don't guarantee a unique result.

    For example, you can have two fields with a label "FirstName". Thanks to the field id you do "firstname-student" and "firstname-teacher"

* Export removed `Form.xxx` functions from `Fable.Form.Simple` making transition to 2.0 easy
    * `Form.succeed`
    * `Form.append`
    * `Form.disable`
    * `Form.andThen`
    * `Form.optional`
    * `Form.textField`
    * `Form.passwordField`
    * `Form.colorField`
    * `Form.dateField`
    * `Form.dateTimeLocalField`
    * `Form.numberField`
    * `Form.searchField`
    * `Form.telField`
    * `Form.timeField`
    * `Form.emailField`
    * `Form.textareaField`
    * `Form.checkboxField`
    * `Form.radioField`
    * `Form.selectField`
    * `Form.fileField`
    * `Form.group`
    * `Form.section`
    * `Form.fill`
    * `Form.rec mapFieldValues`
    * `Form.list`
    * `Form.meta`
    * `Form.mapValues`
=== changelog ===
[Fable.Form][Fable.Form.Simple.Bulma]

Fix #45
@MangelMaxime MangelMaxime force-pushed the feature/pluggable branch 2 times, most recently from e2e9b67 to f93359e Compare September 9, 2024 15:25
[Fable.Form][Fable.Form.Simple][Fable.Form.Simple.Bulma]

=== changelog ===
1. Set it at the field level

    ```fsharp
    Form.textField
        // ...
        |> Form.readOnly

    // or

    Form.textField
        // ...
        |> Form.readOnlyIf myCondition
    ```

2. Set it at the form level

    ```fsharp
    let formValue : Form.View.Model<Values> = // ...

    { formValue with State = Form.View.State.Loading }
    ```
=== changelog ===
…ations + improve DaisyUI demo

[Fable.Form.Simple.Sutil.Bulma]
I already spent more time than I planned on this rewrite, and I don't think that a lot of people are using Fable.Lit.

If someone want to add Fable.Lit support they can maintain it.
@MangelMaxime MangelMaxime marked this pull request as ready for review October 20, 2024 17:37
@MangelMaxime MangelMaxime merged commit 60806cf into main Oct 20, 2024
@MangelMaxime MangelMaxime deleted the feature/pluggable branch October 20, 2024 17:38
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