Skip to content

Commit b1e7bc6

Browse files
authored
Merge branch 'master' into supportOneOf
2 parents 832f94a + b4b8298 commit b1e7bc6

File tree

6 files changed

+98
-15
lines changed

6 files changed

+98
-15
lines changed

README.md

+26
Original file line numberDiff line numberDiff line change
@@ -45,6 +45,8 @@ A [live playground](https://mozilla-services.github.io/react-jsonschema-form/) i
4545
- [Autogenerated widget ids](#autogenerated-widget-ids)
4646
- [Form action buttons](#form-action-buttons)
4747
- [Help texts](#help-texts)
48+
- [Title texts](#title-texts)
49+
- [Description texts](#description-texts)
4850
- [Auto focus](#auto-focus)
4951
- [Textarea rows option](#textarea-rows-option)
5052
- [Placeholders](#placeholders)
@@ -640,6 +642,30 @@ const uiSchema = {
640642

641643
Help texts work for any kind of field at any level, and will always be rendered immediately below the field component widget(s), but after contextualized errors, if any.
642644

645+
### Title texts
646+
647+
Sometimes it's convenient to change title a field; this is the purpose of the `ui:title` uiSchema directive:
648+
649+
```js
650+
const schema = {type: "string"};
651+
const uiSchema = {
652+
"ui:widget": "password",
653+
"ui:title": "Your password"
654+
};
655+
```
656+
657+
### Description texts
658+
659+
Sometimes it's convenient to change description a field; this is the purpose of the `ui:description` uiSchema directive:
660+
661+
```js
662+
const schema = {type: "string"};
663+
const uiSchema = {
664+
"ui:widget": "password",
665+
"ui:description": "The best password"
666+
};
667+
```
668+
643669
### Auto focus
644670

645671
If you want to focus on a text input or textarea input/on a widget automatically, just set `ui:autofocus` uiSchema directive to `true`.

playground/samples/simple.js

+2
Original file line numberDiff line numberDiff line change
@@ -40,6 +40,8 @@ module.exports = {
4040
},
4141
age: {
4242
"ui:widget": "updown",
43+
"ui:title": "Age of person",
44+
"ui:description": "(earthian year)",
4345
},
4446
bio: {
4547
"ui:widget": "textarea",

src/components/fields/SchemaField.js

+6-2
Original file line numberDiff line numberDiff line change
@@ -193,8 +193,12 @@ function SchemaFieldRender(props) {
193193

194194
const { type } = schema;
195195
const id = idSchema.$id;
196-
const label = props.schema.title || schema.title || name;
197-
const description = props.schema.description || schema.description;
196+
const label =
197+
uiSchema["ui:title"] || props.schema.title || schema.title || name;
198+
const description =
199+
uiSchema["ui:description"] ||
200+
props.schema.description ||
201+
schema.description;
198202
const errors = __errors;
199203
const help = uiSchema["ui:help"];
200204
const hidden = uiSchema["ui:widget"] === "hidden";

src/utils.js

+12-12
Original file line numberDiff line numberDiff line change
@@ -128,7 +128,7 @@ function computeDefaults(schema, parentDefaults, definitions = {}) {
128128
switch (schema.type) {
129129
// We need to recur for object schema inner default values.
130130
case "object":
131-
return Object.keys(schema.properties).reduce((acc, key) => {
131+
return Object.keys(schema.properties || {}).reduce((acc, key) => {
132132
// Compute the defaults for this node, with the parent defaults we might
133133
// have from a previous run: defaults[key].
134134
acc[key] = computeDefaults(
@@ -304,21 +304,21 @@ export function isSelect(_schema, definitions = {}) {
304304
}
305305
return false;
306306
}
307-
307+
308308
export function isMultiSelect(schema, definitions = {}) {
309309
const itemsSchema = retrieveSchema(schema.items, definitions);
310-
if (!schema.uniqueItems) {
311-
return false;
312-
} else {
313-
return isSelect(itemsSchema);
314-
}
310+
return schema.items
311+
? schema.uniqueItems && isSelect(itemsSchema, definitions)
312+
: false;
315313
}
314+
316315
export function isFilesArray(schema, uiSchema, definitions = {}) {
317-
const itemsSchema = retrieveSchema(schema.items, definitions);
318-
return (
319-
(itemsSchema.type === "string" && itemsSchema.format === "data-url") ||
320-
uiSchema["ui:widget"] === "files"
321-
);
316+
if (uiSchema["ui:widget"] === "files") {
317+
return true;
318+
} else if (schema.items) {
319+
const itemsSchema = retrieveSchema(schema.items, definitions);
320+
return (itemsSchema.type === "string" && itemsSchema.format === "data-url")
321+
}
322322
}
323323

324324
export function isFixedItems(schema) {

test/uiSchema_test.js

+22
Original file line numberDiff line numberDiff line change
@@ -355,6 +355,28 @@ describe("uiSchema", () => {
355355
});
356356
});
357357

358+
describe("ui:title", () => {
359+
it("should render the provided title text", () => {
360+
const schema = { type: "string" };
361+
const uiSchema = { "ui:title": "plop" };
362+
363+
const { node } = createFormComponent({ schema, uiSchema });
364+
365+
expect(node.querySelector("label.control-label").textContent).eql("plop");
366+
});
367+
});
368+
369+
describe("ui:description", () => {
370+
it("should render the provided description text", () => {
371+
const schema = { type: "string" };
372+
const uiSchema = { "ui:description": "plop" };
373+
374+
const { node } = createFormComponent({ schema, uiSchema });
375+
376+
expect(node.querySelector("p.field-description").textContent).eql("plop");
377+
});
378+
});
379+
358380
it("should accept a react element as help", () => {
359381
const schema = { type: "string" };
360382
const uiSchema = { "ui:help": <b>plop</b> };

test/utils_test.js

+30-1
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@ import {
77
getDefaultFormState,
88
isConstant,
99
toConstant,
10+
isFilesArray,
1011
isMultiSelect,
1112
mergeObjects,
1213
pad,
@@ -45,6 +46,14 @@ describe("utils", () => {
4546
).to.eql({ string: "foo" });
4647
});
4748

49+
it("should default to empty object if no properties are defined", () => {
50+
expect(
51+
getDefaultFormState({
52+
type: "object",
53+
})
54+
).to.eql({});
55+
});
56+
4857
it("should recursively map schema object default to form state", () => {
4958
expect(
5059
getDefaultFormState({
@@ -305,6 +314,7 @@ describe("utils", () => {
305314
});
306315
});
307316

317+
308318
describe("isMultiSelect()", () => {
309319
describe("uniqueItems is true", () => {
310320
describe("schema items enum is an array", () => {
@@ -348,16 +358,35 @@ describe("utils", () => {
348358
const definitions = { FooItem: { type: "string", enum: ["foo"] } };
349359
expect(isMultiSelect(schema, definitions)).to.be.true;
350360
});
361+
362+
it("should be false if items is undefined", () => {
363+
const schema = {};
364+
expect(isMultiSelect(schema)).to.be.false;
365+
});
351366
});
352367

353368
describe("uniqueItems is false", () => {
354-
it("should be false if uniqueItems is false", () => {
369+
it("should be false", () => {
355370
const schema = { items: { enum: ["foo", "bar"] }, uniqueItems: false };
356371
expect(isMultiSelect(schema)).to.be.false;
357372
});
358373
});
359374
});
360375

376+
describe("isFilesArray()", () => {
377+
it("should be true if items have data-url format", () => {
378+
const schema = { items: { type: "string", format: "data-url" } };
379+
const uiSchema = {};
380+
expect(isFilesArray(schema, uiSchema)).to.be.true;
381+
});
382+
383+
it("should be false if items is undefined", () => {
384+
const schema = {};
385+
const uiSchema = {};
386+
expect(isFilesArray(schema, uiSchema)).to.be.false;
387+
});
388+
});
389+
361390
describe("mergeObjects()", () => {
362391
it("should't mutate the provided objects", () => {
363392
const obj1 = { a: 1 };

0 commit comments

Comments
 (0)