Skip to content

Commit

Permalink
Refs #63: Custom widgets registration.
Browse files Browse the repository at this point in the history
  • Loading branch information
n1k0 committed Mar 15, 2016
1 parent 0c52f01 commit 6f8b9f7
Show file tree
Hide file tree
Showing 8 changed files with 38 additions and 9 deletions.
5 changes: 4 additions & 1 deletion src/components/Form.js
Original file line number Diff line number Diff line change
Expand Up @@ -79,11 +79,12 @@ export default class Form extends Component {
return {
SchemaField: this.props.SchemaField || SchemaField,
TitleField: this.props.TitleField || TitleField,
widgets: this.props.widgets || {},
};
}

render() {
const {children, schema, uiSchema} = this.props;
const {children, schema, uiSchema, widgets} = this.props;
const {formData} = this.state;
const registry = this.getRegistry();
const _SchemaField = registry.SchemaField;
Expand All @@ -94,6 +95,7 @@ export default class Form extends Component {
schema={schema}
uiSchema={uiSchema}
formData={formData}
widgets={widgets}
onChange={this.onChange.bind(this)}
registry={registry}/>
{ children ? children : <p><button type="submit">Submit</button></p> }
Expand All @@ -107,6 +109,7 @@ if (process.env.NODE_ENV !== "production") {
schema: PropTypes.object.isRequired,
uiSchema: PropTypes.object,
formData: PropTypes.any,
widgets: PropTypes.object,
onChange: PropTypes.func,
onError: PropTypes.func,
onSubmit: PropTypes.func,
Expand Down
2 changes: 1 addition & 1 deletion src/components/fields/ArrayField.js
Original file line number Diff line number Diff line change
Expand Up @@ -69,7 +69,7 @@ class ArrayField extends Component {
const {schema, uiSchema, name} = this.props;
const title = schema.title || name;
const {items} = this.state;
const SchemaField = this.props.registry.SchemaField;
const {SchemaField} = this.props.registry;
if (isMultiSelect(schema)) {
return (
<SelectWidget
Expand Down
5 changes: 3 additions & 2 deletions src/components/fields/BooleanField.js
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,8 @@ import React, { PropTypes } from "react";
import { defaultFieldValue, getAlternativeWidget, optionsList } from "../../utils";
import CheckboxWidget from "./../widgets/CheckboxWidget";

function BooleanField({schema, name, uiSchema, formData, required, onChange}) {
function BooleanField(props) {
const {schema, name, uiSchema, formData, widgets, required, onChange} = props;
const {title, description} = schema;
const widget = uiSchema["ui:widget"];
const commonProps = {
Expand All @@ -16,7 +17,7 @@ function BooleanField({schema, name, uiSchema, formData, required, onChange}) {
required,
};
if (widget) {
const Widget = getAlternativeWidget(schema.type, widget);
const Widget = getAlternativeWidget(schema.type, widget, widgets);
return <Widget options={optionsList({enum: [true, false]})} {... commonProps} />;
}
return <CheckboxWidget {...commonProps} />;
Expand Down
2 changes: 1 addition & 1 deletion src/components/fields/ObjectField.js
Original file line number Diff line number Diff line change
Expand Up @@ -67,7 +67,7 @@ class ObjectField extends Component {
formData={this.state[name]}
onChange={this.onChange.bind(this, name)}
registry={this.props.registry} />
);
);
})
}</fieldset>
);
Expand Down
1 change: 1 addition & 0 deletions src/components/fields/SchemaField.js
Original file line number Diff line number Diff line change
Expand Up @@ -98,6 +98,7 @@ if (process.env.NODE_ENV !== "production") {
SchemaField.propTypes = {
schema: PropTypes.object.isRequired,
uiSchema: PropTypes.object,
registry: PropTypes.object,
};
}

Expand Down
7 changes: 4 additions & 3 deletions src/components/fields/StringField.js
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,8 @@ import TextWidget from "./../widgets/TextWidget";
import SelectWidget from "./../widgets/SelectWidget";


function StringField({schema, name, uiSchema, formData, required, onChange}) {
function StringField(props) {
const {schema, widgets, name, uiSchema, formData, required, onChange} = props;
const {title, description} = schema;
const widget = uiSchema["ui:widget"];
const commonProps = {
Expand All @@ -19,13 +20,13 @@ function StringField({schema, name, uiSchema, formData, required, onChange}) {
};
if (Array.isArray(schema.enum)) {
if (widget) {
const Widget = getAlternativeWidget(schema.type, widget);
const Widget = getAlternativeWidget(schema.type, widget, widgets);
return <Widget options={optionsList(schema)} {...commonProps} />;
}
return <SelectWidget options={optionsList(schema)} {...commonProps} />;
}
if (widget) {
const Widget = getAlternativeWidget(schema.type, widget);
const Widget = getAlternativeWidget(schema.type, widget, widgets);
return <Widget {...commonProps} />;
}
return <TextWidget {...commonProps} />;
Expand Down
5 changes: 4 additions & 1 deletion src/utils.js
Original file line number Diff line number Diff line change
Expand Up @@ -43,13 +43,16 @@ export function defaultFieldValue(formData, schema) {
return formData === null ? defaultTypeValue(schema.type) : formData;
}

export function getAlternativeWidget(type, widget) {
export function getAlternativeWidget(type, widget, registeredWidgets={}) {
if (typeof widget === "function") {
return widget;
}
if (typeof widget !== "string") {
throw new Error(`Unsupported widget definition: ${typeof widget}`);
}
if (widget in registeredWidgets) {
return registeredWidgets[widget];
}
if (!altWidgetMap.hasOwnProperty(type)) {
throw new Error(`No alternative widget for type ${type}`);
}
Expand Down
20 changes: 20 additions & 0 deletions test/index_test.js
Original file line number Diff line number Diff line change
Expand Up @@ -91,6 +91,26 @@ describe("Form", () => {
});
});

describe("Custom widgets", () => {
it("should support custom StringField widgets", () => {
const schema = {type: "string"};
const uiSchema = {"ui:widget": "foo"};
const foo = () => <div id="custom">yo</div>;
const {node} = createComponent({schema, uiSchema, widgets: {foo}});

expect(node.querySelector("#custom").textContent).eql("yo");
});

it("should support custom BooleanField widgets", () => {
const schema = {type: "boolean"};
const uiSchema = {"ui:widget": "foo"};
const foo = () => <div id="custom">yo</div>;
const {node} = createComponent({schema, uiSchema, widgets: {foo}});

expect(node.querySelector("#custom").textContent).eql("yo");
});
});

describe("Object fields ordering", () => {
const schema = {
type: "object",
Expand Down

0 comments on commit 6f8b9f7

Please sign in to comment.