From 182b687723d92355f33e1aa42dad9dec4ab4b1bb Mon Sep 17 00:00:00 2001 From: Mathieu Agopian Date: Mon, 25 Apr 2016 16:29:29 +0200 Subject: [PATCH] Fixes #165: Add a ColorWidget. r=@n1k0 --- README.md | 1 + playground/samples/widgets.js | 8 +++ src/components/widgets/ColorWidget.js | 33 ++++++++++++ src/utils.js | 2 + test/StringField_test.js | 73 +++++++++++++++++++++++++++ test/uiSchema_test.js | 37 +++++++++++++- 6 files changed, 153 insertions(+), 1 deletion(-) create mode 100644 src/components/widgets/ColorWidget.js diff --git a/README.md b/README.md index 4d4571496f..e6e6ddcd4a 100644 --- a/README.md +++ b/README.md @@ -214,6 +214,7 @@ Here's a list of supported alternative widgets for different JSONSchema data typ * `textarea`: a `textarea` element is used; * `password`: an `input[type=password]` element is used; + * `color`: an `input[type=color]` element is used; * by default, a regular `input[type=text]` element is used. ##### String formats diff --git a/playground/samples/widgets.js b/playground/samples/widgets.js index 80c2971b0d..b0a09dd747 100644 --- a/playground/samples/widgets.js +++ b/playground/samples/widgets.js @@ -46,6 +46,11 @@ module.exports = { textarea: { type: "string", title: "textarea" + }, + color: { + type: "string", + title: "color picker", + default: "#151ce6" } } }, @@ -67,6 +72,9 @@ module.exports = { string: { textarea: { "ui:widget": "textarea" + }, + color: { + "ui:widget": "color" } }, secret: { diff --git a/src/components/widgets/ColorWidget.js b/src/components/widgets/ColorWidget.js new file mode 100644 index 0000000000..e44f3d7e02 --- /dev/null +++ b/src/components/widgets/ColorWidget.js @@ -0,0 +1,33 @@ +import React, { PropTypes } from "react"; + + +function ColorWidget({ + schema, + id, + placeholder, + value, + required, + onChange +}) { + return ( + onChange(event.target.value)} /> + ); +} + +if (process.env.NODE_ENV !== "production") { + ColorWidget.propTypes = { + schema: PropTypes.object.isRequired, + id: PropTypes.string.isRequired, + value: React.PropTypes.string, + required: PropTypes.bool, + onChange: PropTypes.func, + }; +} + +export default ColorWidget; diff --git a/src/utils.js b/src/utils.js index bef3d00594..e83c1a3b2a 100644 --- a/src/utils.js +++ b/src/utils.js @@ -15,6 +15,7 @@ import EmailWidget from "./components/widgets/EmailWidget"; import URLWidget from "./components/widgets/URLWidget"; import TextareaWidget from "./components/widgets/TextareaWidget"; import HiddenWidget from "./components/widgets/HiddenWidget"; +import ColorWidget from "./components/widgets/ColorWidget"; const RE_ERROR_ARRAY_PATH = /\[\d+]/g; @@ -34,6 +35,7 @@ const altWidgetMap = { datetime: DateTimeWidget, "alt-date": AltDateWidget, "alt-datetime": AltDateTimeWidget, + color: ColorWidget, }, number: { updown: UpDownWidget, diff --git a/test/StringField_test.js b/test/StringField_test.js index 41b7c3c200..52536fc300 100644 --- a/test/StringField_test.js +++ b/test/StringField_test.js @@ -816,4 +816,77 @@ describe("StringField", () => { .then(() => expect(comp.state.errors).to.have.length.of(1)); }); }); + + describe("ColorWidget", () => { + const uiSchema = {"ui:widget": "color"}; + const color = "#123456"; + + it("should render a color field", () => { + const {node} = createFormComponent({schema: { + type: "string", + format: "color", + }, uiSchema}); + + expect(node.querySelectorAll(".field [type=color]")) + .to.have.length.of(1); + }); + + it("should assign a default value", () => { + const {comp} = createFormComponent({schema: { + type: "string", + format: "color", + default: color, + }, uiSchema}); + + expect(comp.state.formData).eql(color); + }); + + it("should reflect the change into the dom", () => { + const {node} = createFormComponent({schema: { + type: "string", + format: "color", + }, uiSchema}); + + const newColor = "#654321"; + return SimulateAsync().change(node.querySelector("[type=color]"), { + target: {value: newColor} + }) + .then(() => { + return expect(node.querySelector("[type=color]").value) + .eql(newColor); + }); + }); + + it("should fill field with data", () => { + const {comp} = createFormComponent({schema: { + type: "string", + format: "color", + }, formData: color}); + + expect(comp.state.formData).eql(color); + }); + + it("should render the widget with the expected id", () => { + const {node} = createFormComponent({schema: { + type: "string", + format: "color", + }, uiSchema}); + + expect(node.querySelector("[type=color]").id) + .eql("root"); + }); + + + it("should reject an invalid entered color", () => { + const {comp, node} = createFormComponent({schema: { + type: "string", + format: "color", + }, uiSchema, liveValidate: true}); + + return SimulateAsync().change(node.querySelector("[type=color]"), { + target: {value: "invalid"} + }) + .then(() => expect(comp.state.errors).to.have.length.of(1)); + }); + }); }); diff --git a/test/uiSchema_test.js b/test/uiSchema_test.js index efb08c9203..9eb0e9525b 100644 --- a/test/uiSchema_test.js +++ b/test/uiSchema_test.js @@ -148,7 +148,7 @@ describe("uiSchema", () => { .eql("a"); }); - it("should update state when text is updated is checked", () => { + it("should update state when text is updated", () => { const {comp, node} = createFormComponent({schema, uiSchema, formData: { foo: "a" }}); @@ -195,6 +195,41 @@ describe("uiSchema", () => { }); }); + describe("color", () => { + const uiSchema = { + foo: { + "ui:widget": "color" + } + }; + + it("should accept a uiSchema object", () => { + const {node} = createFormComponent({schema, uiSchema}); + + expect(node.querySelectorAll("[type=color]")) + .to.have.length.of(1); + }); + + it("should support formData", () => { + const {node} = createFormComponent({schema, uiSchema, formData: { + foo: "#151ce6" + }}); + + expect(node.querySelector("[type=color]").value) + .eql("#151ce6"); + }); + + it("should update state when text is updated", () => { + const {comp, node} = createFormComponent({schema, uiSchema, formData: { + foo: "#151ce6" + }}); + + return SimulateAsync().change(node.querySelector("[type=color]"), { + target: {value: "#001122"} + }) + .then(() => expect(comp.state.formData).eql({foo: "#001122"})); + }); + }); + describe("hidden", () => { const uiSchema = { foo: {