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
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -4,3 +4,5 @@ build
dist
lib
yarn.lock
.vscode
.directory
122 changes: 77 additions & 45 deletions README.md

Large diffs are not rendered by default.

2 changes: 2 additions & 0 deletions diagram-arrayfield.svg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
2 changes: 2 additions & 0 deletions diagram-form.svg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
13 changes: 5 additions & 8 deletions playground/app.js
Original file line number Diff line number Diff line change
Expand Up @@ -266,6 +266,7 @@ function ThemeSelector({ theme, select }) {
};
return (
<Form
idPrefix="theme-selector"
schema={themeSchema}
formData={theme}
onChange={({ formData }) => select(formData, themes[formData])}>
Expand Down Expand Up @@ -346,15 +347,12 @@ class App extends Component {
}

load = data => {
// Reset the ArrayFieldTemplate whenever you load new data
const { ArrayFieldTemplate, ObjectFieldTemplate } = data;
// force resetting form component instance
this.setState({ form: false }, _ =>
this.setState({
...data,
form: true,
ArrayFieldTemplate,
ObjectFieldTemplate,
templates: data.templates,
})
);
};
Expand Down Expand Up @@ -400,8 +398,7 @@ class App extends Component {
validate,
theme,
editor,
ArrayFieldTemplate,
ObjectFieldTemplate,
templates,
transformErrors,
} = this.state;

Expand All @@ -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?

schema={liveValidateSchema}
formData={liveValidate}
onChange={this.setLiveValidate}>
Expand Down Expand Up @@ -455,8 +453,7 @@ class App extends Component {
<div className="col-sm-5">
{this.state.form && (
<Form
ArrayFieldTemplate={ArrayFieldTemplate}
ObjectFieldTemplate={ObjectFieldTemplate}
templates={templates}
liveValidate={liveValidate}
schema={schema}
uiSchema={uiSchema}
Expand Down
2 changes: 1 addition & 1 deletion playground/samples/customArray.js
Original file line number Diff line number Diff line change
Expand Up @@ -54,5 +54,5 @@ module.exports = {
},
},
formData: ["react", "jsonschema", "form"],
ArrayFieldTemplate,
templates: { ArrayFieldTemplate },
};
12 changes: 8 additions & 4 deletions playground/samples/customObject.js
Original file line number Diff line number Diff line change
@@ -1,9 +1,10 @@
import React from "react";

function ObjectFieldTemplate({ TitleField, properties, title, description }) {
function ObjectFieldTemplate({ registry, properties, title, description, id }) {
const { TitleTemplate, DescriptionTemplate } = registry.templates;
return (
<div>
<TitleField title={title} />
<TitleTemplate title={title} />
<div className="row">
{properties.map(prop => (
<div
Expand All @@ -13,7 +14,10 @@ function ObjectFieldTemplate({ TitleField, properties, title, description }) {
</div>
))}
</div>
{description}
<DescriptionTemplate
id={`${id}__description`}
description={description}
/>
</div>
);
}
Expand Down Expand Up @@ -61,5 +65,5 @@ module.exports = {
bio: "Roundhouse kicking asses since 1940",
password: "noneed",
},
ObjectFieldTemplate,
templates: { ObjectFieldTemplate },
};
50 changes: 18 additions & 32 deletions src/components/Form.js
Original file line number Diff line number Diff line change
@@ -1,14 +1,12 @@
import React, { Component } from "react";
import PropTypes from "prop-types";

import { default as DefaultErrorList } from "./ErrorList";
import {
getDefaultFormState,
retrieveSchema,
shouldRender,
toIdSchema,
setState,
getDefaultRegistry,
} from "../utils";
import validateFormData, { toErrorList } from "../validate";

Expand All @@ -19,7 +17,6 @@ export default class Form extends Component {
liveValidate: false,
safeRenderCompletion: false,
noHtml5Validate: false,
ErrorList: DefaultErrorList,
};

constructor(props) {
Expand Down Expand Up @@ -82,13 +79,13 @@ export default class Form extends Component {
);
}

renderErrors() {
renderErrors(ErrorListTemplate) {
const { errors, errorSchema, schema, uiSchema } = this.state;
const { ErrorList, showErrorList, formContext } = this.props;
const { showErrorList, formContext } = this.props;

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?

errors={errors}
errorSchema={errorSchema}
schema={schema}
Expand Down Expand Up @@ -157,15 +154,10 @@ export default class Form extends Component {
};

getRegistry() {
// For BC, accept passed SchemaField and TitleField props and pass them to
// the "fields" registry one.
const { fields, widgets } = getDefaultRegistry();
return {
fields: { ...fields, ...this.props.fields },
widgets: { ...widgets, ...this.props.widgets },
ArrayFieldTemplate: this.props.ArrayFieldTemplate,
ObjectFieldTemplate: this.props.ObjectFieldTemplate,
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.

definitions: this.props.schema.definitions || {},
formContext: this.props.formContext || {},
};
Expand All @@ -190,7 +182,10 @@ export default class Form extends Component {

const { schema, uiSchema, formData, errorSchema, idSchema } = this.state;
const registry = this.getRegistry();
const _SchemaField = registry.fields.SchemaField;
const {
fields: { SchemaField },
templates: { SubmitTemplate, ErrorListTemplate },
} = registry;

return (
<form
Expand All @@ -205,8 +200,8 @@ export default class Form extends Component {
acceptCharset={acceptcharset}
noValidate={noHtml5Validate}
onSubmit={this.onSubmit}>
{this.renderErrors()}
<_SchemaField
{this.renderErrors(ErrorListTemplate)}
<SchemaField
schema={schema}
uiSchema={uiSchema}
errorSchema={errorSchema}
Expand All @@ -219,15 +214,7 @@ export default class Form extends Component {
registry={registry}
safeRenderCompletion={safeRenderCompletion}
/>
{children ? (
children
) : (
<p>
<button type="submit" className="btn btn-info">
Submit
</button>
</p>
)}
{children ? children : <SubmitTemplate />}
</form>
);
}
Expand All @@ -240,12 +227,11 @@ if (process.env.NODE_ENV !== "production") {
formData: PropTypes.any,
widgets: PropTypes.objectOf(
PropTypes.oneOfType([PropTypes.func, PropTypes.object])
),
fields: PropTypes.objectOf(PropTypes.func),
ArrayFieldTemplate: PropTypes.func,
ObjectFieldTemplate: PropTypes.func,
FieldTemplate: PropTypes.func,
ErrorList: PropTypes.func,
).isRequired,
templates: PropTypes.objectOf(
PropTypes.oneOfType([PropTypes.func, PropTypes.object])
).isRequired,
fields: PropTypes.objectOf(PropTypes.func).isRequired,
onChange: PropTypes.func,
onError: PropTypes.func,
showErrorList: PropTypes.bool,
Expand Down
Loading