Skip to content

Commit

Permalink
Fixes #165: Add a ColorWidget. r=@n1k0
Browse files Browse the repository at this point in the history
  • Loading branch information
magopian authored and n1k0 committed Apr 25, 2016
1 parent 69c95d1 commit 182b687
Show file tree
Hide file tree
Showing 6 changed files with 153 additions and 1 deletion.
1 change: 1 addition & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
8 changes: 8 additions & 0 deletions playground/samples/widgets.js
Original file line number Diff line number Diff line change
Expand Up @@ -46,6 +46,11 @@ module.exports = {
textarea: {
type: "string",
title: "textarea"
},
color: {
type: "string",
title: "color picker",
default: "#151ce6"
}
}
},
Expand All @@ -67,6 +72,9 @@ module.exports = {
string: {
textarea: {
"ui:widget": "textarea"
},
color: {
"ui:widget": "color"
}
},
secret: {
Expand Down
33 changes: 33 additions & 0 deletions src/components/widgets/ColorWidget.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
import React, { PropTypes } from "react";


function ColorWidget({
schema,
id,
placeholder,
value,
required,
onChange
}) {
return (
<input type="color"
id={id}
className="form-control"
value={typeof value === "undefined" ? "" : value}
placeholder={placeholder}
required={required}
onChange={(event) => 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;
2 changes: 2 additions & 0 deletions src/utils.js
Original file line number Diff line number Diff line change
Expand Up @@ -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;

Expand All @@ -34,6 +35,7 @@ const altWidgetMap = {
datetime: DateTimeWidget,
"alt-date": AltDateWidget,
"alt-datetime": AltDateTimeWidget,
color: ColorWidget,
},
number: {
updown: UpDownWidget,
Expand Down
73 changes: 73 additions & 0 deletions test/StringField_test.js
Original file line number Diff line number Diff line change
Expand Up @@ -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));
});
});
});
37 changes: 36 additions & 1 deletion test/uiSchema_test.js
Original file line number Diff line number Diff line change
Expand Up @@ -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"
}});
Expand Down Expand Up @@ -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: {
Expand Down

0 comments on commit 182b687

Please sign in to comment.