diff --git a/README.md b/README.md index e316b86ec8..7d4f32d9fb 100644 --- a/README.md +++ b/README.md @@ -104,6 +104,7 @@ Here's a list of supported alternative widgets for different JSONSchema data typ #### `string`: * `textarea`: a `textarea` element; + * `password`: an `input[type=password]` element; * by default, a regular `input[type=text]` element is used. #### `number` and `integer`: diff --git a/playground/samples/nested.js b/playground/samples/nested.js index 54da1cac34..8bce1dff8b 100644 --- a/playground/samples/nested.js +++ b/playground/samples/nested.js @@ -10,9 +10,9 @@ module.exports = { }, tasks: { type: "array", + title: "Tasks", items: { type: "object", - title: "Task", required: ["title"], properties: { title: { diff --git a/playground/samples/simple.js b/playground/samples/simple.js index 660e56f587..3ebb047ff6 100644 --- a/playground/samples/simple.js +++ b/playground/samples/simple.js @@ -1,20 +1,47 @@ module.exports = { schema: { - title: "A simple todo entry", + title: "A registration form", type: "object", - required: ["title"], + required: ["firstName", "lastName"], properties: { - title: {type: "string", title: "Title", default: "A new task"}, - done: {type: "boolean", title: "Done?", default: false} + firstName: { + type: "string", + title: "First name", + }, + lastName: { + type: "string", + title: "Last name", + }, + age: { + type: "integer", + title: "Age" + }, + bio: { + type: "string", + title: "Bio", + }, + password: { + type: "string", + title: "Password" + } } }, uiSchema: { - done: { - widget: "radio" + age: { + widget: "updown" + }, + bio: { + widget: "textarea" + }, + password: { + widget: "password" } }, formData: { - title: "My task", - done: false + firstName: "Chuck", + lastName: "Norris", + age: 75, + bio: "Roundhouse kicking asses since 1940", + password: "noneed", } }; diff --git a/playground/styles.css b/playground/styles.css index 9448f6383d..af82d707ee 100644 --- a/playground/styles.css +++ b/playground/styles.css @@ -2,9 +2,14 @@ width: 200px; } -.rjsf input[type=text], .rjsf textarea { +.rjsf input[type=text], +.rjsf input[type=number], +.rjsf input[type=password], +.rjsf input[type=range], +.rjsf textarea, +.rjsf select { font-weight: normal; - width: 350px; + width: 320px; } .rjsf textarea { diff --git a/src/components/fields/ArrayField.js b/src/components/fields/ArrayField.js index 27dd908f5a..9b795b8ea0 100644 --- a/src/components/fields/ArrayField.js +++ b/src/components/fields/ArrayField.js @@ -63,7 +63,7 @@ class ArrayField extends Component { render() { const {schema, uiSchema, name} = this.props; - const title = name || schema.title; + const title = schema.title || name; const {items} = this.state; return (
onChange(event.target.value)} /> + ); +} + +if (process.env.NODE_ENV !== "production") { + PasswordWidget.propTypes = { + schema: PropTypes.object.isRequired, + label: PropTypes.string, + placeholder: PropTypes.string, + value: PropTypes.oneOfType([ + React.PropTypes.string, + React.PropTypes.number, + ]), + defaultValue: PropTypes.oneOfType([ + React.PropTypes.string, + React.PropTypes.number, + ]), + required: PropTypes.bool, + onChange: PropTypes.func, + }; +} + +export default PasswordWidget; diff --git a/src/components/widgets/RadioWidget.js b/src/components/widgets/RadioWidget.js index c9021cdcc4..d6da035fc6 100644 --- a/src/components/widgets/RadioWidget.js +++ b/src/components/widgets/RadioWidget.js @@ -3,7 +3,6 @@ import React, { PropTypes } from "react"; function RadioWidget({ schema, - type, options, label, placeholder, @@ -38,7 +37,6 @@ function RadioWidget({ if (process.env.NODE_ENV !== "production") { RadioWidget.propTypes = { schema: PropTypes.object.isRequired, - type: PropTypes.string.isRequired, options: PropTypes.array.isRequired, label: PropTypes.string, placeholder: PropTypes.string, diff --git a/src/components/widgets/RangeWidget.js b/src/components/widgets/RangeWidget.js index fe11524b41..08f512ca64 100644 --- a/src/components/widgets/RangeWidget.js +++ b/src/components/widgets/RangeWidget.js @@ -17,7 +17,6 @@ function rangeSpec(schema) { function RangeWidget({ schema, - type, label, placeholder, value, @@ -42,7 +41,6 @@ function RangeWidget({ if (process.env.NODE_ENV !== "production") { RangeWidget.propTypes = { schema: PropTypes.object.isRequired, - type: PropTypes.string.isRequired, label: PropTypes.string, placeholder: PropTypes.string, value: PropTypes.oneOfType([ diff --git a/src/components/widgets/SelectWidget.js b/src/components/widgets/SelectWidget.js index 2a06ea3b54..c2d2d09d5f 100644 --- a/src/components/widgets/SelectWidget.js +++ b/src/components/widgets/SelectWidget.js @@ -18,7 +18,6 @@ function processValue(type, value) { function SelectWidget({ schema, - type, options, label, placeholder, @@ -32,7 +31,9 @@ function SelectWidget({ title={placeholder} value={value} defaultValue={defaultValue} - onChange={(event) => onChange(processValue(type, event.target.value))}>{ + onChange={(event) => { + onChange(processValue(schema.type, event.target.value)); + }}>{ options.map((option, i) => { return ; }) @@ -43,7 +44,6 @@ function SelectWidget({ if (process.env.NODE_ENV !== "production") { SelectWidget.propTypes = { schema: PropTypes.object.isRequired, - type: PropTypes.string.isRequired, options: PropTypes.array.isRequired, label: PropTypes.string, placeholder: PropTypes.string, diff --git a/src/components/widgets/TextWidget.js b/src/components/widgets/TextWidget.js index f3ed7b9c35..d8b92a0b47 100644 --- a/src/components/widgets/TextWidget.js +++ b/src/components/widgets/TextWidget.js @@ -3,7 +3,6 @@ import React, { PropTypes } from "react"; function TextWidget({ schema, - type, label, placeholder, value, @@ -24,7 +23,6 @@ function TextWidget({ if (process.env.NODE_ENV !== "production") { TextWidget.propTypes = { schema: PropTypes.object.isRequired, - type: PropTypes.string.isRequired, label: PropTypes.string, placeholder: PropTypes.string, value: PropTypes.oneOfType([ diff --git a/src/components/widgets/TextareaWidget.js b/src/components/widgets/TextareaWidget.js index b2a58ee586..e52e0739fe 100644 --- a/src/components/widgets/TextareaWidget.js +++ b/src/components/widgets/TextareaWidget.js @@ -3,7 +3,6 @@ import React, { PropTypes } from "react"; function TextWidget({ schema, - type, label, placeholder, value, @@ -24,7 +23,6 @@ function TextWidget({ if (process.env.NODE_ENV !== "production") { TextWidget.propTypes = { schema: PropTypes.object.isRequired, - type: PropTypes.string.isRequired, label: PropTypes.string, placeholder: PropTypes.string, value: PropTypes.string, diff --git a/src/components/widgets/UpDownWidget.js b/src/components/widgets/UpDownWidget.js index eeda83e0d3..0619e63a08 100644 --- a/src/components/widgets/UpDownWidget.js +++ b/src/components/widgets/UpDownWidget.js @@ -17,7 +17,6 @@ function rangeSpec(schema) { function UpDownWidget({ schema, - type, label, placeholder, value, @@ -39,7 +38,6 @@ function UpDownWidget({ if (process.env.NODE_ENV !== "production") { UpDownWidget.propTypes = { schema: PropTypes.object.isRequired, - type: PropTypes.string.isRequired, label: PropTypes.string, placeholder: PropTypes.string, value: PropTypes.oneOfType([ diff --git a/src/utils.js b/src/utils.js index e1497970fc..99279113f0 100644 --- a/src/utils.js +++ b/src/utils.js @@ -1,3 +1,4 @@ +import PasswordWidget from "./components/widgets/PasswordWidget"; import RadioWidget from "./components/widgets/RadioWidget"; import UpDownWidget from "./components/widgets/UpDownWidget"; import RangeWidget from "./components/widgets/RangeWidget"; @@ -33,6 +34,7 @@ export function getAlternativeWidget(type, name) { break; case "string": switch(name) { + case "password": return PasswordWidget; case "radio": return RadioWidget; case "select": return SelectWidget; case "textarea": return TextareaWidget; diff --git a/test/index_test.js b/test/index_test.js index 0fa255d886..4e4e2d719c 100644 --- a/test/index_test.js +++ b/test/index_test.js @@ -589,6 +589,42 @@ describe("Form", () => { expect(comp.state.formData).eql({foo: "b"}); }); }); + + describe("password", () => { + const uiSchema = { + foo: { + widget: "password" + } + }; + + it("should accept a uiSchema object", () => { + const {node} = createComponent({schema, uiSchema}); + + expect(node.querySelectorAll("[type=password]")) + .to.have.length.of(1); + }); + + it("should support formData", () => { + const {node} = createComponent({schema, uiSchema, formData: { + foo: "a" + }}); + + expect(node.querySelector("[type=password]").value) + .eql("a"); + }); + + it("should update state when text is updated is checked", () => { + const {comp, node} = createComponent({schema, uiSchema, formData: { + foo: "a" + }}); + + Simulate.change(node.querySelector("[type=password]"), { + target: {value: "b"} + }); + + expect(comp.state.formData).eql({foo: "b"}); + }); + }); }); describe("string (enum)", () => {