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

Separate templates and allow a completely custom UI components #1013

Closed
wants to merge 13 commits into from

Conversation

MatejBransky
Copy link

@MatejBransky MatejBransky commented Aug 26, 2018

Reasons for making this change

This PR separates template components from fields so you can replace all UI components with your own.

New API:

  • Form.props.templates - mainly UI components separated from fields
    • templates.ArrayFieldTemplate - old ArrayFieldTemplate
    • templates.DescriptionTemplate - old fields.DescriptionField
    • templates.ErrorListTemplate - old ErrorList
    • templates.FieldTemplate - old FieldTemplate
    • templates.ObjectFieldTemplate - old ObjectFieldTemplate
    • templates.SubmitTemplate - old default submit button in Form's render
    • templates.TitleTemplate - old fields.TitleField
  • added HOC withTheme - it wraps Form with components (fields, widgets, templates), it's useful for building a custom theme:
import withTheme from 'react-jsonschema-form/lib/components/withTheme';

import widgets from './my-theme/widgets';
import templates from './my-theme/templates';

const Form = withTheme('MyTheme', { widgets, templates });

Fields, widgets, templates...this diagram helped me to keep the basic relationships between components in my head (ArrayField is extended in readme):

react-jsonschema-form

And it's quite useful if you build your custom UI.

Breaking changes (I suppose that this PR should land in v2):

  • replaced Form.props.FieldTemplate with Form.props.templates.FieldTemplate
  • replaced Form.props.ArrayFieldTemplate with Form.props.templates.ArrayFieldTemplate
  • replaced Form.props.ObjectFieldTemplate with Form.props.templates.ObjectFieldTemplate
  • replaced Form.props.ErrorList with Form.props.templates.ErrorListTemplate
  • replaced Form.props.fields.DescriptionField with Form.props.templates.DescriptionTemplate
  • replaced Form.props.fields.TitleField with Form.props.templates.TitleTemplate
  • all "raw-" props replace component based versions
    • rawErrors is now errors
    • rawDescription is now description
    • rawHelp is now help

If this is related to existing tickets, include links to them as well.

#693 - build whatever UI you want
#766 - <p> tags replaced with <div> in SubmitTemplate
#767 - uppercased props moved into the templates
#899 - this merge allows relatively painless update from Bootstrap 3 to Bootstrap 4 (I have prepared update to Bootstrap 4 based on this PR) and if anyone wants to use a custom theme without importing Bootstrap 4 components then with this merge it's finally possible
#951, #952 - FieldTemplate is separated
#1010 - templates

Checklist

  • I'm updating documentation
    • I've checked the rendering of the Markdown text I've added
    • If I'm adding a new section, I've updated the Table of Content
  • I'm adding or updating code
    • I've added and/or updated tests
    • I've updated docs if needed
    • I've run npm run cs-format on my branch to conform my code to prettier coding style
  • I'm adding a new feature
    • I've updated the playground with an example use of the feature

@MatejBransky
Copy link
Author

I had an old fork so I had to solve some merge issues and some of them I overlooked and merged them incorrectly. Now it should be ok (tests pass).

FieldTemplate: this.props.FieldTemplate,
fields: this.props.fields,
widgets: this.props.widgets,
templates: this.props.templates,
Copy link
Contributor

@loganvolkers loganvolkers Aug 28, 2018

Choose a reason for hiding this comment

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

To maintain backwards compatibility with current props, you could check for the old props here and use them if they were provided.

Otherwise to be strict with Semver including this PR would mean releasing a V2.

If we include backwards compatible props, then this could be released as V1.1.

For example (this is pseudocode), this could provide backwards compatibility

  templates: {
      ...this.props.templates,
      ArrayFieldTemplate: this.props.ArrayFieldTemplate || this.props.templates.ArrayFieldTemplate,
      ObjectFieldTemplate: this.props.ObjectFieldTemplate || this.props.templates.ObjectFieldTemplate,
      FieldTemplate: this.props.FieldTemplate || this.props.templates.FieldTemplate,
      ErrorListTemplate: this.props.ErrorList || this.props.templates.ErrorListTemplate
  }

@glasserc do you think that maintaining backwards compatibility with props is important?

Copy link
Author

@MatejBransky MatejBransky Aug 28, 2018

Choose a reason for hiding this comment

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

I thought that this would be in v2 (I've updated the first comment with this info) but yes we can change it to support backward compatibility.

onBlur,
onFocus,
idPrefix,
rawErrors,
errors,
Copy link
Contributor

Choose a reason for hiding this comment

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

I don't see the benefit that renaming errors to rawErrors would provide.

I understand that the naming would be more clear, but the downside is that this introduces breaking changes.

Avoiding breaking changes means that this PR is easier to merge, easier to release and more people will get benefits earlier.

Copy link
Author

Choose a reason for hiding this comment

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

I wanted to mainly avoid adding another template (ErrorList from old SchemaField). Because component based errors needs UI component ErrorList which was in the old SchemaField.js. But sure we can take that back it probably means that I need to create another template for this ErrorList. What would be its name? ErrorListTemplate is taken by the template for list of all errors visible at the top of the form. So it should be the name which doesn't confuse devs.

Copy link
Contributor

Choose a reason for hiding this comment

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

I don't really understand this argument. What are we using this errors and how is it different from rawErrors that we had before?

@loganvolkers
Copy link
Contributor

@matejmazur I added some comments to your PR.

I have a feeling that there isn't really a requirement to have backwards-incompatible changes as part of this.

I also have a feeling that if this doesn't introduce backwards-incompatible changes, then it will be far easier to merge and release, and make Ethan's life easier.

@MatejBransky
Copy link
Author

MatejBransky commented Aug 28, 2018

@loganvolkers Thanks for your review! 👍
Backward compatibility is possible. I just didn't keep it in mind.

@Fedorov113
Copy link

Any update on this?

@MatejBransky
Copy link
Author

MatejBransky commented Oct 1, 2018

@Fedorov113
Unfortunately no, because nobody from contributors has responded yet (they are probably not interested into this or they don't have any time to review it).

By the way it was for me a lot of work to refactor it such a way that is just an improvement without any huge changes (I've tried multiple refactorings before this PR)..and still no response from maintainers. :-/

But at least I've learned something about forms and I've found out that it's one of the hardest parts in frontend...you need to solve so many edge cases. This library and JSON Schema helped me with it a lot. So huge thanks belong to all contributors who tried to keep it alive.

For now it's easier for me to use a private version with custom enhancements.

@HerbCaudill
Copy link
Contributor

Hi - I've been following this conversation from the beginning, because I think rjsf is amazing but would like to use something besides Bootstrap.

It seems clear for me that the future of this project has to be framework-independent. I've read through #623 and #899 etc. etc. and I understand that while @glasserc and other maintainers agree in principle, they don't have the time to make it happen.

@matejmazur seems to have gotten us 99% of the way there, but with breaking changes. So I wonder what the right way to move this forward is. Is there any interest in a v2? The only mention I've seen of that, outside of this PR, is #805. Or is it just a matter of addressing @loganvolkers's comments above to make these changes backwards-compatible?

@glasserc
Copy link
Contributor

glasserc commented Oct 3, 2018

Hi, sorry for taking so long to respond. In principle, what I would like to see is a move from "import rjsf and you get Bootstrap for free" to "import rjsf and one of the helper libraries; if you want Bootstrap, you have to say so explicitly". Fundamentally that's a breaking change and would have to be a major version. Even just changing from Bootstrap v3 to Bootstrap v4 feels like a breaking change to me. So I don't conceptually have a problem with other breaking changes happening at the same time.

I also don't have a good answer for what the way forward is. I also thought that this PR was the brightest path, but I guess I took too long to review it and now it's closed. I took a quick look before writing this comment and a lot of things are changing in this PR all at once, which makes it a bit hard to review. I tried to review commit-by-commit but since most of the changes are in the first commit, that doesn't really help. I sympathize with @matejmazur's difficulty in making a change that is both easily-reviewable and valuable.

It seems like fundamentally, most of the pieces are already in place -- we already have DescriptionField and TitleField. That's good and mostly what I expected. I guess mostly what we need is some cleanups around defining "themes" and extraction of the default BSv3 theme. I really do intend to review such a PR because it beats having to write it myself, but as noted, I can only put a limited amount of effort on the maintenance of rjsf and a lot of it gets sucked up by smaller issues.

@MatejBransky MatejBransky reopened this Oct 3, 2018
@MatejBransky
Copy link
Author

MatejBransky commented Oct 3, 2018

Finally! Glad to see your response, @glasserc ! 🙂 I understand that it's a huge change. Sorry about that but I did this in a rush (from a different repo).
Unfortunately I don't have time right now but if you could bring up some ideas how would you like to proceed next...I'll be glad for that.

Btw refactoring Bootstrap from 3 to 4 is the easiest part (it just depends on the separating of all UI components like is, for example, proposed in this PR).

This PR basically just move all *Template components from *Field components to separate files.

@HerbCaudill
Copy link
Contributor

what I would like to see is a move from "import rjsf and you get Bootstrap for free" to "import rjsf and one of the helper libraries; if you want Bootstrap, you have to say so explicitly". Fundamentally that's a breaking change and would have to be a major version.

That makes sense.

The alternative - "import rjsf and you get Bootstrap for free, unless you override it with your UI framework of choice" - seems reasonable as well, and would make the upgrade path to V2 a bit easier.

Along those lines, it seems like even if this effort results in a V2, @loganvolkers's suggestions for renaming things etc. to make it backwards-compatible would make it easier for people to upgrade. And an easy upgrade would mean less pressure to continue maintaining V1 in parallel.

I'd be happy to work on this - @matejmazur / @glasserc , let me know what you think would be helpful to move this forward.

Copy link
Contributor

@glasserc glasserc left a comment

Choose a reason for hiding this comment

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

I kind of agree with your point of view @HerbCaudill. Maybe the first step is to separate out the parts of the PR that add the functionality and organization we want, and merge that, with a remaining PR to do the restructuring of arguments and such.

I think the following things are pretty unobjectionable:

  • Fixes to typos in the README.
  • Extracting template classes into src/components/templates/. I think this is the biggest change by lines of code touched so separating this out would make reviewing the rest a lot easier.
  • Renaming classes that aren't exposed externally, e.g. TitleField to TitleTemplate. I think this reinforces the division of fields, widgets, and templates without causing any API breakage. On the other hand, maybe we want to keep these in sync with the prop names?
  • Adding the withTheme function. This might be helpful because we can introduce the new API here and maintain backwards compatibility here without tampering with the existing Form class.

Less clear to me:

  • We should add any new templates we need. I think this is only SubmitTemplate. How do we let a user pass SubmitTemplate? Do we start using this templates prop or do we rely on putting everything in the Form props for consistency until v2?
  • Internal reorganizations such as passing TitleField and DescriptionField through the registry instead of explicitly. I guess there's nothing wrong with it but maybe we should separate this change and review it by itself.

Things that would maybe wait until later:

  • Changing API to rely on a templates prop. We could make the change internally if we added backwards compatibility though.

I'd also love to see an example of using whatever API with another UI library such as Material. I'm not sure how much would have to change to use a different library. I'm nervous about how much we'd have to duplicate in e.g. widgets.

@@ -38,4 +89,5 @@ export default {
FileWidget,
CheckboxWidget,
CheckboxesWidget,
__widgetMap: widgetMap,
Copy link
Contributor

Choose a reason for hiding this comment

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

What's this change about?

@@ -1544,7 +1570,7 @@ Here are some examples from the [playground](http://mozilla-services.github.io/r
![](http://i.imgur.com/IMFqMwK.png)
![](http://i.imgur.com/HOACwt5.png)

Last, if you really really want to override the semantics generated by the lib, you can always create and use your own custom [widget](#custom-widget-components), [field](#custom-field-components) and/or [schema field](#custom-schemafield) components.
Last, if you really really want to override the semantics generated by the lib, you can always create and use your own custom [widget](#custom-widget-components), templates, [field](#custom-field-components) and/or [schema field](#custom-schemafield) components.
Copy link
Contributor

Choose a reason for hiding this comment

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

Shouldn't there be a link for templates?


A: There's no specific built-in way to do this, but you can write your own FieldTemplate that supports hiding/showing fields according to user input. We don't yet have an example of this use, but if you write one, please add it to the "tips and tricks" section, above. See also: [#268](https://github.com/mozilla-services/react-jsonschema-form/issues/268), [#304](https://github.com/mozilla-services/react-jsonschema-form/pull/304), [#598](https://github.com/mozilla-services/react-jsonschema-form/issues/598), [#920](https://github.com/mozilla-services/react-jsonschema-form/issues/920).
Copy link
Contributor

Choose a reason for hiding this comment

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

Shouldn't we keep the collapse Q?

onBlur,
onFocus,
idPrefix,
rawErrors,
errors,
Copy link
Contributor

Choose a reason for hiding this comment

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

I don't really understand this argument. What are we using this errors and how is it different from rawErrors that we had before?

@@ -415,6 +412,7 @@ class App extends Component {
</div>
<div className="col-sm-2">
<Form
idPrefix="live-validate"
Copy link
Contributor

Choose a reason for hiding this comment

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

What's this change about?


if (errors.length && showErrorList != false) {
return (
<ErrorList
<ErrorListTemplate
Copy link
Contributor

Choose a reason for hiding this comment

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

Why does this need to be a parameter now instead of coming from props?

<FieldTemplate {...templateProps}>
<Field {...fieldProps} />
</FieldTemplate>
);
Copy link
Contributor

Choose a reason for hiding this comment

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

What are these changes about?

@Fedorov113
Copy link

Sorry for bumping again, but @matejmazur haven't you look further into this?

@Fedorov113
Copy link

So, I,ve started implementing React Material UI forms using @matejmazur approach. The process is pretty straightforward and works like a charm. I really hope this great PR will be merged into master somewhere in the near future.

@rodrigopavezi
Copy link

Is there any chance this PR will be merged soon? We really need this. Cheers

@rodrigopavezi
Copy link

@Fedorov113 could you share what you have done so far with material-ui? Cheers

@mnlbox
Copy link

mnlbox commented Jan 14, 2019

Any news?
I need use this component with material-ui and also if possible with react-native. 🤔

@epicfaace
Copy link
Member

I think the following things are pretty unobjectionable:

  • Fixes to typos in the README.
  • Extracting template classes into src/components/templates/. I think this is the biggest change by lines of code touched so separating this out would make reviewing the rest a lot easier.
  • Renaming classes that aren't exposed externally, e.g. TitleField to TitleTemplate. I think this reinforces the division of fields, widgets, and templates without causing any API breakage. On the other hand, maybe we want to keep these in sync with the prop names?
  • Adding the withTheme function. This might be helpful because we can introduce the new API here and maintain backwards compatibility here without tampering with the existing Form class.

@MatejBransky Are you willing to open another PR with the "unobjectionable" changes of this pull request mentioned by @glasserc ? Then we should have no problem with merging it.

@sbusch
Copy link
Contributor

sbusch commented Feb 26, 2019

This PR should be included in V2 project IMO.

@videni
Copy link

videni commented Jul 15, 2019

@MatejBransky,how is this going? I really like this PR to be merged.

@epicfaace epicfaace closed this Sep 9, 2019
@epicfaace
Copy link
Member

I'm closing this because we already have a withTheme component, though if you'd like for any of the additional changes to be added to a future version (like v2), let me know.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

Successfully merging this pull request may close these issues.

10 participants