Repository: mozilla-services/react-jsonschema-form (js)

Issue:
Name should not be required for properties in data-url format
### Prerequisites

- [ Yes] I have read the [documentation](https://github.com/mozilla-services/react-jsonschema-form/blob/master/README.md#readme);
- [Yes ] In the case of a bug report, I understand that providing a [SSCCE](http://sscce.org/) example is tremendously useful to the maintainers.

### Description

[Thank you for this awesome library. I have been using it extensively. Our primary work for this library to build ui dynamically through custom widgets using materil-ui and some others. Recently I created a custom file upload widget using https://github.com/react-dropzone/react-dropzone  As I was going through documentation it says file widget only supports data-url. So i got bit worried how i will get to know file name since data-url does not contain file name. So I decided to skip name entirely continued my work. After completing file upload widget when I tested it, it kept on giving me this error file is not of type data-uri. Here is how I was setting its value
handleOnDropAccepeted(file){
        let uploadedFilesNames = [];

        let reader = new FileReader();
        reader.readAsDataURL(file[0]);
        reader.onloadend = () => {
            this.props.onChange(reader.result);
        }
    }

It boggled me for hours as I could not figure out why it is not working. Then upon looking into your code I saw you are also encoding file name there in base64 and if we did not encode file name in string it will complain saying string data is not valid data-uri. So please mention this in your documentation for custom file upload widget you also need to encode file name there as well. Here is how my code looks now
export const addNameToDataURI=(dataURL, name)=>{
  return dataURL.replace(";base64", `;name=${name};base64`);
}

handleOnDropAccepeted(file){
        let uploadedFilesNames = [];

        let reader = new FileReader();
        reader.readAsDataURL(file[0]);
        reader.onloadend = () => {
            this.props.onChange(addNameToDataURI(reader.result, file[0].name));
        }
    }

as you can see encoding name into file is basically function from your code source
]

### Steps to Reproduce

1. [First Step]
2. [Second Step]
3. [and so on...]

Ideally, I'm providing a [sample JSFiddle](https://jsfiddle.net/n1k0/f2y3fq7L/6/) or a [shared playground link](https://mozilla-services.github.io/react-jsonschema-form/) demonstrating the issue.

#### Expected behavior

[What you expected to happen]

#### Actual behavior

[What actually happened]

### Version

You can usually get this information in your `package.json` or in the file URL if you're using the unpkg one.


Pull request description:
Fixes #824
### Reasons for making this change

See Issue #824, made name not required.

### Checklist

* [ ] **I'm updating documentation**
  - [ ] I've checked the rendering of the Markdown text I've added
  - [ ] If I'm adding a new section, I've updated the Table of Content
* [ ] **I'm adding or updating code**
  - [ ] I've added and/or updated tests
  - [ ] I've updated docs if needed
  - [X] I've run `npm run cs-format` on my branch to conform my code to [prettier](https://github.com/prettier/prettier) coding style
* [ ] **I'm adding a new feature**
  - [ ] I've updated the playground with an example use of the feature


Patch:
diff --git a/docs/index.md b/docs/index.md
index a844300b3..e1550ef85 100644
--- a/docs/index.md
+++ b/docs/index.md
@@ -173,7 +173,7 @@ Here are some examples from the [playground](http://mozilla-services.github.io/r
 ![](https://i.imgur.com/IMFqMwK.png)
 ![](https://i.imgur.com/HOACwt5.png)
 
-Last, if you really really want to override the semantics generated by the lib, you can always create and use your own custom [widget](#custom-widget-components), [field](#custom-field-components) and/or [schema field](#custom-schemafield) components.
+Last, if you really really want to override the semantics generated by the lib, you can always create and use your own custom [widget](advanced-customization.md#custom-widget-components), [field](advanced-customization.md#custom-field-components) and/or [schema field](advanced-customization.md#custom-schemafield) components.
 
 
 ## JSON Schema supporting status
@@ -188,7 +188,9 @@ This component follows [JSON Schema](http://json-schema.org/documentation.html)
 
     The `anyOf`  and `oneOf` keywords are supported,  however, properties declared inside the `anyOf/oneOf` should not overlap with properties "outside" of the `anyOf/oneOf`.
 
-    You can also use `oneOf` with [schema dependencies](#schema-dependencies) to dynamically add schema properties based on input data.
+    You can also use `oneOf` with [schema dependencies](dependencies.md#schema-dependencies) to dynamically add schema properties based on input data.
+
+* `"additionalProperties":false` produces incorrect schemas when used with [schema dependencies](#schema-dependencies). This library does not remove extra properties, which causes validation to fail. It is recommended to avoid setting `"additionalProperties":false` when you use schema dependencies. See [#848](https://github.com/mozilla-services/react-jsonschema-form/issues/848) [#902](https://github.com/mozilla-services/react-jsonschema-form/issues/902) [#992](https://github.com/mozilla-services/react-jsonschema-form/issues/992)
 
 ## Tips and tricks
 
@@ -272,7 +274,7 @@ $ git push --tags origin master
 ### Q: Does rjsf support `oneOf`, `anyOf`, multiple types in an array, etc.?
 
 A: The `anyOf`  and `oneOf` keywords are supported,  however, properties declared inside the `anyOf/oneOf` should not overlap with properties "outside" of the `anyOf/oneOf`.
-There is also special cased where you can use `oneOf` in [schema dependencies](#schema-dependencies), If you'd like to help improve support for these keywords, see the following issues for inspiration [#329](https://github.com/mozilla-services/react-jsonschema-form/pull/329) or [#417](https://github.com/mozilla-services/react-jsonschema-form/pull/417). See also: [#52](https://github.com/mozilla-services/react-jsonschema-form/issues/52), [#151](https://github.com/mozilla-services/react-jsonschema-form/issues/151), [#171](https://github.com/mozilla-services/react-jsonschema-form/issues/171), [#200](https://github.com/mozilla-services/react-jsonschema-form/issues/200), [#282](https://github.com/mozilla-services/react-jsonschema-form/issues/282), [#302](https://github.com/mozilla-services/react-jsonschema-form/pull/302), [#330](https://github.com/mozilla-services/react-jsonschema-form/issues/330), [#430](https://github.com/mozilla-services/react-jsonschema-form/issues/430), [#522](https://github.com/mozilla-services/react-jsonschema-form/issues/522), [#538](https://github.com/mozilla-services/react-jsonschema-form/issues/538), [#551](https://github.com/mozilla-services/react-jsonschema-form/issues/551), [#552](https://github.com/mozilla-services/react-jsonschema-form/issues/552), or [#648](https://github.com/mozilla-services/react-jsonschema-form/issues/648).
+There is also special cased where you can use `oneOf` in [schema dependencies](dependencies.md#schema-dependencies), If you'd like to help improve support for these keywords, see the following issues for inspiration [#329](https://github.com/mozilla-services/react-jsonschema-form/pull/329) or [#417](https://github.com/mozilla-services/react-jsonschema-form/pull/417). See also: [#52](https://github.com/mozilla-services/react-jsonschema-form/issues/52), [#151](https://github.com/mozilla-services/react-jsonschema-form/issues/151), [#171](https://github.com/mozilla-services/react-jsonschema-form/issues/171), [#200](https://github.com/mozilla-services/react-jsonschema-form/issues/200), [#282](https://github.com/mozilla-services/react-jsonschema-form/issues/282), [#302](https://github.com/mozilla-services/react-jsonschema-form/pull/302), [#330](https://github.com/mozilla-services/react-jsonschema-form/issues/330), [#430](https://github.com/mozilla-services/react-jsonschema-form/issues/430), [#522](https://github.com/mozilla-services/react-jsonschema-form/issues/522), [#538](https://github.com/mozilla-services/react-jsonschema-form/issues/538), [#551](https://github.com/mozilla-services/react-jsonschema-form/issues/551), [#552](https://github.com/mozilla-services/react-jsonschema-form/issues/552), or [#648](https://github.com/mozilla-services/react-jsonschema-form/issues/648).
 
 ### Q: Will react-jsonschema-form support Material, Ant-Design, Foundation, or [some other specific widget library or frontend style]?
 
diff --git a/docs/validation.md b/docs/validation.md
index 8558174da..4978ba707 100644
--- a/docs/validation.md
+++ b/docs/validation.md
@@ -88,7 +88,7 @@ render((
 ), document.getElementById("app"));
 ```
 
-> Note: you can also use your own [ErrorList](#error-list-template)
+> Note: you can also use your own [ErrorList](advanced-customization.md#error-list-template)
 
 ### The case of empty strings
 
diff --git a/mkdocs.yml b/mkdocs.yml
index 83ce2c8c6..d3d8fcbdc 100644
--- a/mkdocs.yml
+++ b/mkdocs.yml
@@ -9,4 +9,8 @@ nav:
   - Dependencies: dependencies.md
   - Form Customization: form-customization.md
   - Validation: validation.md
-  - Playground: https://mozilla-services.github.io/react-jsonschema-form/
\ No newline at end of file
+  - Playground: https://mozilla-services.github.io/react-jsonschema-form/
+
+markdown_extensions:
+  - toc:
+      permalink: true
\ No newline at end of file
diff --git a/src/components/fields/MultiSchemaField.js b/src/components/fields/MultiSchemaField.js
index e11b9434a..593590e6b 100644
--- a/src/components/fields/MultiSchemaField.js
+++ b/src/components/fields/MultiSchemaField.js
@@ -30,7 +30,49 @@ class AnyOfField extends Component {
 
   getMatchingOption(formData, options) {
     for (let i = 0; i < options.length; i++) {
-      if (isValid(options[i], formData)) {
+      const option = options[i];
+
+      // If the schema describes an object then we need to add slightly more
+      // strict matching to the schema, because unless the schema uses the
+      // "requires" keyword, an object will match the schema as long as it
+      // doesn't have matching keys with a conflicting type. To do this we use an
+      // "anyOf" with an array of requires. This augmentation expresses that the
+      // schema should match if any of the keys in the schema are present on the
+      // object and pass validation.
+      if (option.properties) {
+        // Create an "anyOf" schema that requires at least one of the keys in the
+        // "properties" object
+        const requiresAnyOf = {
+          anyOf: Object.keys(option.properties).map(key => ({
+            required: [key],
+          })),
+        };
+
+        let augmentedSchema;
+
+        // If the "anyOf" keyword already exists, wrap the augmentation in an "allOf"
+        if (option.anyOf) {
+          // Create a shallow clone of the option
+          const { ...shallowClone } = option;
+
+          if (!shallowClone.allOf) {
+            shallowClone.allOf = [];
+          } else {
+            // If "allOf" already exists, shallow clone the array
+            shallowClone.allOf = shallowClone.allOf.slice();
+          }
+
+          shallowClone.allOf.push(requiresAnyOf);
+
+          augmentedSchema = shallowClone;
+        } else {
+          augmentedSchema = Object.assign({}, option, requiresAnyOf);
+        }
+
+        if (isValid(augmentedSchema, formData)) {
+          return i;
+        }
+      } else if (isValid(options[i], formData)) {
         return i;
       }
     }
diff --git a/src/validate.js b/src/validate.js
index 222b16328..80d599bd4 100644
--- a/src/validate.js
+++ b/src/validate.js
@@ -8,7 +8,7 @@ const ajv = new Ajv({
 // add custom formats
 ajv.addFormat(
   "data-url",
-  /^data:([a-z]+\/[a-z0-9-+.]+)?;name=(.*);base64,(.*)$/
+  /^data:([a-z]+\/[a-z0-9-+.]+)?;(?:name=(.*);)?base64,(.*)$/
 );
 ajv.addFormat(
   "color",


Test patch:
diff --git a/test/anyOf_test.js b/test/anyOf_test.js
index cc845af6f..51566c3bf 100644
--- a/test/anyOf_test.js
+++ b/test/anyOf_test.js
@@ -300,6 +300,235 @@ describe("anyOf", () => {
     expect(node.querySelector("select").value).eql("1");
   });
 
+  it("should not change the selected option when entering values", () => {
+    const schema = {
+      type: "object",
+      anyOf: [
+        {
+          title: "First method of identification",
+          properties: {
+            firstName: {
+              type: "string",
+            },
+            lastName: {
+              type: "string",
+            },
+          },
+        },
+        {
+          title: "Second method of identification",
+          properties: {
+            idCode: {
+              type: "string",
+            },
+          },
+        },
+      ],
+    };
+
+    const { node } = createFormComponent({
+      schema,
+    });
+
+    const $select = node.querySelector("select");
+
+    expect($select.value).eql("0");
+
+    Simulate.change($select, {
+      target: { value: $select.options[1].value },
+    });
+
+    expect($select.value).eql("1");
+
+    Simulate.change(node.querySelector("input#root_idCode"), {
+      target: { value: "Lorem ipsum dolor sit amet" },
+    });
+
+    expect($select.value).eql("1");
+  });
+
+  it("should not change the selected option when entering values and the subschema uses `anyOf`", () => {
+    const schema = {
+      type: "object",
+      anyOf: [
+        {
+          title: "First method of identification",
+          properties: {
+            firstName: {
+              type: "string",
+            },
+            lastName: {
+              type: "string",
+            },
+          },
+        },
+        {
+          title: "Second method of identification",
+          properties: {
+            idCode: {
+              type: "string",
+            },
+          },
+          anyOf: [
+            {
+              properties: {
+                foo: {
+                  type: "string",
+                },
+              },
+            },
+            {
+              properties: {
+                bar: {
+                  type: "string",
+                },
+              },
+            },
+          ],
+        },
+      ],
+    };
+
+    const { node } = createFormComponent({
+      schema,
+    });
+
+    const $select = node.querySelector("select");
+
+    expect($select.value).eql("0");
+
+    Simulate.change($select, {
+      target: { value: $select.options[1].value },
+    });
+
+    expect($select.value).eql("1");
+
+    Simulate.change(node.querySelector("input#root_idCode"), {
+      target: { value: "Lorem ipsum dolor sit amet" },
+    });
+
+    expect($select.value).eql("1");
+  });
+
+  it("should not change the selected option when entering values and the subschema uses `allOf`", () => {
+    const schema = {
+      type: "object",
+      anyOf: [
+        {
+          title: "First method of identification",
+          properties: {
+            firstName: {
+              type: "string",
+            },
+            lastName: {
+              type: "string",
+            },
+          },
+        },
+        {
+          title: "Second method of identification",
+          properties: {
+            idCode: {
+              type: "string",
+            },
+          },
+          allOf: [
+            {
+              properties: {
+                foo: {
+                  type: "string",
+                },
+              },
+            },
+            {
+              properties: {
+                bar: {
+                  type: "string",
+                },
+              },
+            },
+          ],
+        },
+      ],
+    };
+
+    const { node } = createFormComponent({
+      schema,
+    });
+
+    const $select = node.querySelector("select");
+
+    expect($select.value).eql("0");
+
+    Simulate.change($select, {
+      target: { value: $select.options[1].value },
+    });
+
+    expect($select.value).eql("1");
+
+    Simulate.change(node.querySelector("input#root_idCode"), {
+      target: { value: "Lorem ipsum dolor sit amet" },
+    });
+
+    expect($select.value).eql("1");
+  });
+
+  it("should not mutate a schema that contains nested anyOf and allOf", () => {
+    const schema = {
+      type: "object",
+      anyOf: [
+        {
+          properties: {
+            foo: { type: "string" },
+          },
+          allOf: [
+            {
+              properties: {
+                baz: { type: "string" },
+              },
+            },
+          ],
+          anyOf: [
+            {
+              properties: {
+                buzz: { type: "string" },
+              },
+            },
+          ],
+        },
+      ],
+    };
+
+    createFormComponent({
+      schema,
+    });
+
+    expect(schema).to.eql({
+      type: "object",
+      anyOf: [
+        {
+          properties: {
+            foo: { type: "string" },
+          },
+          allOf: [
+            {
+              properties: {
+                baz: { type: "string" },
+              },
+            },
+          ],
+          anyOf: [
+            {
+              properties: {
+                buzz: { type: "string" },
+              },
+            },
+          ],
+        },
+      ],
+    });
+  });
+
   describe("Arrays", () => {
     it("should correctly render form inputs for anyOf inside array items", () => {
       const schema = {
diff --git a/test/validate_test.js b/test/validate_test.js
index cb437e894..072ed61ec 100644
--- a/test/validate_test.js
+++ b/test/validate_test.js
@@ -134,6 +134,32 @@ describe("Validation", () => {
       });
     });
 
+    describe("Data-Url validation", () => {
+      const schema = {
+        type: "object",
+        properties: {
+          dataUrlWithName: { type: "string", format: "data-url" },
+          dataUrlWithoutName: { type: "string", format: "data-url" },
+        },
+      };
+
+      it("Data-Url with name is accepted", () => {
+        const formData = {
+          dataUrlWithName: "data:text/plain;name=file1.txt;base64,x=",
+        };
+        const result = validateFormData(formData, schema);
+        expect(result.errors).to.have.length.of(0);
+      });
+
+      it("Data-Url without name is accepted", () => {
+        const formData = {
+          dataUrlWithoutName: "data:text/plain;base64,x=",
+        };
+        const result = validateFormData(formData, schema);
+        expect(result.errors).to.have.length.of(0);
+      });
+    });
+
     describe("toErrorList()", () => {
       it("should convert an errorSchema into a flat list", () => {
         expect(