├── .gitignore
├── .npmignore
├── .travis.yml
├── .vscode
└── settings.json
├── LICENSE
├── README.md
├── docs
├── asset-manifest.json
├── favicon.ico
├── index.html
├── manifest.json
├── service-worker.js
└── static
│ ├── css
│ ├── main.1d316427.css
│ └── main.1d316427.css.map
│ ├── js
│ ├── main.f2da4b7a.js
│ └── main.f2da4b7a.js.map
│ └── media
│ ├── dynamic_docs.c45dd5e7.md
│ ├── form_docs.c680d6e1.md
│ ├── forms.aec5c7b8.png
│ ├── getting_started.2be5c59d.md
│ ├── glyphicons-halflings-regular.448c34a5.woff2
│ ├── glyphicons-halflings-regular.89889688.svg
│ ├── glyphicons-halflings-regular.e18bbf61.ttf
│ ├── glyphicons-halflings-regular.f4769f9b.eot
│ ├── glyphicons-halflings-regular.fa277232.woff
│ ├── intro.fda87512.md
│ ├── list_docs.12101c16.md
│ └── schema_docs.01abfc75.md
├── lerna.json
├── package.json
└── packages
├── react-dynamic-forms
├── .babelrc
├── .eslintrc
├── CONTRIBUTING.md
├── LICENSE
├── README.md
├── lib
│ ├── components
│ │ ├── CheckBoxes.js
│ │ ├── Chooser.js
│ │ ├── DateEdit.js
│ │ ├── Field.js
│ │ ├── Form.js
│ │ ├── List.js
│ │ ├── RadioButtons.js
│ │ ├── Schema.js
│ │ ├── TagsEdit.js
│ │ ├── TextArea.js
│ │ ├── TextEdit.js
│ │ └── View.js
│ ├── css
│ │ ├── chooser.css
│ │ ├── dateedit.css
│ │ ├── group.css
│ │ ├── icon.css
│ │ ├── list.css
│ │ ├── select.css
│ │ ├── tagsedit.css
│ │ ├── textarea.css
│ │ └── textedit.css
│ ├── index.js
│ └── js
│ │ ├── constants.js
│ │ ├── formGroup.js
│ │ └── formList.js
├── package-lock.json
├── package.json
├── public
│ ├── favicon.ico
│ └── index.html
├── src
│ ├── components
│ │ ├── CheckBoxes.js
│ │ ├── Chooser.js
│ │ ├── DateEdit.js
│ │ ├── Field.js
│ │ ├── Form.js
│ │ ├── List.js
│ │ ├── RadioButtons.js
│ │ ├── Schema.js
│ │ ├── TagsEdit.js
│ │ ├── TextArea.js
│ │ ├── TextEdit.js
│ │ └── View.js
│ ├── css
│ │ ├── chooser.css
│ │ ├── dateedit.css
│ │ ├── group.css
│ │ ├── icon.css
│ │ ├── list.css
│ │ ├── select.css
│ │ ├── tagsedit.css
│ │ ├── textarea.css
│ │ └── textedit.css
│ ├── index.js
│ └── js
│ │ ├── constants.js
│ │ ├── formGroup.js
│ │ └── formList.js
├── tests
│ ├── ChooserTests.js
│ ├── TextEditTests.js
│ ├── __snapshots__
│ │ └── textedit.test.js.snap
│ ├── components_test
│ │ ├── ChooserExamples.js
│ │ └── TextEditExamples.js
│ └── textedit.test.js
└── yarn.lock
└── website
├── .gitignore
├── README.md
├── forms.png
├── package-lock.json
├── package.json
├── public
├── favicon.ico
├── index.html
└── manifest.json
├── src
├── App.css
├── App.js
├── Header.js
├── Sidebar.js
├── api
│ └── docs.json
├── components
│ ├── API.js
│ ├── APIDoc.js
│ ├── Example.js
│ ├── Guide.js
│ └── Highlighter.js
├── examples
│ ├── dynamic
│ │ ├── Index.js
│ │ ├── dynamic_docs.md
│ │ └── dynamic_thumbnail.png
│ ├── examples.js
│ ├── examples.json
│ ├── form
│ │ ├── Index.js
│ │ ├── form_docs.md
│ │ └── form_thumbnail.png
│ ├── list
│ │ ├── Index.js
│ │ ├── list_docs.md
│ │ └── list_thumbnail.png
│ └── schema
│ │ ├── Index.js
│ │ ├── schema_docs.md
│ │ └── schema_thumbnail.png
├── guides
│ ├── getting_started.md
│ ├── guides.js
│ └── intro.md
├── img
│ ├── forms.png
│ └── github.png
├── index.css
├── index.js
├── renderers.js
└── styles.js
└── yarn.lock
/.gitignore:
--------------------------------------------------------------------------------
1 | node_modules
2 | *.log
3 | .DS_Store
4 | npm-debug.log
5 | examples-bundle.js
--------------------------------------------------------------------------------
/.npmignore:
--------------------------------------------------------------------------------
1 | src/
2 | examples/
3 | screenshots/
4 | docs/
5 | bin/
6 | build/global
7 | index.html
8 | .eslintrc
9 | .gitignore
10 | CONTRIBUTING.md
11 | examples-bundle.js
12 | examples-bundle.js.map
13 | *.config.js
14 | .DS_Store
15 | npm-debug.log
16 |
--------------------------------------------------------------------------------
/.travis.yml:
--------------------------------------------------------------------------------
1 | sudo: false
2 | language: node_js
3 | node_js:
4 | - "0.12"
5 | notifications:
6 | email: false
7 |
--------------------------------------------------------------------------------
/.vscode/settings.json:
--------------------------------------------------------------------------------
1 | {
2 | "git.ignoreLimitWarning": true
3 | }
--------------------------------------------------------------------------------
/LICENSE:
--------------------------------------------------------------------------------
1 | "ESnet React Forms Library, Copyright (c) 2015-2017, The Regents of the
2 | University of California, through Lawrence Berkeley National Laboratory
3 | (subject to receipt of any required approvals from the U.S. Dept. of Energy).
4 | All rights reserved."
5 |
6 | Redistribution and use in source and binary forms, with or without
7 | modification, are permitted provided that the following conditions are met:
8 |
9 | (1) Redistributions of source code must retain the above copyright notice, this
10 | list of conditions and the following disclaimer.
11 |
12 | (2) Redistributions in binary form must reproduce the above copyright notice,
13 | this list of conditions and the following disclaimer in the documentation and/
14 | or other materials provided with the distribution.
15 |
16 | (3) Neither the name of the University of California, Lawrence Berkeley
17 | National Laboratory, U.S. Dept. of Energy nor the names of its contributors may
18 | be used to endorse or promote products derived from this software without
19 | specific prior written permission.
20 |
21 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
22 | ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
23 | WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
24 | DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
25 | ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
26 | (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
27 | LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
28 | ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
29 | (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
30 | SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
31 |
32 | You are under no obligation whatsoever to provide any bug fixes, patches, or
33 | upgrades to the features, functionality or performance of the source code
34 | ("Enhancements") to anyone; however, if you choose to make your Enhancements
35 | available either publicly, or directly to Lawrence Berkeley National
36 | Laboratory, without imposing a separate written license agreement for such
37 | Enhancements, then you hereby grant the following license: a non-exclusive,
38 | royalty-free perpetual license to install, use, modify, prepare derivative
39 | works, incorporate into other computer software, distribute, and sublicense
40 | such enhancements or derivative works thereof, in binary and source code form.
--------------------------------------------------------------------------------
/docs/asset-manifest.json:
--------------------------------------------------------------------------------
1 | {
2 | "main.css": "static/css/main.1d316427.css",
3 | "main.css.map": "static/css/main.1d316427.css.map",
4 | "main.js": "static/js/main.f2da4b7a.js",
5 | "main.js.map": "static/js/main.f2da4b7a.js.map",
6 | "static/media/dynamic_docs.md": "static/media/dynamic_docs.c45dd5e7.md",
7 | "static/media/form_docs.md": "static/media/form_docs.c680d6e1.md",
8 | "static/media/forms.png": "static/media/forms.aec5c7b8.png",
9 | "static/media/getting_started.md": "static/media/getting_started.2be5c59d.md",
10 | "static/media/glyphicons-halflings-regular.eot": "static/media/glyphicons-halflings-regular.f4769f9b.eot",
11 | "static/media/glyphicons-halflings-regular.svg": "static/media/glyphicons-halflings-regular.89889688.svg",
12 | "static/media/glyphicons-halflings-regular.ttf": "static/media/glyphicons-halflings-regular.e18bbf61.ttf",
13 | "static/media/glyphicons-halflings-regular.woff": "static/media/glyphicons-halflings-regular.fa277232.woff",
14 | "static/media/glyphicons-halflings-regular.woff2": "static/media/glyphicons-halflings-regular.448c34a5.woff2",
15 | "static/media/intro.md": "static/media/intro.fda87512.md",
16 | "static/media/list_docs.md": "static/media/list_docs.12101c16.md",
17 | "static/media/schema_docs.md": "static/media/schema_docs.01abfc75.md"
18 | }
--------------------------------------------------------------------------------
/docs/favicon.ico:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/esnet/react-dynamic-forms/0f24c808fa1cadb3df6b1635cde377a0959acdd6/docs/favicon.ico
--------------------------------------------------------------------------------
/docs/index.html:
--------------------------------------------------------------------------------
1 |
React Dynamic Forms You need to enable JavaScript to run this app.
--------------------------------------------------------------------------------
/docs/manifest.json:
--------------------------------------------------------------------------------
1 | {
2 | "short_name": "React App",
3 | "name": "Create React App Sample",
4 | "icons": [
5 | {
6 | "src": "favicon.ico",
7 | "sizes": "64x64 32x32 24x24 16x16",
8 | "type": "image/x-icon"
9 | }
10 | ],
11 | "start_url": "./index.html",
12 | "display": "standalone",
13 | "theme_color": "#000000",
14 | "background_color": "#ffffff"
15 | }
16 |
--------------------------------------------------------------------------------
/docs/service-worker.js:
--------------------------------------------------------------------------------
1 | "use strict";var precacheConfig=[["/react-dynamic-forms/index.html","55629829bed102766b685e46075e2579"],["/react-dynamic-forms/static/css/main.1d316427.css","cb8f3e7561ccd1df6b5ad8d24ecdb60a"],["/react-dynamic-forms/static/js/main.f2da4b7a.js","dedd342e0fd9383c169d1dd71831e8d5"],["/react-dynamic-forms/static/media/dynamic_docs.c45dd5e7.md","c45dd5e78fa2eee95bda79c8db5af2a5"],["/react-dynamic-forms/static/media/form_docs.c680d6e1.md","c680d6e1735aa3e59e9b5c1405bfa6de"],["/react-dynamic-forms/static/media/forms.aec5c7b8.png","aec5c7b8a344873d9d4f6cbd5cbdd81c"],["/react-dynamic-forms/static/media/getting_started.2be5c59d.md","2be5c59d289c1d198b7f5a75ec92ec2c"],["/react-dynamic-forms/static/media/glyphicons-halflings-regular.448c34a5.woff2","448c34a56d699c29117adc64c43affeb"],["/react-dynamic-forms/static/media/glyphicons-halflings-regular.89889688.svg","89889688147bd7575d6327160d64e760"],["/react-dynamic-forms/static/media/glyphicons-halflings-regular.e18bbf61.ttf","e18bbf611f2a2e43afc071aa2f4e1512"],["/react-dynamic-forms/static/media/glyphicons-halflings-regular.f4769f9b.eot","f4769f9bdb7466be65088239c12046d1"],["/react-dynamic-forms/static/media/glyphicons-halflings-regular.fa277232.woff","fa2772327f55d8198301fdb8bcfc8158"],["/react-dynamic-forms/static/media/intro.fda87512.md","fda875123c517186590247e34c3ec8bf"],["/react-dynamic-forms/static/media/list_docs.12101c16.md","12101c16b67ac38ae6f98be1647a558e"],["/react-dynamic-forms/static/media/schema_docs.01abfc75.md","01abfc750a0c942167651c40d088531d"]],cacheName="sw-precache-v3-sw-precache-webpack-plugin-"+(self.registration?self.registration.scope:""),ignoreUrlParametersMatching=[/^utm_/],addDirectoryIndex=function(e,t){var a=new URL(e);return"/"===a.pathname.slice(-1)&&(a.pathname+=t),a.toString()},cleanResponse=function(t){return t.redirected?("body"in t?Promise.resolve(t.body):t.blob()).then(function(e){return new Response(e,{headers:t.headers,status:t.status,statusText:t.statusText})}):Promise.resolve(t)},createCacheKey=function(e,t,a,r){var n=new URL(e);return r&&n.pathname.match(r)||(n.search+=(n.search?"&":"")+encodeURIComponent(t)+"="+encodeURIComponent(a)),n.toString()},isPathWhitelisted=function(e,t){if(0===e.length)return!0;var a=new URL(t).pathname;return e.some(function(e){return a.match(e)})},stripIgnoredUrlParameters=function(e,a){var t=new URL(e);return t.hash="",t.search=t.search.slice(1).split("&").map(function(e){return e.split("=")}).filter(function(t){return a.every(function(e){return!e.test(t[0])})}).map(function(e){return e.join("=")}).join("&"),t.toString()},hashParamName="_sw-precache",urlsToCacheKeys=new Map(precacheConfig.map(function(e){var t=e[0],a=e[1],r=new URL(t,self.location),n=createCacheKey(r,hashParamName,a,/\.\w{8}\./);return[r.toString(),n]}));function setOfCachedUrls(e){return e.keys().then(function(e){return e.map(function(e){return e.url})}).then(function(e){return new Set(e)})}self.addEventListener("install",function(e){e.waitUntil(caches.open(cacheName).then(function(r){return setOfCachedUrls(r).then(function(a){return Promise.all(Array.from(urlsToCacheKeys.values()).map(function(t){if(!a.has(t)){var e=new Request(t,{credentials:"same-origin"});return fetch(e).then(function(e){if(!e.ok)throw new Error("Request for "+t+" returned a response with status "+e.status);return cleanResponse(e).then(function(e){return r.put(t,e)})})}}))})}).then(function(){return self.skipWaiting()}))}),self.addEventListener("activate",function(e){var a=new Set(urlsToCacheKeys.values());e.waitUntil(caches.open(cacheName).then(function(t){return t.keys().then(function(e){return Promise.all(e.map(function(e){if(!a.has(e.url))return t.delete(e)}))})}).then(function(){return self.clients.claim()}))}),self.addEventListener("fetch",function(t){if("GET"===t.request.method){var e,a=stripIgnoredUrlParameters(t.request.url,ignoreUrlParametersMatching),r="index.html";(e=urlsToCacheKeys.has(a))||(a=addDirectoryIndex(a,r),e=urlsToCacheKeys.has(a));var n="/react-dynamic-forms/index.html";!e&&"navigate"===t.request.mode&&isPathWhitelisted(["^(?!\\/__).*"],t.request.url)&&(a=new URL(n,self.location).toString(),e=urlsToCacheKeys.has(a)),e&&t.respondWith(caches.open(cacheName).then(function(e){return e.match(urlsToCacheKeys.get(a)).then(function(e){if(e)return e;throw Error("The cached response that was expected is missing.")})}).catch(function(e){return console.warn('Couldn\'t serve response for "%s" from cache: %O',t.request.url,e),fetch(t.request)}))}});
--------------------------------------------------------------------------------
/docs/static/media/dynamic_docs.c45dd5e7.md:
--------------------------------------------------------------------------------
1 | ### Description
2 |
3 | The forms library allows you to create forms that dynamically change depending on other filled out fields. An example of this is a form which has a type field and that field controls several other fields that only apply to that type. In this case we want to:
4 |
5 | * Hide and show fields in reaction to a change in the type
6 | * Have hidden fields not be required, i.e. support conditional requires
7 |
8 | #### Render
9 |
10 | The above example begins with a pretty simple `renderForm()` implementation. In fact there's not much to see here. Regardless of the visibility that we'll control in a minute, we can just render all the fields and the forms code will take care of selectively hiding fields for us. Here is the rendered `
44 | ```
45 |
46 | #### Tags
47 |
48 | The forms library `schema` supports visibility tags, which can be used to quickly control which set of fields show be visible and which should not, rather than setting each one. The schema for our example looks like
49 | this:
50 |
51 | ```jsx
52 |
53 |
54 |
55 |
56 |
57 |
58 |
59 |
65 |
66 |
67 |
68 |
69 |
70 |
71 | ```
72 |
73 | You can see that for each Field we've defined a `tags` prop. This is a list of visibility tags. Here we've named our tags based on our type values ("Equipment Port", "Patch Panel" and "Foreign"). A special tag "all" can also be added meaning that the attr will always be visible.
74 |
75 | To turn on visibility we use the `visibility` prop on the `Form`. This method takes as its argument the tag to match against the schema to control the visibility of the fields. For example, if we passed in "Equipment Port" then all the attrs with a tag of "all" would be shown, as would those with a tag of "Equipment Port" ("device_name" and "interface"). All others would be hidden.
76 |
77 | ## Dynamic changing the form
78 |
79 | In this form we have a bookmark chooser. When the user selects a preset from this chooser it will fill the form with values. The subtle thing here is that this also sets the type chooser further down the form, which itself controls what fields will be shown. It's this kind of behavior that the forms code is designed to handle.
80 |
81 | Let's think this through:
82 |
83 | 1. The first thing that happens is that the user selects a bookmark from the top chooser.
84 | 2. We know when the user changes something by handling `onChange` in `handleChange()`, so we can compare the previous and next version of the form value
85 | 3. If the bookmark has indeed changed then we can merge in some pre-baked data for that bookmark into the form value before setting it as our source of truth. In this way the change of a single field can cause a change to many fields.
86 |
87 | ```js
88 | if (value.get("bookmarked") !== this.state.value.get("bookmarked")) {
89 | const bookmark = bookmarked[value.get("bookmarked")];
90 | const merged = value.merge(bookmark);
91 | this.setState({ value: merged });
92 | } else {
93 | this.setState({ value });
94 | }
95 | ```
96 |
97 | 4. The form will then re-render and update to show the new values. However we need to handle the visibility state of the form. The visibility of the form is a function of the data in the form (at least in this case), meaning that if the form data is in a particular state, we only show certain fields. Specifically, in this case, when we set the "type" between to one of three possible values we show different fields that only apply to that "type". Therefore, in our `render()` function we get the "type" out of our form state and then set our visibility based on that:
98 |
99 | ```js
100 | render() {
101 |
102 | // Current type
103 | const currentType = values.get("type");
104 |
105 | // Find the visibility tag given our current type
106 | const visibilityTag = getVisibilityTag(currentType);
107 |
108 | ...
109 | }
110 | ```
111 |
112 | As mentioned above, we encode the tags within the `Schema`, so here we are simply mapping between the current type value and the tags in the schema.
113 |
114 | 5. Finally, to complete the dynamically updating form, we simply render
115 | the form but set the visibility prop to our `visibilityTag`.
116 |
117 | ```
118 | render() {
119 | ...
120 | return (
121 |
126 | ...
127 |
128 | );
129 | }
130 | ```
131 |
--------------------------------------------------------------------------------
/docs/static/media/form_docs.c680d6e1.md:
--------------------------------------------------------------------------------
1 | ### Forms example
2 |
3 | The forms library is designed to help you build a complete form. In this example
4 | we create a simple contacts form. There are other examples too of forms which change
5 | their structure as the user interacts with tham, as well as demostrating the use
6 | of lists within the forms. But here we keep it relatively simple.
7 |
8 | **What do we want from our form?**
9 |
10 | Essentially we want to provide perhaps some initial data, our form `"value"`,
11 | defaults in the case of a new form, or maybe our current
12 | database state in the case of editing an existing entity.
13 |
14 | As the user edits the data, we'll want to track that. We may choose to save
15 | it on submit (if it's a new form, that's likely), or save it as the user edits it
16 | (perhaps if they are using inline editing we might
17 | want to save the data when any fields are changed). Either way, the forms library
18 | allows you to provide a callback function, which will be called whenever the values
19 | in the form change. How you want to respond to that is up to you, but this example
20 | demostrates one possible approach.
21 |
22 | In addition to knowing that the form values have changed, we also need to know if
23 | the form has any errors or missing fields. We do this via callbacks as well, where
24 | each callback will tell you the number of missing or empty fields that exist within
25 | the form. You can use that to control if the user can submit the form or not, as
26 | we do in this example.
27 |
28 | Okay, so we have initial values and we have some callbacks.
29 |
30 | **How do we get a form up and running to use those?**
31 |
32 | Forms have two concerns. Each form has a schema which we use to provide the meta
33 | data for fields within the form. This includes UI elements like the label for each
34 | fields, the placeholder text, etc, but also rules around the field itself. For
35 | example a field (called an Field in this library),
36 |
37 | The form elements are defined by a **schema**. Schemas can be defined with JSX or manually. Here's the schema used in this page:
38 |
39 | const schema = (
40 |
41 |
43 |
45 |
47 |
48 |
49 |
50 | );
51 |
52 | As you can see the schema is used to associate the Field name (`"first_name"` for example) with some properties which define how it looks and what is a valid value for that Field. Here we define a label (`"First name"`), a placeholder text, and some validation properties. Required can be set true to have the form track that this Field field needs to be filled out before the form is submitted. More on errors and missing value counts below. In addition to being required or not, the Field can have a validation prop set which will be passed to Revalidator for field validation while the user interacts with the form. It is most common to use it to specify the type (`"string", "integer", or "number"`), but you can also specify a format, such as in the example above where the email Field is checked to make sure it is a valid email address. Maximum string lengths, or ranges of numeric values can also be specified. For full details see the [Revalidator website](https://github.com/flatiron/revalidator).
53 |
54 | Rendering is not automatic. Instead the form itself is a React component that you define. We define the form itself like this:
55 |
56 | class ContactForm extends React.Component {
57 |
58 | }
59 |
60 | And then implement the form layout like this:
61 |
62 | renderForm() {
63 | const disableSubmit = this.hasErrors();
64 | return (
65 |
66 |
67 |
68 |
69 |
70 |
71 |
72 |
73 | );
74 | }
75 |
76 | As you can see, we return a `` element which contains further JSX, which is a convenience. In fact, you can define this with a ` ` too. You can use any JSX in here to render the form however you like. This makes the layout of the form as flexible as any other React code.
77 |
78 | The special elements here are the `TextEdit`s. They specify an `field` prop which references the schema (we'll see how to get the schema hooked up in a minute). Each TextEditGroup will generate a label and a form control (in this case a `TextEdit`). We use Bootstrap for the layout. In addition to TextEditGroups there's also: `TextAreaGroup`, `ChooserGroup`, `OptionsGroup` and `TagsGroup`. You can also wrap your own controls in the generic `Group`.
79 |
80 | Now that we have out form it's time to use it. Typically the form will be contained (rendered by) another React component which will hold the business logic of sourcing the schema and initial values, as well as handling the submit of the form in some way.
81 |
82 | To render the form we created above we need to pass in the initial values and schema. Here is the key part of render function for this page's example:
83 |
84 | render: function() {
85 | ...
86 |
91 | ...
92 | }
93 |
94 | Note that the schema is required, so you cannot render the form until one is available. If this is being loaded from the server you would display a Spinner until it is available.
95 |
96 | ---
--------------------------------------------------------------------------------
/docs/static/media/forms.aec5c7b8.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/esnet/react-dynamic-forms/0f24c808fa1cadb3df6b1635cde377a0959acdd6/docs/static/media/forms.aec5c7b8.png
--------------------------------------------------------------------------------
/docs/static/media/glyphicons-halflings-regular.448c34a5.woff2:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/esnet/react-dynamic-forms/0f24c808fa1cadb3df6b1635cde377a0959acdd6/docs/static/media/glyphicons-halflings-regular.448c34a5.woff2
--------------------------------------------------------------------------------
/docs/static/media/glyphicons-halflings-regular.e18bbf61.ttf:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/esnet/react-dynamic-forms/0f24c808fa1cadb3df6b1635cde377a0959acdd6/docs/static/media/glyphicons-halflings-regular.e18bbf61.ttf
--------------------------------------------------------------------------------
/docs/static/media/glyphicons-halflings-regular.f4769f9b.eot:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/esnet/react-dynamic-forms/0f24c808fa1cadb3df6b1635cde377a0959acdd6/docs/static/media/glyphicons-halflings-regular.f4769f9b.eot
--------------------------------------------------------------------------------
/docs/static/media/glyphicons-halflings-regular.fa277232.woff:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/esnet/react-dynamic-forms/0f24c808fa1cadb3df6b1635cde377a0959acdd6/docs/static/media/glyphicons-halflings-regular.fa277232.woff
--------------------------------------------------------------------------------
/docs/static/media/intro.fda87512.md:
--------------------------------------------------------------------------------
1 | ## Introduction
2 |
3 | ---
4 |
5 | This repository contains a set of React based forms components which are used within ESnet for our network database application (ESDB), but could be used by any React based project needing to build complex forms.
6 |
7 | Our approach is to treat a form as a controlled input, essentially an input with many inputs (which may have many inputs, and so on...) You maintain your form's state however you want, you pass that state down into the form as its value prop. If the form is edited, a callback is called and you can update your form state. When it comes time to save the form, that's up to you, you always have your form's state. On top of this the form has a schema defining rules. Therefore, you can also listen to changes in the count of either missing values or errors. With this information it is simple to control if the user can submit the form as well.
8 |
9 | The library is built on Immutable.js, so form state should be passed into the form as an Immutable.Map. This allows efficient operations on your form data, minimizing copying while ensuring safety as the form state is mutated.
10 |
11 | While part of defining a form is to specify a schema for your form, you still maintain complete control over the layout in the form in your `render()` method, just like any other react app. The schema and presentation are entirely separate. This React friendly approach makes it easy to build forms which dynamically change values or structure based on the current state of the form.
12 |
13 | This library contains:
14 |
15 | * Low level forms control wrappers that communicate errors and missing values to parent components and style themselves appropriately for errors and missing value state. You can write your own in the same way. Supplied standard form controls:
16 | * Textedit
17 | * TextArea
18 | * Checkboxes
19 | * RadioButtons
20 | * Chooser (internally we use react-select)
21 | * TagsEdit (again using react-select)
22 | * DateEdit (react-datepicker)
23 | * A `` component that lets you define the rules for each field. Each field is specified in a `` component
24 | * A `` component that acts as a top level controlled input for all of the form state, to assemble controls together and track state change, errors and missing values and enabling dynamic forms with via a declarative schema
25 | * Higher Order Components:
26 | * for grouping of controls with their labels, required state and editing control
27 | * building lists of forms
28 | * Inline editing
29 | * List editing
30 |
31 | The library is built on several other open source libraries, especially:
32 |
33 | * react
34 | * immutable.js
35 | * revalidator
36 | * react-bootstrap
37 | * react-select
38 | * react-virtualized
39 | * react-datepicker
40 |
41 | Please browse the examples for a feel for the library, or read on to get started.
42 |
--------------------------------------------------------------------------------
/docs/static/media/list_docs.12101c16.md:
--------------------------------------------------------------------------------
1 | ### List example
2 |
3 | The first step is to render a form for entering an email address. In the case of this example we do have a little form that asks for the email address and email type. In that case we specify a schema and a form component to render that form:
4 |
5 | const schema = (
6 |
7 |
14 |
15 |
16 | );
17 |
18 | /**
19 | * Renders a form for entering an email address
20 | */
21 | class EmailForm extends React.Component {
22 |
23 | renderForm() {
24 | const id = this.value("email_type");
25 | return (
26 |
34 |
40 |
41 |
42 | );
43 | }
44 | };
45 |
46 | const EmailList = formList(EmailForm);
47 | const Emails = formGroup(EmailList);
48 |
49 | Having defined that, we can now create a form to edit a contact:
50 |
51 | class ContactForm extends React.Component {
52 |
53 | schema() {
54 | return (
55 |
56 |
63 |
70 |
71 |
72 | );
73 | }
74 |
75 | render() {
76 | const disableSubmit = false;
77 | const style = { background: "#FAFAFA", padding: 10, borderRadius: 5 };
78 | const { value } = this.props;
79 | const emails = value.get("emails");
80 |
81 | return (
82 | this.handleChange(fieldName, value)}
90 | onMissingCountChange={(form, missing) =>
91 | this.handleMissingCountChange(form, missing)}
92 | onErrorCountChange={(form, errors) => this.handleErrorCountChange(form, errors)}
93 | >
94 |
95 |
96 |
97 |
98 |
99 | );
100 | }
101 |
102 | });
103 | ---
--------------------------------------------------------------------------------
/docs/static/media/schema_docs.01abfc75.md:
--------------------------------------------------------------------------------
1 | #
--------------------------------------------------------------------------------
/lerna.json:
--------------------------------------------------------------------------------
1 | {
2 | "lerna": "2.0.0",
3 | "packages": [
4 | "packages/*"
5 | ],
6 | "version": "independent"
7 | }
8 |
--------------------------------------------------------------------------------
/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "scripts": {
3 | "start": "cd packages/website && npm run start",
4 | "build-website":
5 | "echo \"*** Building website\n\" && rm -rf docs && cd packages/website && npm run build && mv build ../../docs"
6 | },
7 | "devDependencies": {
8 | "lerna": "^2.5.1"
9 | },
10 | "dependencies": {}
11 | }
--------------------------------------------------------------------------------
/packages/react-dynamic-forms/.babelrc:
--------------------------------------------------------------------------------
1 | {
2 | "presets": ["es2015", "stage-0", "react"],
3 | "plugins": ["transform-class-properties"]
4 | }
--------------------------------------------------------------------------------
/packages/react-dynamic-forms/.eslintrc:
--------------------------------------------------------------------------------
1 | {
2 | "extends": ["react-app", "prettier", "prettier/react"]
3 | }
4 |
--------------------------------------------------------------------------------
/packages/react-dynamic-forms/CONTRIBUTING.md:
--------------------------------------------------------------------------------
1 | # How to contribute to ESnet React Forms
2 |
3 | In general we follow the "fork & pull" model as outlined in the
4 | [GitHub docs](https://help.github.com/articles/using-pull-requests/).
5 |
6 | Here are a few additional thoughts on how to make the contribution process as
7 | painless as possible for yourself and for the developers.
8 |
9 | 1. *Communicate.* please create an GitHub issue in the appropriate GitHub
10 | project communicating your plans. This allows coordination -- it's possible
11 | someone else has ideas about this topic and it can save a lot of time if
12 | things are disucssed before you dive in. When you submit your pull request
13 | please include the issue number with the discussion relevant to this pull
14 | request.
15 |
16 | 2. *Work on a branch.* Work on a branch in a fork of the project code. *DO NOT
17 | WORK ON `master` or `develop`.*
18 |
19 | 3. *Follow the style of the code.* All code must follow the style of the
20 | project. We generally adhere to the [Google JavaScript style
21 | guide](https://google-styleguide.googlecode.com/svn/trunk/javascriptguide.xml).
22 | Please lint your code with a reasonable linting tool.
23 |
24 | 4. *Create examples.* All new features must have appropriate examples in the
25 | examples directory. If you are adding a major feature you may wish to create a
26 | new example page. If you are adding a smaller feature you may just wish to
27 | augment one of the existing examples.
28 |
29 | 5. *Tests.* We currently evaluating how to test this library. In the mean time
30 | please be sure to check that all of the examples continue to work before
31 | submitting your pull request. If you have suggestions on how to build tests
32 | we'd love to hear them.
33 |
34 | The [jQuery guidlines](http://contribute.jquery.org/commits-and-pull-requests/)
35 | have some good suggestions for rectifying common Git mistakes
36 |
37 | Once you have you are ready to share your code go ahead and follow the
38 | instructions in the [GitHub
39 | docs](https://help.github.com/articles/using-pull-requests/) to submit your
40 | pull request.
41 |
--------------------------------------------------------------------------------
/packages/react-dynamic-forms/LICENSE:
--------------------------------------------------------------------------------
1 | "ESnet React Forms Library, Copyright (c) 2015-2017, The Regents of the
2 | University of California, through Lawrence Berkeley National Laboratory
3 | (subject to receipt of any required approvals from the U.S. Dept. of Energy).
4 | All rights reserved."
5 |
6 | Redistribution and use in source and binary forms, with or without
7 | modification, are permitted provided that the following conditions are met:
8 |
9 | (1) Redistributions of source code must retain the above copyright notice, this
10 | list of conditions and the following disclaimer.
11 |
12 | (2) Redistributions in binary form must reproduce the above copyright notice,
13 | this list of conditions and the following disclaimer in the documentation and/
14 | or other materials provided with the distribution.
15 |
16 | (3) Neither the name of the University of California, Lawrence Berkeley
17 | National Laboratory, U.S. Dept. of Energy nor the names of its contributors may
18 | be used to endorse or promote products derived from this software without
19 | specific prior written permission.
20 |
21 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
22 | ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
23 | WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
24 | DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
25 | ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
26 | (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
27 | LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
28 | ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
29 | (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
30 | SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
31 |
32 | You are under no obligation whatsoever to provide any bug fixes, patches, or
33 | upgrades to the features, functionality or performance of the source code
34 | ("Enhancements") to anyone; however, if you choose to make your Enhancements
35 | available either publicly, or directly to Lawrence Berkeley National
36 | Laboratory, without imposing a separate written license agreement for such
37 | Enhancements, then you hereby grant the following license: a non-exclusive,
38 | royalty-free perpetual license to install, use, modify, prepare derivative
39 | works, incorporate into other computer software, distribute, and sublicense
40 | such enhancements or derivative works thereof, in binary and source code form.
--------------------------------------------------------------------------------
/packages/react-dynamic-forms/README.md:
--------------------------------------------------------------------------------
1 |
2 |
--------------------------------------------------------------------------------
/packages/react-dynamic-forms/lib/components/Schema.js:
--------------------------------------------------------------------------------
1 | "use strict";
2 |
3 | Object.defineProperty(exports, "__esModule", {
4 | value: true
5 | });
6 |
7 | var _createClass = function () { function defineProperties(target, props) { for (var i = 0; i < props.length; i++) { var descriptor = props[i]; descriptor.enumerable = descriptor.enumerable || false; descriptor.configurable = true; if ("value" in descriptor) descriptor.writable = true; Object.defineProperty(target, descriptor.key, descriptor); } } return function (Constructor, protoProps, staticProps) { if (protoProps) defineProperties(Constructor.prototype, protoProps); if (staticProps) defineProperties(Constructor, staticProps); return Constructor; }; }(); /**
8 | * Copyright (c) 2015 - present, The Regents of the University of California,
9 | * through Lawrence Berkeley National Laboratory (subject to receipt
10 | * of any required approvals from the U.S. Dept. of Energy).
11 | * All rights reserved.
12 | *
13 | * This source code is licensed under the BSD-style license found in the
14 | * LICENSE file in the root directory of this source tree.
15 | */
16 |
17 | var _invariant = require("invariant");
18 |
19 | var _invariant2 = _interopRequireDefault(_invariant);
20 |
21 | function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
22 |
23 | function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } }
24 |
25 | /**
26 | * A schema can be specified using JSX to define the rules for
27 | * each form field. As an example, here is a Form that will take the
28 | * first name, last name and email of a contact. We can define also
29 | * that the email should be of format `email` and that the first and
30 | * last names are `required`:
31 | *
32 | * ```
33 | * const schema = (
34 | *
35 | *
37 | *
39 | *
41 | *
42 | * );
43 | * ```
44 | *
45 | * See also `Field`.
46 | */
47 | var Schema = function () {
48 | function Schema() {
49 | _classCallCheck(this, Schema);
50 | }
51 |
52 | _createClass(Schema, [{
53 | key: "render",
54 | value: function render() {
55 | (0, _invariant2.default)(false, this.constructor.name + " elements are for schema configuration only and should not be rendered");
56 | return;
57 | }
58 | }]);
59 |
60 | return Schema;
61 | }();
62 |
63 | exports.default = Schema;
--------------------------------------------------------------------------------
/packages/react-dynamic-forms/lib/components/View.js:
--------------------------------------------------------------------------------
1 | "use strict";
2 |
3 | Object.defineProperty(exports, "__esModule", {
4 | value: true
5 | });
6 |
7 | var _createClass = function () { function defineProperties(target, props) { for (var i = 0; i < props.length; i++) { var descriptor = props[i]; descriptor.enumerable = descriptor.enumerable || false; descriptor.configurable = true; if ("value" in descriptor) descriptor.writable = true; Object.defineProperty(target, descriptor.key, descriptor); } } return function (Constructor, protoProps, staticProps) { if (protoProps) defineProperties(Constructor.prototype, protoProps); if (staticProps) defineProperties(Constructor, staticProps); return Constructor; }; }();
8 |
9 | var _react = require("react");
10 |
11 | var _react2 = _interopRequireDefault(_react);
12 |
13 | var _formGroup = require("../js/formGroup");
14 |
15 | var _formGroup2 = _interopRequireDefault(_formGroup);
16 |
17 | function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
18 |
19 | function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } }
20 |
21 | function _possibleConstructorReturn(self, call) { if (!self) { throw new ReferenceError("this hasn't been initialised - super() hasn't been called"); } return call && (typeof call === "object" || typeof call === "function") ? call : self; }
22 |
23 | function _inherits(subClass, superClass) { if (typeof superClass !== "function" && superClass !== null) { throw new TypeError("Super expression must either be null or a function, not " + typeof superClass); } subClass.prototype = Object.create(superClass && superClass.prototype, { constructor: { value: subClass, enumerable: false, writable: true, configurable: true } }); if (superClass) Object.setPrototypeOf ? Object.setPrototypeOf(subClass, superClass) : subClass.__proto__ = superClass; } /**
24 | * Copyright (c) 2015 - present, The Regents of the University of California,
25 | * through Lawrence Berkeley National Laboratory (subject to receipt
26 | * of any required approvals from the U.S. Dept. of Energy).
27 | * All rights reserved.
28 | *
29 | * This source code is licensed under the BSD-style license found in the
30 | * LICENSE file in the root directory of this source tree.
31 | */
32 |
33 | var View = function (_React$Component) {
34 | _inherits(View, _React$Component);
35 |
36 | function View() {
37 | _classCallCheck(this, View);
38 |
39 | return _possibleConstructorReturn(this, (View.__proto__ || Object.getPrototypeOf(View)).apply(this, arguments));
40 | }
41 |
42 | _createClass(View, [{
43 | key: "render",
44 | value: function render() {
45 | var text = this.props.value;
46 | var view = this.props.view;
47 | var color = "";
48 | var background = "";
49 | var style = {
50 | color: color,
51 | background: background,
52 | // height: 23,
53 | height: "100%",
54 | width: "100%",
55 | paddingLeft: 3
56 | };
57 | if (!view) {
58 | return _react2.default.createElement(
59 | "div",
60 | { style: style },
61 | text
62 | );
63 | } else {
64 | return _react2.default.createElement(
65 | "div",
66 | { style: style },
67 | view(text)
68 | );
69 | }
70 | }
71 | }]);
72 |
73 | return View;
74 | }(_react2.default.Component);
75 |
76 | exports.default = (0, _formGroup2.default)(View, true);
--------------------------------------------------------------------------------
/packages/react-dynamic-forms/lib/css/chooser.css:
--------------------------------------------------------------------------------
1 | /**
2 | * Copyright (c) 2015 - present, The Regents of the University of California,
3 | * through Lawrence Berkeley National Laboratory (subject to receipt
4 | * of any required approvals from the U.S. Dept. of Energy).
5 | * All rights reserved.
6 | *
7 | * This source code is licensed under the BSD-style license found in the
8 | * LICENSE file in the root directory of this source tree.
9 | */
10 |
11 | .Select-control {
12 | height: 30px;
13 | }
14 |
15 | .Select-value {
16 | line-height: 26px !important;
17 | }
18 |
19 | .Select-value-label {
20 | line-height: 26px;
21 | font-size: 12px;
22 | }
23 |
24 | .Select-menu-outer {
25 | font-size: 12px;
26 | }
27 |
28 | .Select-input {
29 | height: 26px;
30 | }
31 |
32 | .Select-placeholder {
33 | line-height: 20px;
34 | font-size: 12px;
35 | padding-top: 5px;
36 | }
37 |
38 | .Select.is-missing > .Select-control {
39 | background: floralwhite;
40 | }
--------------------------------------------------------------------------------
/packages/react-dynamic-forms/lib/css/dateedit.css:
--------------------------------------------------------------------------------
1 | /**
2 | * Copyright (c) 2015 - present, The Regents of the University of California,
3 | * through Lawrence Berkeley National Laboratory (subject to receipt
4 | * of any required approvals from the U.S. Dept. of Energy).
5 | * All rights reserved.
6 | *
7 | * This source code is licensed under the BSD-style license found in the
8 | * LICENSE file in the root directory of this source tree.
9 | */
10 |
11 | input.datepicker__input.rdf {
12 | font-size: 12px;
13 | height: 30px;
14 | margin-bottom: 10px;
15 | border-radius: 3px;
16 | padding-left: 6px;
17 | color: #555555;
18 | background-color: #ffffff;
19 | background-image: none;
20 | border: 1px solid #cccccc;
21 | border-radius: 4px;
22 | -webkit-box-shadow: inset 0 1px 1px rgba(0,0,0,0.075);
23 | box-shadow: inset 0 1px 1px rgba(0,0,0,0.075);
24 | -webkit-transition: border-color ease-in-out .15s,-webkit-box-shadow ease-in-out .15s;
25 | -o-transition: border-color ease-in-out .15s,box-shadow ease-in-out .15s;
26 | transition: border-color ease-in-out .15s,box-shadow ease-in-out .15s;
27 | }
28 |
29 | input.datepicker__input.rdf:focus {
30 | border-color: #66afe9;
31 | outline: 0;
32 | -webkit-box-shadow: inset 0 1px 1px rgba(0,0,0,0.075),0 0 8px rgba(102,175,233,0.6);
33 | box-shadow: inset 0 1px 1px rgba(0,0,0,0.075),0 0 8px rgba(102,175,233,0.6);
34 | }
35 |
36 | input.datepicker__input.has-error {
37 | border-color: #B94A48;
38 | }
39 |
40 | input.datepicker__input.is-missing {
41 | background-color: floralwhite;
42 | }
43 |
--------------------------------------------------------------------------------
/packages/react-dynamic-forms/lib/css/group.css:
--------------------------------------------------------------------------------
1 | /**
2 | * Copyright (c) 2015 - present, The Regents of the University of California,
3 | * through Lawrence Berkeley National Laboratory (subject to receipt
4 | * of any required approvals from the U.S. Dept. of Energy).
5 | * All rights reserved.
6 | *
7 | * This source code is licensed under the BSD-style license found in the
8 | * LICENSE file in the root directory of this source tree.
9 | */
10 |
11 | .group-required {
12 | color: orange;
13 | font-size: larger;
14 | }
15 |
16 | .group-label {
17 | text-align: right;
18 | padding-right: 0px;
19 | text-transform: uppercase;
20 | font-size: smaller;
21 | }
--------------------------------------------------------------------------------
/packages/react-dynamic-forms/lib/css/icon.css:
--------------------------------------------------------------------------------
1 | /**
2 | * Copyright (c) 2015 - present, The Regents of the University of California,
3 | * through Lawrence Berkeley National Laboratory (subject to receipt
4 | * of any required approvals from the U.S. Dept. of Energy).
5 | * All rights reserved.
6 | *
7 | * This source code is licensed under the BSD-style license found in the
8 | * LICENSE file in the root directory of this source tree.
9 | */
10 |
11 | .icon {
12 | cursor: pointer;
13 | font-size: 9px;
14 | padding-bottom: 10px;
15 | color: steelblue;
16 | padding-top: 3px;
17 | }
18 |
19 | .hostile_icon {
20 | cursor: pointer;
21 | font-size: 9px;
22 | padding-bottom: 10px;
23 | color: #b94a48;
24 | padding-top: 3px;
25 | }
26 |
27 | .delete-action:hover {
28 | color: #b94a48;
29 | }
30 |
31 | .edit-action:hover {
32 | color: steelblue;
33 | }
34 |
35 | .edit-action.active {
36 | color: steelblue;
37 | }
38 |
39 | .add-action:hover {
40 | color: green;
41 | }
42 |
--------------------------------------------------------------------------------
/packages/react-dynamic-forms/lib/css/list.css:
--------------------------------------------------------------------------------
1 | /**
2 | * Copyright (c) 2015 - present, The Regents of the University of California,
3 | * through Lawrence Berkeley National Laboratory (subject to receipt
4 | * of any required approvals from the U.S. Dept. of Energy).
5 | * All rights reserved.
6 | *
7 | * This source code is licensed under the BSD-style license found in the
8 | * LICENSE file in the root directory of this source tree.
9 | */
10 |
11 | /*
12 | * The container includes the whole list, but not the [+] at the bottom
13 | */
14 | .esnet-forms-listeditview-container {
15 | padding-left: 0px;
16 | list-style-type: none;
17 | margin-bottom: 0px;
18 | }
19 |
20 | .esnet-forms-listeditview-container:last-child {
21 | margin-bottom: 0;
22 | }
23 |
24 | /*
25 | * The inner LI of the container is each item, including the [-] control
26 | */
27 |
28 | .esnet-forms-listeditview-container li {
29 | margin-left: 0px;
30 | }
31 |
32 | /*
33 | * The main styling for each item
34 | */
35 |
36 | .esnet-forms-listeditview-edit-item {
37 | width: 95%;
38 | margin-bottom: 10px;
39 | padding-top: 2px;
40 | }
41 |
42 | .esnet-forms-listeditview-edit-item.no-controls {
43 | width: 95%;
44 | }
45 |
46 | /*
47 | .esnet-forms-minus-action-box {
48 | float: left;
49 | margin-top: 5px;
50 | vertical-align: top;
51 | width: 28px;
52 | height: 28px;
53 | background: #EDEDED;
54 | margin-left: -5px;
55 | z-index: 10;
56 | border: #E5E5E5;
57 | border-style: solid;
58 | border-width: 1px;
59 | border-radius: 2px;
60 | }*/
61 |
62 | .esnet-forms-plus-action-box-dialog {
63 | clear: both;
64 | border-width: 1px;
65 | border-color: #cef4d2;
66 | border-style: solid;
67 | border-radius: 4px;
68 | padding: 10px;
69 | height: 70px;
70 | width: 95%;
71 | background: #efe;
72 | }
73 |
74 | /*
75 | List transitions
76 | */
77 |
78 | .esnet-forms-list {
79 | font-size: 12px;
80 | }
81 |
82 | /** start of entering and end of leaving **/
83 | li.esnet-forms-list-item-enter,
84 | li.esnet-forms-list-item-leave.esnet-forms-list-item-leave-active {
85 | opacity: 0.01;
86 | max-height: 0px;
87 | }
88 |
89 | /** start of leaving and end of entering **/
90 | li.esnet-forms-list-item-leave,
91 | li.esnet-forms-list-item-enter.esnet-forms-list-item-enter-active {
92 | opacity: 1;
93 | max-height: 100px;
94 | /*max-height: 50px;*/
95 | }
96 |
97 | /** ease in out quint **/
98 | li.esnet-forms-list-item-enter,
99 | li.esnet-forms-list-item-leave {
100 | -moz-transition: all 100ms ease 0s;
101 | -webkit-transition: all 100ms ease 0s;
102 | transition: all 100ms ease 0s;
103 | }
104 |
--------------------------------------------------------------------------------
/packages/react-dynamic-forms/lib/css/tagsedit.css:
--------------------------------------------------------------------------------
1 | /**
2 | * Copyright (c) 2015 - present, The Regents of the University of California,
3 | * through Lawrence Berkeley National Laboratory (subject to receipt
4 | * of any required approvals from the U.S. Dept. of Energy).
5 | * All rights reserved.
6 | *
7 | * This source code is licensed under the BSD-style license found in the
8 | * LICENSE file in the root directory of this source tree.
9 | */
10 |
11 | .Select-control {
12 | height: 26px;
13 | }
14 |
15 | .Select-value {
16 | line-height: 26px !important;
17 | }
18 |
19 | .Select-value-label {
20 | line-height: 24px;
21 | font-size: 12px;
22 | }
23 |
24 | .Select-menu-outer {
25 | font-size: 12px;
26 | }
27 |
28 | .Select-input {
29 | height: 26px;
30 | }
31 |
32 | .Select.is-missing > .Select-control {
33 | background: floralwhite;
34 | }
35 |
36 | .Select--multi .Select-value {
37 | height: 26px;
38 | height: 24px;
39 | margin-top: 1px;
40 | border-color: #ccc
41 | }
42 |
43 | .Select--multi .Select-value-label {
44 | line-height: 22px;
45 | font-size: 12px;
46 | padding: 0px;
47 | margin-top: -6px;
48 | padding-left: 5px;
49 | padding-right: 5px;
50 | background: #DDD;
51 | color: #555555;
52 | border-color: #555;
53 | }
54 |
55 | .Select--multi .Select-value-icon {
56 | line-height: 22px;
57 | font-size: 12px;
58 | padding: 0px;
59 | margin-top: -6px;
60 | padding-left: 5px;
61 | padding-right: 5px;
62 | background: #DDD;
63 | color: #555555;
64 | border-right-color: #ccc;
65 | }
66 |
67 | .Select--multi .Select-value-icon:hover {
68 | background: #DFDFDF;
69 | color: #b94a48;
70 | }
71 |
72 | .Select.missing.Select--multi.is-searchable > .Select-control {
73 | background: floralwhite;
74 | }
--------------------------------------------------------------------------------
/packages/react-dynamic-forms/lib/css/textarea.css:
--------------------------------------------------------------------------------
1 | /**
2 | * Copyright (c) 2015 - present, The Regents of the University of California,
3 | * through Lawrence Berkeley National Laboratory (subject to receipt
4 | * of any required approvals from the U.S. Dept. of Energy).
5 | * All rights reserved.
6 | *
7 | * This source code is licensed under the BSD-style license found in the
8 | * LICENSE file in the root directory of this source tree.
9 | */
10 |
11 | textarea.form-control {
12 | font-size: 12px;
13 | padding-left: 10px;
14 | }
15 |
--------------------------------------------------------------------------------
/packages/react-dynamic-forms/lib/css/textedit.css:
--------------------------------------------------------------------------------
1 | /**
2 | * Copyright (c) 2015 - present, The Regents of the University of California,
3 | * through Lawrence Berkeley National Laboratory (subject to receipt
4 | * of any required approvals from the U.S. Dept. of Energy).
5 | * All rights reserved.
6 | *
7 | * This source code is licensed under the BSD-style license found in the
8 | * LICENSE file in the root directory of this source tree.
9 | */
10 |
11 | datepicker__input.has-error {
12 | border-color: "green"
13 | }
--------------------------------------------------------------------------------
/packages/react-dynamic-forms/lib/index.js:
--------------------------------------------------------------------------------
1 | "use strict";
2 |
3 | Object.defineProperty(exports, "__esModule", {
4 | value: true
5 | });
6 | exports.FormGroupLayout = exports.FormEditStates = exports.View = exports.CheckBoxes = exports.RadioButtons = exports.TagsEdit = exports.DateEdit = exports.Chooser = exports.TextArea = exports.TextEdit = exports.List = exports.formList = exports.formGroup = exports.Field = exports.Schema = exports.Form = undefined;
7 |
8 | var _Form = require("./components/Form");
9 |
10 | var _Form2 = _interopRequireDefault(_Form);
11 |
12 | var _Schema = require("./components/Schema");
13 |
14 | var _Schema2 = _interopRequireDefault(_Schema);
15 |
16 | var _Field = require("./components/Field");
17 |
18 | var _Field2 = _interopRequireDefault(_Field);
19 |
20 | var _formGroup = require("./js/formGroup");
21 |
22 | var _formGroup2 = _interopRequireDefault(_formGroup);
23 |
24 | var _formList = require("./js/formList");
25 |
26 | var _formList2 = _interopRequireDefault(_formList);
27 |
28 | var _List = require("./components/List");
29 |
30 | var _List2 = _interopRequireDefault(_List);
31 |
32 | var _TextEdit = require("./components/TextEdit");
33 |
34 | var _TextEdit2 = _interopRequireDefault(_TextEdit);
35 |
36 | var _TextArea = require("./components/TextArea");
37 |
38 | var _TextArea2 = _interopRequireDefault(_TextArea);
39 |
40 | var _Chooser = require("./components/Chooser.js");
41 |
42 | var _Chooser2 = _interopRequireDefault(_Chooser);
43 |
44 | var _DateEdit = require("./components/DateEdit");
45 |
46 | var _DateEdit2 = _interopRequireDefault(_DateEdit);
47 |
48 | var _TagsEdit = require("./components/TagsEdit");
49 |
50 | var _TagsEdit2 = _interopRequireDefault(_TagsEdit);
51 |
52 | var _RadioButtons = require("./components/RadioButtons");
53 |
54 | var _RadioButtons2 = _interopRequireDefault(_RadioButtons);
55 |
56 | var _CheckBoxes = require("./components/CheckBoxes");
57 |
58 | var _CheckBoxes2 = _interopRequireDefault(_CheckBoxes);
59 |
60 | var _View = require("./components/View");
61 |
62 | var _View2 = _interopRequireDefault(_View);
63 |
64 | var _constants = require("./js/constants");
65 |
66 | function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
67 |
68 | exports.Form = _Form2.default; /**
69 | * Copyright (c) 2015 - present, The Regents of the University of California,
70 | * through Lawrence Berkeley National Laboratory (subject to receipt
71 | * of any required approvals from the U.S. Dept. of Energy).
72 | * All rights reserved.
73 | *
74 | * This source code is licensed under the BSD-style license found in the
75 | * LICENSE file in the root directory of this source tree.
76 | */
77 |
78 | exports.Schema = _Schema2.default;
79 | exports.Field = _Field2.default;
80 | exports.formGroup = _formGroup2.default;
81 | exports.formList = _formList2.default;
82 | exports.List = _List2.default;
83 | exports.TextEdit = _TextEdit2.default;
84 | exports.TextArea = _TextArea2.default;
85 | exports.Chooser = _Chooser2.default;
86 | exports.DateEdit = _DateEdit2.default;
87 | exports.TagsEdit = _TagsEdit2.default;
88 | exports.RadioButtons = _RadioButtons2.default;
89 | exports.CheckBoxes = _CheckBoxes2.default;
90 | exports.View = _View2.default;
91 | exports.FormEditStates = _constants.FormEditStates;
92 | exports.FormGroupLayout = _constants.FormGroupLayout;
93 |
--------------------------------------------------------------------------------
/packages/react-dynamic-forms/lib/js/constants.js:
--------------------------------------------------------------------------------
1 | "use strict";
2 |
3 | var _keymirror = require("keymirror");
4 |
5 | var _keymirror2 = _interopRequireDefault(_keymirror);
6 |
7 | function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
8 |
9 | module.exports = {
10 | /**
11 | * At Form can either:
12 | * * ALL - Always show edit state for all of its fields
13 | * * SELECTION - Show edit icons next to items, selecting one show edit state for that item
14 | * * NEVER - Never show edit state for the items (view only)
15 | */
16 | FormEditStates: (0, _keymirror2.default)({
17 | ALWAYS: null,
18 | SELECTED: null,
19 | NEVER: null,
20 | TABLE: null
21 | }),
22 |
23 | FormGroupLayout: (0, _keymirror2.default)({
24 | ROW: null,
25 | COLUMN: null,
26 | INLINE: null
27 | })
28 | }; /**
29 | * Copyright (c) 2017 - present, The Regents of the University of California,
30 | * through Lawrence Berkeley National Laboratory (subject to receipt
31 | * of any required approvals from the U.S. Dept. of Energy).
32 | * All rights reserved.
33 | *
34 | * This source code is licensed under the BSD-style license found in the
35 | * LICENSE file in the root directory of this source tree.
36 | */
--------------------------------------------------------------------------------
/packages/react-dynamic-forms/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "react-dynamic-forms",
3 | "version": "1.0.3",
4 | "description": "Dynamic forms library for React",
5 | "keywords": [
6 | "forms",
7 | "dynamic",
8 | "react"
9 | ],
10 | "main": "lib/index.js",
11 | "author": "ESnet SEG ",
12 | "bugs": {
13 | "url": "https://github.com/esnet/esnet-react-forms/issues"
14 | },
15 | "scripts": {
16 | "docs": "echo \"*** Building API docs\n\" && react-docgen src/components -x js -o ../website/src/api/docs.json --pretty",
17 | "lint": "eslint src/components/*.js",
18 | "test": "npm run lint",
19 | "build": "echo \"*** Building lib\n\" && rm -rf lib/* && babel src/components --optional runtime --stage 0 --out-dir lib/components && mkdir lib/css && cp ./src/css/*.css ./lib/css/ && babel src/js --optional runtime --stage 0 --out-dir lib/js && babel src/index.js --optional runtime --stage 0 --out-file lib/index.js",
20 | "start-website": "react-scripts start",
21 | "build-website": "echo \"*** Building website\n\" && rm -rf docs && react-scripts build && mv build docs",
22 | "precommit": "lint-staged",
23 | "prettier": "prettier --print-width 100 --tab-width 4 --write \"src/**/*.js\""
24 | },
25 | "lint-staged": {
26 | "*.js": [
27 | "prettier --print-width 100 --tab-width 4 --write",
28 | "git add"
29 | ]
30 | },
31 | "pre-commit": [
32 | "lint",
33 | "build"
34 | ],
35 | "license": "BSD-3-Clause-LBNL",
36 | "peerDependencies": {
37 | "react": "^16.2.0",
38 | "react-dom": "^16.2.0"
39 | },
40 | "dependencies": {
41 | "classnames": "^2.1.3",
42 | "deepcopy": "^0.6.3",
43 | "flexbox-react": "^4.2.1",
44 | "immutable": "^3.8.1",
45 | "invariant": "^2.2.3",
46 | "keymirror": "^0.1.1",
47 | "moment": "^2.21.0",
48 | "react-datepicker": "^1.2.2",
49 | "react-transition-group": "^1.0.0",
50 | "react-virtualized": "^9.18.5",
51 | "react-virtualized-select": "^3.1.3",
52 | "revalidator": "^0.3.1",
53 | "underscore": "^1.8.3"
54 | },
55 | "devDependencies": {
56 | "babel-cli": "^6.5.1",
57 | "babel-core": "^6.5.2",
58 | "babel-loader": "^7.1.4",
59 | "babel-plugin-transform-class-properties": "^6.22.0",
60 | "babel-preset-es2015": "^6.5.0",
61 | "babel-preset-react": "^6.5.0",
62 | "babel-preset-stage-0": "^6.5.0",
63 | "chance": "^1.0.6",
64 | "enzyme": "3.3.0",
65 | "enzyme-to-json": "3.3.1",
66 | "eslint-config-prettier": "^2.9.0",
67 | "eslint-config-react-app": "^2.1.0",
68 | "lint-staged": "^7.0.0",
69 | "prettier": "^1.11.1",
70 | "prop-types": "^15.6.1",
71 | "react": "^16.2.0",
72 | "react-docgen": "^2.20.1",
73 | "react-dom": "^16.2.0",
74 | "react-scripts": "^1.1.1",
75 | "react-select": "^1.2.1",
76 | "react-test-renderer": "^16.2.0"
77 | },
78 | "eslintConfig": {
79 | "extends": "react-app"
80 | }
81 | }
82 |
--------------------------------------------------------------------------------
/packages/react-dynamic-forms/public/favicon.ico:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/esnet/react-dynamic-forms/0f24c808fa1cadb3df6b1635cde377a0959acdd6/packages/react-dynamic-forms/public/favicon.ico
--------------------------------------------------------------------------------
/packages/react-dynamic-forms/public/index.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 | React Dynamic Forms
12 |
13 |
14 |
15 |
16 |
20 |
21 |
22 |
23 |
26 |
27 |
28 |
29 |
30 |
31 |
32 |
--------------------------------------------------------------------------------
/packages/react-dynamic-forms/src/components/CheckBoxes.js:
--------------------------------------------------------------------------------
1 | /**
2 | * Copyright (c) 2015 - present, The Regents of the University of California,
3 | * through Lawrence Berkeley National Laboratory (subject to receipt
4 | * of any required approvals from the U.S. Dept. of Energy).
5 | * All rights reserved.
6 | *
7 | * This source code is licensed under the BSD-style license found in the
8 | * LICENSE file in the root directory of this source tree.
9 | */
10 |
11 | import React from "react";
12 | import _ from "underscore";
13 | import Immutable from "immutable";
14 |
15 | import formGroup from "../js/formGroup";
16 |
17 | /**
18 | * Form control to select multiple items from a list,
19 | * uses checkboxes next to each item.
20 | */
21 | class CheckBoxes extends React.Component {
22 | componentWillReceiveProps(nextProps) {
23 | if (this.props.value !== nextProps.value) {
24 | const missingCount = this.isMissing(nextProps.value) ? 1 : 0;
25 | if (this.props.onMissingCountChange) {
26 | this.props.onMissingCountChange(this.props.name, missingCount);
27 | }
28 | }
29 | }
30 |
31 | handleChange(i) {
32 | let value;
33 | const option = this.props.optionList.get(i);
34 | if (this.props.value.includes(option)) {
35 | value = this.props.value.filterNot(item => item === option);
36 | } else {
37 | value = this.props.value.push(option);
38 | }
39 | if (this.props.onChange) {
40 | this.props.onChange(this.props.name, value);
41 | }
42 | }
43 |
44 | isEmpty(value) {
45 | if (Immutable.List.isList(value)) {
46 | return value.size === 0;
47 | }
48 | return _.isNull(value) || _.isUndefined(value);
49 | }
50 |
51 | isMissing(value = this.props.value) {
52 | return this.props.required && !this.props.disabled && this.isEmpty(value);
53 | }
54 |
55 | inlineStyle(hasError, isMissing) {
56 | let color = "inherited";
57 | let background = "inherited";
58 | if (hasError) {
59 | color = "#b94a48";
60 | background = "#fff0f3";
61 | } else if (isMissing) {
62 | background = "floralwhite";
63 | }
64 | return {
65 | color,
66 | background,
67 | width: "100%",
68 | paddingLeft: 3
69 | };
70 | }
71 |
72 | render() {
73 | if (this.props.edit) {
74 | const items = [];
75 | this.props.optionList.forEach((option, i) => {
76 | items.push(
77 |
78 |
79 | this.handleChange(i)}
83 | />
84 | {option}
85 |
86 |
87 | );
88 | });
89 |
90 | return (
91 |
92 | {items}
93 |
94 | );
95 | } else {
96 | return (
97 |
98 | {this.props.value.join(", ")}
99 |
100 | );
101 | }
102 | }
103 | }
104 |
105 | export default formGroup(CheckBoxes);
106 |
--------------------------------------------------------------------------------
/packages/react-dynamic-forms/src/components/DateEdit.js:
--------------------------------------------------------------------------------
1 | /**
2 | * Copyright (c) 2015 - present, The Regents of the University of California,
3 | * through Lawrence Berkeley National Laboratory (subject to receipt
4 | * of any required approvals from the U.S. Dept. of Energy).
5 | * All rights reserved.
6 | *
7 | * This source code is licensed under the BSD-style license found in the
8 | * LICENSE file in the root directory of this source tree.
9 | */
10 |
11 | import React from "react";
12 | import _ from "underscore";
13 | import moment from "moment";
14 | import PropTypes from "prop-types";
15 | import DatePicker from "react-datepicker";
16 |
17 | import formGroup from "../js/formGroup";
18 |
19 | import "react-datepicker/dist/react-datepicker.css";
20 | import "../css/dateedit.css";
21 |
22 | /**
23 | * Form control to edit a date text field.
24 | *
25 | * Set the initial value with `initialValue` and set a callback for
26 | * value changed with `onChange`.
27 | */
28 | class DateEdit extends React.Component {
29 | isEmpty(value) {
30 | return _.isNull(value) || _.isUndefined(value) || value === "";
31 | }
32 |
33 | isMissing(v) {
34 | return this.props.required && !this.props.disabled && this.isEmpty(v);
35 | }
36 |
37 | componentWillReceiveProps(nextProps) {
38 | if (this.props.value && nextProps.value) {
39 | if (this.props.value.getTime() !== nextProps.value.getTime()) {
40 | const missing = this.isMissing(nextProps.value);
41 | if (this.props.onMissingCountChange) {
42 | this.props.onMissingCountChange(this.props.name, missing ? 1 : 0);
43 | }
44 | }
45 | }
46 | }
47 |
48 | componentDidMount() {
49 | const missing = this.isMissing(this.props.value);
50 | if (this.props.onMissingCountChange) {
51 | this.props.onMissingCountChange(this.props.name, missing ? 1 : 0);
52 | }
53 | }
54 |
55 | handleDateChange(v) {
56 | const value = v ? v.toDate() : null;
57 | const missing = this.isMissing(value);
58 |
59 | // Callbacks
60 | if (this.props.onChange) {
61 | this.props.onChange(this.props.name, value);
62 | }
63 | if (this.props.onMissingCountChange) {
64 | this.props.onMissingCountChange(this.props.name, missing ? 1 : 0);
65 | }
66 | if (this.props.onBlur) {
67 | this.props.onBlur(this.props.name);
68 | }
69 | }
70 |
71 | inlineStyle(hasError, isMissing) {
72 | let color = "inherited";
73 | let background = "inherited";
74 | if (hasError) {
75 | color = "#b94a48";
76 | background = "#fff0f3";
77 | } else if (isMissing) {
78 | background = "floralwhite";
79 | }
80 | return {
81 | color,
82 | background,
83 | height: 23,
84 | width: "100%",
85 | paddingLeft: 3
86 | };
87 | }
88 |
89 | render() {
90 | // Control state
91 | const isMissing = this.isMissing(this.props.value);
92 |
93 | // Selected date
94 | const selected = this.props.value ? moment(this.props.value) : null;
95 |
96 | let className = "datepicker__input rdf";
97 |
98 | if (isMissing) {
99 | className += " is-missing";
100 | }
101 |
102 | if (this.props.edit) {
103 | return (
104 |
105 |
106 | { this.textInput = input; }}
109 | className={className}
110 | disabled={this.props.disabled}
111 | placeholderText={this.props.placeholder}
112 | selected={selected}
113 | onChange={v => this.handleDateChange(v)}
114 | />
115 |
116 |
117 | );
118 | } else {
119 | const hasError = false;
120 | let text = selected ? selected.format("MM/DD/YYYY") : "";
121 | if (isMissing) {
122 | text = " ";
123 | }
124 | const style = this.inlineStyle(hasError, isMissing);
125 | return {text}
;
126 | }
127 | }
128 | }
129 |
130 | DateEdit.propTypes = {
131 | /**
132 | * width - Customize the horizontal size of the Chooser
133 | */
134 | width: PropTypes.number,
135 |
136 | /**
137 | * field - The identifier of the field being edited
138 | */
139 | field: PropTypes.string
140 | };
141 |
142 | DateEdit.defaultProps = {
143 | width: 100
144 | };
145 |
146 | export default formGroup(DateEdit);
147 |
--------------------------------------------------------------------------------
/packages/react-dynamic-forms/src/components/Field.js:
--------------------------------------------------------------------------------
1 | /**
2 | * Copyright (c) 2017 - present, The Regents of the University of California,
3 | * through Lawrence Berkeley National Laboratory (subject to receipt
4 | * of any required approvals from the U.S. Dept. of Energy).
5 | * All rights reserved.
6 | *
7 | * This source code is licensed under the BSD-style license found in the
8 | * LICENSE file in the root directory of this source tree.
9 | */
10 |
11 | import React from "react";
12 | import invariant from "invariant";
13 | import PropTypes from "prop-types";
14 |
15 | /**
16 | * A `Field` is a part of the JSX definition of a `Schema`. Each `Field` describes
17 | * the rules and meta data associated with a field on the `Form`.
18 | *
19 | * For example, here is an `Field` which will input the users email address, defining
20 | * a user friendly label "Email", a placeholder and a validation rule that expects
21 | * the field to be a valid email address. The field is also required to be filled in.
22 | *
23 | * ```
24 | *
25 | * ...
26 | *
32 | * ...
33 | *
34 | * ```
35 | */
36 | export default class Field extends React.Component {
37 | render() {
38 | invariant(
39 | false,
40 | `${this.constructor.name} elements are for schema configuration only and should not be rendered`
41 | );
42 | return;
43 | }
44 | }
45 |
46 | Field.propTypes = {
47 | /**
48 | * name - The name of the field, or basically how it is referenced when rendering the field
49 | */
50 | name: PropTypes.string,
51 |
52 | /**
53 | * label - The UI fieldly name of the field, used when constructing a `Group`.
54 | */
55 | label: PropTypes.string,
56 |
57 | /**
58 | * placeholder - If appropiate to the widget, displays placeholder text.
59 | */
60 | placeholder: PropTypes.string,
61 |
62 | /**
63 | * validation* - See [Revalidator](https://github.com/flatiron/revalidator) for possible formats
64 | * for the validation property.
65 | */
66 | validation: PropTypes.object
67 | }
--------------------------------------------------------------------------------
/packages/react-dynamic-forms/src/components/RadioButtons.js:
--------------------------------------------------------------------------------
1 | /**
2 | * Copyright (c) 2017 - present, The Regents of the University of California,
3 | * through Lawrence Berkeley National Laboratory (subject to receipt
4 | * of any required approvals from the U.S. Dept. of Energy).
5 | * All rights reserved.
6 | *
7 | * This source code is licensed under the BSD-style license found in the
8 | * LICENSE file in the root directory of this source tree.
9 | */
10 |
11 | import React from "react";
12 | import _ from "underscore";
13 |
14 | import formGroup from "../js/formGroup";
15 |
16 | class RadioButtons extends React.Component {
17 | handleChange(v) {
18 | // Callbacks
19 | if (this.props.onChange) {
20 | this.props.onChange(this.props.name, v);
21 | }
22 | if (this.props.onBlur) {
23 | this.props.onBlur(this.props.name);
24 | }
25 | }
26 |
27 | getCurrentChoiceLabel() {
28 | const choiceItem = this.props.optionList.find(item => {
29 | return item.get("id") === this.props.value;
30 | });
31 | return choiceItem ? choiceItem.get("label") : "";
32 | }
33 |
34 | inlineStyle(hasError, isMissing) {
35 | let color = "inherited";
36 | let background = "inherited";
37 | if (hasError) {
38 | color = "#b94a48";
39 | background = "#fff0f3";
40 | } else if (isMissing) {
41 | background = "floralwhite";
42 | }
43 | return {
44 | color,
45 | background,
46 | width: "100%",
47 | paddingLeft: 3
48 | };
49 | }
50 |
51 | render() {
52 | if (this.props.edit) {
53 | const items = this.props.optionList.map((item, i) => {
54 | const id = item.get("id");
55 | const label = item.get("label");
56 | return (
57 |
58 |
59 | this.handleChange(id)}
66 | />
67 | {label}
68 |
69 |
70 | );
71 | });
72 | return (
73 |
74 | {items}
75 |
76 | );
77 | } else {
78 | let text = this.getCurrentChoiceLabel();
79 | return (
80 |
81 | {text}
82 |
83 | );
84 | }
85 | }
86 | }
87 |
88 | RadioButtons.defaultProps = {
89 | width: 300
90 | };
91 |
92 | export default formGroup(RadioButtons);
93 |
--------------------------------------------------------------------------------
/packages/react-dynamic-forms/src/components/Schema.js:
--------------------------------------------------------------------------------
1 | /**
2 | * Copyright (c) 2015 - present, The Regents of the University of California,
3 | * through Lawrence Berkeley National Laboratory (subject to receipt
4 | * of any required approvals from the U.S. Dept. of Energy).
5 | * All rights reserved.
6 | *
7 | * This source code is licensed under the BSD-style license found in the
8 | * LICENSE file in the root directory of this source tree.
9 | */
10 |
11 | import invariant from "invariant";
12 |
13 | /**
14 | * A schema can be specified using JSX to define the rules for
15 | * each form field. As an example, here is a Form that will take the
16 | * first name, last name and email of a contact. We can define also
17 | * that the email should be of format `email` and that the first and
18 | * last names are `required`:
19 | *
20 | * ```
21 | * const schema = (
22 | *
23 | *
25 | *
27 | *
29 | *
30 | * );
31 | * ```
32 | *
33 | * See also `Field`.
34 | */
35 | export default class Schema {
36 | render() {
37 | invariant(
38 | false,
39 | `${this.constructor
40 | .name} elements are for schema configuration only and should not be rendered`
41 | );
42 | return;
43 | }
44 | }
45 |
--------------------------------------------------------------------------------
/packages/react-dynamic-forms/src/components/TagsEdit.js:
--------------------------------------------------------------------------------
1 | /**
2 | * Copyright (c) 2015 - present, The Regents of the University of California,
3 | * through Lawrence Berkeley National Laboratory (subject to receipt
4 | * of any required approvals from the U.S. Dept. of Energy).
5 | * All rights reserved.
6 | *
7 | * This source code is licensed under the BSD-style license found in the
8 | * LICENSE file in the root directory of this source tree.
9 | */
10 |
11 | import React from "react";
12 | import _ from "underscore";
13 | import { Creatable } from "react-select";
14 | import Immutable from "immutable";
15 |
16 | import formGroup from "../js/formGroup";
17 |
18 | import "react-select/dist/react-select.css";
19 | import "../css/tagsedit.css";
20 |
21 | /**
22 | * Form control to select tags from a pull down list.
23 | * You can also add a new tag with the Add tag button.
24 | */
25 | class TagsEdit extends React.Component {
26 | constructor(props) {
27 | super(props);
28 | this.state = {
29 | touched: false
30 | };
31 | }
32 |
33 | componentWillReceiveProps(nextProps) {
34 | if (this.props.value !== nextProps.value) {
35 | const missingCount = this.isMissing(nextProps.value) ? 1 : 0;
36 | if (this.props.onMissingCountChange) {
37 | this.props.onMissingCountChange(this.props.name, missingCount);
38 | }
39 | }
40 | }
41 |
42 | handleChange(tags) {
43 | const value = _.map(tags, tag => tag.label);
44 |
45 | let updatedTagList;
46 | _.each(tags, tag => {
47 | if (tag.className === "Select-create-option-placeholder") {
48 | updatedTagList = this.props.tagList.push(tag.label);
49 | }
50 | });
51 |
52 | if (updatedTagList && this.props.onTagListChange) {
53 | this.props.onTagListChange(this.props.name, updatedTagList);
54 | }
55 |
56 | if (this.props.onChange) {
57 | this.props.onChange(this.props.name, Immutable.fromJS(value));
58 | }
59 | }
60 |
61 | isEmpty(value) {
62 | if (Immutable.List.isList(value)) {
63 | return value.size === 0;
64 | }
65 | return _.isNull(value) || _.isUndefined(value);
66 | }
67 |
68 | isMissing(value = this.props.value) {
69 | return this.props.required && !this.props.disabled && this.isEmpty(value);
70 | }
71 |
72 | render() {
73 | const isMissing = this.isMissing(this.props.value);
74 | if (this.props.edit) {
75 | const options = [];
76 | const value = [];
77 |
78 | this.props.tagList.forEach((tag, i) => {
79 | if (this.props.value.contains(tag)) {
80 | value.push({ value: i, label: tag });
81 | } else {
82 | options.push({ value: i, label: tag });
83 | }
84 | });
85 |
86 | let className;
87 | if (isMissing) {
88 | className = "missing";
89 | }
90 |
91 | return (
92 |
93 |
this.handleChange(value)}
103 | />
104 |
105 |
106 | );
107 | } else {
108 | const tagStyle = {
109 | cursor: "default",
110 | paddingTop: 2,
111 | paddingBottom: 2,
112 | paddingLeft: 5,
113 | paddingRight: 5,
114 | background: "#ececec",
115 | borderRadius: 2,
116 | marginLeft: 2,
117 | marginRight: 2
118 | };
119 | return (
120 |
121 | {this.props.value.map((tag, i) => {tag} )}
122 |
123 | );
124 | }
125 | }
126 | }
127 |
128 | export default formGroup(TagsEdit);
129 |
--------------------------------------------------------------------------------
/packages/react-dynamic-forms/src/components/TextArea.js:
--------------------------------------------------------------------------------
1 | /**
2 | * Copyright (c) 2015 - present, The Regents of the University of California,
3 | * through Lawrence Berkeley National Laboratory (subject to receipt
4 | * of any required approvals from the U.S. Dept. of Energy).
5 | * All rights reserved.
6 | *
7 | * This source code is licensed under the BSD-style license found in the
8 | * LICENSE file in the root directory of this source tree.
9 | */
10 |
11 | import React from "react";
12 | import _ from "underscore";
13 | import { validate } from "revalidator";
14 |
15 | import formGroup from "../js/formGroup";
16 |
17 | import "../css/textarea.css";
18 |
19 | /**
20 | * Form control to edit a Text Area field
21 | */
22 | class TextArea extends React.Component {
23 | constructor(props) {
24 | super(props);
25 | this.state = {
26 | touched: false
27 | };
28 | }
29 |
30 | isEmpty(value) {
31 | return _.isNull(value) || _.isUndefined(value) || value === "";
32 | }
33 |
34 | isMissing(v) {
35 | return this.props.required && !this.props.disabled && this.isEmpty(v);
36 | }
37 |
38 | getError(value) {
39 | let result = { validationError: false, validationErrorMessage: null };
40 |
41 | // If the user has a field blank then that is never an error
42 | // Likewise if this item is disabled it can't be called an error
43 | if (this.isEmpty(value) || this.props.disabled) {
44 | return result;
45 | }
46 |
47 | // Validate the value with Revalidator, given the rules in this.props.rules
48 | let obj = {};
49 | obj[this.props.name] = value;
50 |
51 | let properties = {};
52 | properties[this.props.name] = this.props.rules;
53 |
54 | const rules = this.props.rules ? { properties } : null;
55 | if (obj && rules) {
56 | const validation = validate(obj, rules, { cast: true });
57 | const name = this.props.name || "Value";
58 |
59 | let msg;
60 | if (!validation.valid) {
61 | msg = `${name} ${validation.errors[0].message}`;
62 | result.validationError = true;
63 | result.validationErrorMessage = msg;
64 | }
65 | }
66 | return result;
67 | }
68 |
69 | componentWillReceiveProps(nextProps) {
70 | if (this.props.value !== nextProps.value) {
71 | const missing = this.isMissing(nextProps.value);
72 | const { validationError } = this.getError(nextProps.value);
73 |
74 | // Broadcast error and missing states up to the owner
75 | if (this.props.onErrorCountChange) {
76 | this.props.onErrorCountChange(this.props.name, validationError ? 1 : 0);
77 | }
78 |
79 | if (this.props.onMissingCountChange) {
80 | this.props.onMissingCountChange(this.props.name, missing ? 1 : 0);
81 | }
82 | }
83 | }
84 |
85 | componentDidMount() {
86 | const missing = this.isMissing(this.props.value);
87 | const { validationError } = this.getError(this.props.value);
88 |
89 | // Initial error and missing states are fed up to the owner
90 | if (this.props.onErrorCountChange) {
91 | this.props.onErrorCountChange(this.props.name, validationError ? 1 : 0);
92 | }
93 |
94 | if (this.props.onMissingCountChange) {
95 | this.props.onMissingCountChange(this.props.name, missing ? 1 : 0);
96 | }
97 | }
98 |
99 | onBlur() {
100 | const { value } = this.textInput;
101 | const missing = this.props.required && this.isEmpty(value);
102 | const { validationError } = this.getError(value);
103 |
104 | // Callbacks
105 | if (this.props.onChange) {
106 | this.props.onChange(this.props.name, value);
107 | }
108 | if (this.props.onErrorCountChange) {
109 | this.props.onErrorCountChange(this.props.name, validationError ? 1 : 0);
110 | }
111 | if (this.props.onMissingCountChange) {
112 | this.props.onMissingCountChange(this.props.name, missing ? 1 : 0);
113 | }
114 |
115 | this.setState({ touched: true });
116 | }
117 |
118 | inlineStyle(hasError, isMissing) {
119 | let color = "";
120 | let background = "";
121 | if (hasError) {
122 | color = "#b94a48";
123 | background = "#fff0f3";
124 | } else if (isMissing) {
125 | background = "floralwhite";
126 | }
127 | return {
128 | color,
129 | background,
130 | height: "100%",
131 | width: "100%",
132 | paddingLeft: 3
133 | };
134 | }
135 |
136 | render() {
137 | // Control state
138 | const isMissing = this.isMissing(this.props.value);
139 | const { validationError, validationErrorMessage } = this.getError(this.props.value);
140 |
141 | if (this.props.edit) {
142 | // Error style/message
143 | let className = "";
144 | const msg = validationError ? validationErrorMessage : "";
145 | let helpClassName = "help-block";
146 | if (validationError && this.state.touched) {
147 | helpClassName += " has-error";
148 | className = "has-error";
149 | }
150 |
151 | // Warning style
152 | const style = isMissing ? { background: "floralwhite" } : {};
153 |
154 | return (
155 |
156 |
{ this.textInput = input; }}
158 | key={this.props.value}
159 | className="form-control"
160 | style={style}
161 | type="text"
162 | disabled={this.props.disabled}
163 | placeholder={this.props.placeholder}
164 | defaultValue={this.props.value}
165 | rows={this.props.rows}
166 | onBlur={() => this.onBlur()}
167 | />
168 | {msg}
169 |
170 | );
171 | } else {
172 | const view = this.props.view;
173 | let text = this.props.value;
174 | if (isMissing) {
175 | text = " ";
176 | }
177 | const style = {
178 | height: 100,
179 | ...this.inlineStyle(validationError, isMissing)
180 | };
181 | if (!view) {
182 | return {text}
;
183 | } else {
184 | return {view(text)}
;
185 | }
186 | }
187 | }
188 | }
189 |
190 | export default formGroup(TextArea);
191 |
--------------------------------------------------------------------------------
/packages/react-dynamic-forms/src/components/TextEdit.js:
--------------------------------------------------------------------------------
1 | /**
2 | * Copyright (c) 2015 - present, The Regents of the University of California,
3 | * through Lawrence Berkeley National Laboratory (subject to receipt
4 | * of any required approvals from the U.S. Dept. of Energy).
5 | * All rights reserved.
6 | *
7 | * This source code is licensed under the BSD-style license found in the
8 | * LICENSE file in the root directory of this source tree.
9 | */
10 |
11 | import React from "react";
12 | import _ from "underscore";
13 | import { validate } from "revalidator";
14 |
15 | import formGroup from "../js/formGroup";
16 |
17 | import "../css/textedit.css";
18 |
19 | /**
20 | * Form control to edit a text field.
21 | * Set the initial value with `initialValue` and set a callback for
22 | * value changed with `onChange`.
23 | */
24 | class TextEdit extends React.Component {
25 | constructor(props) {
26 | super(props);
27 | this.state = {
28 | touched: false
29 | };
30 | }
31 |
32 | isEmpty(value) {
33 | return _.isNull(value) || _.isUndefined(value) || value === "";
34 | }
35 |
36 | isMissing(v) {
37 | return this.props.required && !this.props.disabled && this.isEmpty(v);
38 | }
39 |
40 | getError(value) {
41 | const result = { validationError: false, validationErrorMessage: null };
42 |
43 | // If the user has a field blank then that is never an error. Likewise if the field
44 | // is disabled then that is never an error.
45 | if (this.isEmpty(value) || this.props.disabled) {
46 | return result;
47 | }
48 |
49 | // Validate the value with Revalidator, given the rules in this.props.rules
50 | let obj = {};
51 | obj[this.props.name] = value;
52 |
53 | let properties = {};
54 | properties[this.props.name] = this.props.validation;
55 |
56 | const rules = this.props.validation ? { properties } : null;
57 | if (obj && rules) {
58 | const validation = validate(obj, rules, { cast: true });
59 | const name = this.props.name || "Value";
60 |
61 | let msg;
62 | if (!validation.valid) {
63 | msg = `${name} ${validation.errors[0].message}`;
64 | result.validationError = true;
65 | result.validationErrorMessage = msg;
66 | }
67 | }
68 | return result;
69 | }
70 |
71 | componentWillReceiveProps(nextProps) {
72 | if (this.props.value !== nextProps.value) {
73 | const missing = this.isMissing(nextProps.value);
74 | const { validationError } = this.getError(nextProps.value);
75 |
76 | // Broadcast error and missing states up to the owner
77 | if (this.props.onErrorCountChange) {
78 | this.props.onErrorCountChange(this.props.name, validationError ? 1 : 0);
79 | }
80 |
81 | if (this.props.onMissingCountChange) {
82 | this.props.onMissingCountChange(this.props.name, missing ? 1 : 0);
83 | }
84 | }
85 | }
86 |
87 | componentDidMount() {
88 | const missing = this.isMissing(this.props.value);
89 | const { validationError } = this.getError(this.props.value);
90 |
91 | // Initial error and missing states are fed up to the owner
92 | if (this.props.onErrorCountChange) {
93 | this.props.onErrorCountChange(this.props.name, validationError ? 1 : 0);
94 | }
95 |
96 | if (this.props.onMissingCountChange) {
97 | this.props.onMissingCountChange(this.props.name, missing ? 1 : 0);
98 | }
99 | }
100 |
101 | handleChange() {
102 | const { value } = this.textInput;
103 | const missing = this.props.required && this.isEmpty(value);
104 | const { validationError } = this.getError(value);
105 | let cast = value;
106 |
107 | // Callbacks
108 | if (this.props.onErrorCountChange) {
109 | this.props.onErrorCountChange(this.props.name, validationError ? 1 : 0);
110 | }
111 |
112 | if (this.props.onMissingCountChange) {
113 | this.props.onMissingCountChange(this.props.name, missing ? 1 : 0);
114 | }
115 |
116 | if (this.props.onChange) {
117 | if (_.has(this.props.rules, "type")) {
118 | switch (this.props.rules.type) {
119 | case "integer":
120 | cast = value === "" ? null : parseInt(value, 10);
121 | break;
122 | case "number":
123 | cast = value === "" ? null : parseFloat(value, 10);
124 | break;
125 | //pass
126 | default:
127 | }
128 | }
129 | this.props.onChange(this.props.name, cast);
130 | }
131 | }
132 |
133 | handleBlur() {
134 | if (this.props.onBlur) {
135 | this.props.onBlur(this.props.name);
136 | }
137 |
138 | this.setState({ touched: true });
139 | }
140 |
141 | inlineStyle(hasError, isMissing) {
142 | let color = "";
143 | let background = "";
144 | if (hasError) {
145 | color = "#b94a48";
146 | background = "#fff0f3";
147 | } else if (isMissing) {
148 | background = "floralwhite";
149 | }
150 | return {
151 | color,
152 | background,
153 | // height: 23,
154 | height: "100%",
155 | width: "100%",
156 | paddingLeft: 3
157 | };
158 | }
159 |
160 | render() {
161 | // Control state
162 | const isMissing = this.isMissing(this.props.value);
163 | const { validationError, validationErrorMessage } = this.getError(this.props.value);
164 |
165 | if (this.props.edit) {
166 | // Error style/message
167 | let className = "";
168 | const msg = validationError && this.state.touched ? validationErrorMessage : "";
169 | let helpClassName = "help-block";
170 | if (validationError && this.state.touched) {
171 | helpClassName += " has-error";
172 | className = "has-error";
173 | }
174 |
175 | // Warning style
176 | const style = isMissing ? { background: "floralwhite" } : {};
177 |
178 | const type = this.props.type || "text";
179 |
180 | return (
181 |
182 |
{ this.textInput = input; }}
184 | className="form-control input-sm"
185 | style={style}
186 | type={type}
187 | disabled={this.props.disabled}
188 | placeholder={this.props.placeholder}
189 | value={this.props.value}
190 | onChange={() => this.handleChange()}
191 | onBlur={() => this.handleBlur()}
192 | />
193 |
{msg}
194 |
195 | );
196 | } else {
197 | const view = this.props.view;
198 | let text = this.props.value;
199 | if (isMissing) {
200 | text = " ";
201 | }
202 | const style = this.inlineStyle(validationError, isMissing);
203 | if (!view) {
204 | return {text}
;
205 | } else {
206 | return {view(text)}
;
207 | }
208 | }
209 | }
210 | }
211 |
212 | export default formGroup(TextEdit);
213 |
--------------------------------------------------------------------------------
/packages/react-dynamic-forms/src/components/View.js:
--------------------------------------------------------------------------------
1 | /**
2 | * Copyright (c) 2015 - present, The Regents of the University of California,
3 | * through Lawrence Berkeley National Laboratory (subject to receipt
4 | * of any required approvals from the U.S. Dept. of Energy).
5 | * All rights reserved.
6 | *
7 | * This source code is licensed under the BSD-style license found in the
8 | * LICENSE file in the root directory of this source tree.
9 | */
10 |
11 | import React from "react";
12 |
13 | import formGroup from "../js/formGroup";
14 |
15 | class View extends React.Component {
16 | render() {
17 | const text = this.props.value;
18 | const view = this.props.view;
19 | let color = "";
20 | let background = "";
21 | const style = {
22 | color,
23 | background,
24 | // height: 23,
25 | height: "100%",
26 | width: "100%",
27 | paddingLeft: 3
28 | };
29 | if (!view) {
30 | return (
31 |
32 | {text}
33 |
34 | );
35 | } else {
36 | return (
37 |
38 | {view(text)}
39 |
40 | );
41 | }
42 | }
43 | }
44 |
45 | export default formGroup(View, true);
--------------------------------------------------------------------------------
/packages/react-dynamic-forms/src/css/chooser.css:
--------------------------------------------------------------------------------
1 | /**
2 | * Copyright (c) 2015 - present, The Regents of the University of California,
3 | * through Lawrence Berkeley National Laboratory (subject to receipt
4 | * of any required approvals from the U.S. Dept. of Energy).
5 | * All rights reserved.
6 | *
7 | * This source code is licensed under the BSD-style license found in the
8 | * LICENSE file in the root directory of this source tree.
9 | */
10 |
11 | .Select-control {
12 | height: 30px;
13 | }
14 |
15 | .Select-value {
16 | line-height: 26px !important;
17 | }
18 |
19 | .Select-value-label {
20 | line-height: 26px;
21 | font-size: 12px;
22 | }
23 |
24 | .Select-menu-outer {
25 | font-size: 12px;
26 | }
27 |
28 | .Select-input {
29 | height: 26px;
30 | }
31 |
32 | .Select-placeholder {
33 | line-height: 20px;
34 | font-size: 12px;
35 | padding-top: 5px;
36 | }
37 |
38 | .Select.is-missing > .Select-control {
39 | background: floralwhite;
40 | }
--------------------------------------------------------------------------------
/packages/react-dynamic-forms/src/css/dateedit.css:
--------------------------------------------------------------------------------
1 | /**
2 | * Copyright (c) 2015 - present, The Regents of the University of California,
3 | * through Lawrence Berkeley National Laboratory (subject to receipt
4 | * of any required approvals from the U.S. Dept. of Energy).
5 | * All rights reserved.
6 | *
7 | * This source code is licensed under the BSD-style license found in the
8 | * LICENSE file in the root directory of this source tree.
9 | */
10 |
11 | input.datepicker__input.rdf {
12 | font-size: 12px;
13 | height: 30px;
14 | margin-bottom: 10px;
15 | border-radius: 3px;
16 | padding-left: 6px;
17 | color: #555555;
18 | background-color: #ffffff;
19 | background-image: none;
20 | border: 1px solid #cccccc;
21 | border-radius: 4px;
22 | -webkit-box-shadow: inset 0 1px 1px rgba(0,0,0,0.075);
23 | box-shadow: inset 0 1px 1px rgba(0,0,0,0.075);
24 | -webkit-transition: border-color ease-in-out .15s,-webkit-box-shadow ease-in-out .15s;
25 | -o-transition: border-color ease-in-out .15s,box-shadow ease-in-out .15s;
26 | transition: border-color ease-in-out .15s,box-shadow ease-in-out .15s;
27 | }
28 |
29 | input.datepicker__input.rdf:focus {
30 | border-color: #66afe9;
31 | outline: 0;
32 | -webkit-box-shadow: inset 0 1px 1px rgba(0,0,0,0.075),0 0 8px rgba(102,175,233,0.6);
33 | box-shadow: inset 0 1px 1px rgba(0,0,0,0.075),0 0 8px rgba(102,175,233,0.6);
34 | }
35 |
36 | input.datepicker__input.has-error {
37 | border-color: #B94A48;
38 | }
39 |
40 | input.datepicker__input.is-missing {
41 | background-color: floralwhite;
42 | }
43 |
--------------------------------------------------------------------------------
/packages/react-dynamic-forms/src/css/group.css:
--------------------------------------------------------------------------------
1 | /**
2 | * Copyright (c) 2015 - present, The Regents of the University of California,
3 | * through Lawrence Berkeley National Laboratory (subject to receipt
4 | * of any required approvals from the U.S. Dept. of Energy).
5 | * All rights reserved.
6 | *
7 | * This source code is licensed under the BSD-style license found in the
8 | * LICENSE file in the root directory of this source tree.
9 | */
10 |
11 | .group-required {
12 | color: orange;
13 | font-size: larger;
14 | }
15 |
16 | .group-label {
17 | text-align: right;
18 | padding-right: 0px;
19 | text-transform: uppercase;
20 | font-size: smaller;
21 | }
--------------------------------------------------------------------------------
/packages/react-dynamic-forms/src/css/icon.css:
--------------------------------------------------------------------------------
1 | /**
2 | * Copyright (c) 2015 - present, The Regents of the University of California,
3 | * through Lawrence Berkeley National Laboratory (subject to receipt
4 | * of any required approvals from the U.S. Dept. of Energy).
5 | * All rights reserved.
6 | *
7 | * This source code is licensed under the BSD-style license found in the
8 | * LICENSE file in the root directory of this source tree.
9 | */
10 |
11 | .icon {
12 | cursor: pointer;
13 | font-size: 9px;
14 | padding-bottom: 10px;
15 | color: steelblue;
16 | padding-top: 3px;
17 | }
18 |
19 | .hostile_icon {
20 | cursor: pointer;
21 | font-size: 9px;
22 | padding-bottom: 10px;
23 | color: #b94a48;
24 | padding-top: 3px;
25 | }
26 |
27 | .delete-action:hover {
28 | color: #b94a48;
29 | }
30 |
31 | .edit-action:hover {
32 | color: steelblue;
33 | }
34 |
35 | .edit-action.active {
36 | color: steelblue;
37 | }
38 |
39 | .add-action:hover {
40 | color: green;
41 | }
42 |
--------------------------------------------------------------------------------
/packages/react-dynamic-forms/src/css/list.css:
--------------------------------------------------------------------------------
1 | /**
2 | * Copyright (c) 2015 - present, The Regents of the University of California,
3 | * through Lawrence Berkeley National Laboratory (subject to receipt
4 | * of any required approvals from the U.S. Dept. of Energy).
5 | * All rights reserved.
6 | *
7 | * This source code is licensed under the BSD-style license found in the
8 | * LICENSE file in the root directory of this source tree.
9 | */
10 |
11 | /*
12 | * The container includes the whole list, but not the [+] at the bottom
13 | */
14 | .esnet-forms-listeditview-container {
15 | padding-left: 0px;
16 | list-style-type: none;
17 | margin-bottom: 0px;
18 | }
19 |
20 | .esnet-forms-listeditview-container:last-child {
21 | margin-bottom: 0;
22 | }
23 |
24 | /*
25 | * The inner LI of the container is each item, including the [-] control
26 | */
27 |
28 | .esnet-forms-listeditview-container li {
29 | margin-left: 0px;
30 | }
31 |
32 | /*
33 | * The main styling for each item
34 | */
35 |
36 | .esnet-forms-listeditview-edit-item {
37 | width: 95%;
38 | margin-bottom: 10px;
39 | padding-top: 2px;
40 | }
41 |
42 | .esnet-forms-listeditview-edit-item.no-controls {
43 | width: 95%;
44 | }
45 |
46 | /*
47 | .esnet-forms-minus-action-box {
48 | float: left;
49 | margin-top: 5px;
50 | vertical-align: top;
51 | width: 28px;
52 | height: 28px;
53 | background: #EDEDED;
54 | margin-left: -5px;
55 | z-index: 10;
56 | border: #E5E5E5;
57 | border-style: solid;
58 | border-width: 1px;
59 | border-radius: 2px;
60 | }*/
61 |
62 | .esnet-forms-plus-action-box-dialog {
63 | clear: both;
64 | border-width: 1px;
65 | border-color: #cef4d2;
66 | border-style: solid;
67 | border-radius: 4px;
68 | padding: 10px;
69 | height: 70px;
70 | width: 95%;
71 | background: #efe;
72 | }
73 |
74 | /*
75 | List transitions
76 | */
77 |
78 | .esnet-forms-list {
79 | font-size: 12px;
80 | }
81 |
82 | /** start of entering and end of leaving **/
83 | li.esnet-forms-list-item-enter,
84 | li.esnet-forms-list-item-leave.esnet-forms-list-item-leave-active {
85 | opacity: 0.01;
86 | max-height: 0px;
87 | }
88 |
89 | /** start of leaving and end of entering **/
90 | li.esnet-forms-list-item-leave,
91 | li.esnet-forms-list-item-enter.esnet-forms-list-item-enter-active {
92 | opacity: 1;
93 | max-height: 100px;
94 | /*max-height: 50px;*/
95 | }
96 |
97 | /** ease in out quint **/
98 | li.esnet-forms-list-item-enter,
99 | li.esnet-forms-list-item-leave {
100 | -moz-transition: all 100ms ease 0s;
101 | -webkit-transition: all 100ms ease 0s;
102 | transition: all 100ms ease 0s;
103 | }
104 |
--------------------------------------------------------------------------------
/packages/react-dynamic-forms/src/css/tagsedit.css:
--------------------------------------------------------------------------------
1 | /**
2 | * Copyright (c) 2015 - present, The Regents of the University of California,
3 | * through Lawrence Berkeley National Laboratory (subject to receipt
4 | * of any required approvals from the U.S. Dept. of Energy).
5 | * All rights reserved.
6 | *
7 | * This source code is licensed under the BSD-style license found in the
8 | * LICENSE file in the root directory of this source tree.
9 | */
10 |
11 | .Select-control {
12 | height: 26px;
13 | }
14 |
15 | .Select-value {
16 | line-height: 26px !important;
17 | }
18 |
19 | .Select-value-label {
20 | line-height: 24px;
21 | font-size: 12px;
22 | }
23 |
24 | .Select-menu-outer {
25 | font-size: 12px;
26 | }
27 |
28 | .Select-input {
29 | height: 26px;
30 | }
31 |
32 | .Select.is-missing > .Select-control {
33 | background: floralwhite;
34 | }
35 |
36 | .Select--multi .Select-value {
37 | height: 26px;
38 | height: 24px;
39 | margin-top: 1px;
40 | border-color: #ccc
41 | }
42 |
43 | .Select--multi .Select-value-label {
44 | line-height: 22px;
45 | font-size: 12px;
46 | padding: 0px;
47 | margin-top: -6px;
48 | padding-left: 5px;
49 | padding-right: 5px;
50 | background: #DDD;
51 | color: #555555;
52 | border-color: #555;
53 | }
54 |
55 | .Select--multi .Select-value-icon {
56 | line-height: 22px;
57 | font-size: 12px;
58 | padding: 0px;
59 | margin-top: -6px;
60 | padding-left: 5px;
61 | padding-right: 5px;
62 | background: #DDD;
63 | color: #555555;
64 | border-right-color: #ccc;
65 | }
66 |
67 | .Select--multi .Select-value-icon:hover {
68 | background: #DFDFDF;
69 | color: #b94a48;
70 | }
71 |
72 | .Select.missing.Select--multi.is-searchable > .Select-control {
73 | background: floralwhite;
74 | }
--------------------------------------------------------------------------------
/packages/react-dynamic-forms/src/css/textarea.css:
--------------------------------------------------------------------------------
1 | /**
2 | * Copyright (c) 2015 - present, The Regents of the University of California,
3 | * through Lawrence Berkeley National Laboratory (subject to receipt
4 | * of any required approvals from the U.S. Dept. of Energy).
5 | * All rights reserved.
6 | *
7 | * This source code is licensed under the BSD-style license found in the
8 | * LICENSE file in the root directory of this source tree.
9 | */
10 |
11 | textarea.form-control {
12 | font-size: 12px;
13 | padding-left: 10px;
14 | }
15 |
--------------------------------------------------------------------------------
/packages/react-dynamic-forms/src/css/textedit.css:
--------------------------------------------------------------------------------
1 | /**
2 | * Copyright (c) 2015 - present, The Regents of the University of California,
3 | * through Lawrence Berkeley National Laboratory (subject to receipt
4 | * of any required approvals from the U.S. Dept. of Energy).
5 | * All rights reserved.
6 | *
7 | * This source code is licensed under the BSD-style license found in the
8 | * LICENSE file in the root directory of this source tree.
9 | */
10 |
11 | datepicker__input.has-error {
12 | border-color: "green"
13 | }
--------------------------------------------------------------------------------
/packages/react-dynamic-forms/src/index.js:
--------------------------------------------------------------------------------
1 | /**
2 | * Copyright (c) 2015 - present, The Regents of the University of California,
3 | * through Lawrence Berkeley National Laboratory (subject to receipt
4 | * of any required approvals from the U.S. Dept. of Energy).
5 | * All rights reserved.
6 | *
7 | * This source code is licensed under the BSD-style license found in the
8 | * LICENSE file in the root directory of this source tree.
9 | */
10 |
11 | import Form from "./components/Form";
12 | import Schema from "./components/Schema";
13 | import Field from "./components/Field";
14 | import formGroup from "./js/formGroup";
15 | import formList from "./js/formList";
16 | import List from "./components/List";
17 | import TextEdit from "./components/TextEdit";
18 | import TextArea from "./components/TextArea";
19 | import Chooser from "./components/Chooser.js";
20 | import DateEdit from "./components/DateEdit";
21 | import TagsEdit from "./components/TagsEdit";
22 | import RadioButtons from "./components/RadioButtons";
23 | import CheckBoxes from "./components/CheckBoxes";
24 | import View from "./components/View";
25 | import { FormEditStates, FormGroupLayout } from "./js/constants";
26 |
27 | export { Form };
28 | export { Schema };
29 | export { Field };
30 | export { formGroup };
31 | export { formList };
32 | export { List };
33 | export { TextEdit };
34 | export { TextArea };
35 | export { Chooser };
36 | export { DateEdit };
37 | export { TagsEdit };
38 | export { RadioButtons };
39 | export { CheckBoxes };
40 | export { View };
41 | export { FormEditStates, FormGroupLayout };
--------------------------------------------------------------------------------
/packages/react-dynamic-forms/src/js/constants.js:
--------------------------------------------------------------------------------
1 | /**
2 | * Copyright (c) 2017 - present, The Regents of the University of California,
3 | * through Lawrence Berkeley National Laboratory (subject to receipt
4 | * of any required approvals from the U.S. Dept. of Energy).
5 | * All rights reserved.
6 | *
7 | * This source code is licensed under the BSD-style license found in the
8 | * LICENSE file in the root directory of this source tree.
9 | */
10 |
11 | import keymirror from "keymirror";
12 |
13 | module.exports = {
14 | /**
15 | * At Form can either:
16 | * * ALL - Always show edit state for all of its fields
17 | * * SELECTION - Show edit icons next to items, selecting one show edit state for that item
18 | * * NEVER - Never show edit state for the items (view only)
19 | */
20 | FormEditStates: keymirror({
21 | ALWAYS: null,
22 | SELECTED: null,
23 | NEVER: null,
24 | TABLE: null
25 | }),
26 |
27 | FormGroupLayout: keymirror({
28 | ROW: null,
29 | COLUMN: null,
30 | INLINE: null
31 | })
32 | };
33 |
--------------------------------------------------------------------------------
/packages/react-dynamic-forms/src/js/formList.js:
--------------------------------------------------------------------------------
1 | /**
2 | * Copyright (c) 2015 - present, The Regents of the University of California,
3 | * through Lawrence Berkeley National Laboratory (subject to receipt
4 | * of any required approvals from the U.S. Dept. of Energy).
5 | * All rights reserved.
6 | *
7 | * This source code is licensed under the BSD-style license found in the
8 | * LICENSE file in the root directory of this source tree.
9 | */
10 |
11 | import React from "react";
12 | import _ from "underscore";
13 | import Immutable from "immutable";
14 |
15 | import List from "../components/List";
16 |
17 | /**
18 | * A Higher-order component -- a function that takes the item
19 | * Component class and returns a new Component that manages a
20 | * list of that class.
21 | */
22 | export default function list(ItemComponent, hideEditRemove) {
23 | return class HOC extends React.Component {
24 | constructor(props) {
25 | super(props);
26 | this.state = { errors: [], missing: [], selected: null };
27 | }
28 |
29 | handleSelectItem(i) {
30 | if (this.state.selected !== i) {
31 | this.setState({ selected: i });
32 | } else {
33 | this.setState({ selected: null });
34 | }
35 | }
36 |
37 | //Handle an item at i changing to a new value.
38 | handleChangeItem(i, value) {
39 | let newValue = this.props.value.set(i, value);
40 | if (this.props.onChange) {
41 | this.props.onChange(this.props.name, newValue);
42 | }
43 | }
44 |
45 | handleMissingCountChange(i, missingCount) {
46 | let totalMissingCount;
47 | let missingList = this.state.missing;
48 | missingList[i] = missingCount;
49 | totalMissingCount = _.reduce(missingList, (memo, num) => memo + num, 0);
50 |
51 | // Callback
52 | if (this.props.onMissingCountChange) {
53 | this.props.onMissingCountChange(this.props.name, totalMissingCount);
54 | }
55 | }
56 |
57 | /**
58 | * Handler for if a child changes its error count
59 | */
60 | handleErrorCountChange(i, errorCount) {
61 | let totalErrorCount;
62 | let errorList = this.state.errors;
63 | errorList[i] = errorCount;
64 | totalErrorCount = _.reduce(errorList, (memo, num) => memo + num, 0);
65 |
66 | // Callback
67 | if (this.props.onErrorCountChange) {
68 | this.props.onErrorCountChange(this.props.name, totalErrorCount);
69 | }
70 | }
71 |
72 | // Handle removing an item. Here it splices out the item
73 | // at the supplied index and updates the list of items on the state.
74 | //
75 | // Also updates the error and missing lists to match.
76 | handleRemovedItem(i) {
77 | let value = this.props.value;
78 |
79 | let n = 1;
80 | let errors = this.state.errors;
81 | let missing = this.state.missing;
82 | errors.splice(i - n + 1, n);
83 | missing.splice(i - n + 1, n);
84 | this.setState({ errors, missing });
85 |
86 | // Callbacks
87 | if (this.props.onChange) {
88 | this.props.onChange(this.props.name, value.splice(i - n + 1, n));
89 | }
90 | if (this.props.onErrorCountChange) {
91 | this.props.onErrorCountChange(this.props.name, this.numErrors(errors));
92 | }
93 | if (this.props.onMissingCountChange) {
94 | this.props.onMissingCountChange(this.props.name, this.numMissing(missing));
95 | }
96 | }
97 |
98 | handleAddItem() {
99 | let value = this.props.value;
100 |
101 | let errors = this.state.errors;
102 | let missing = this.state.missing;
103 | let created = Immutable.fromJS(ItemComponent.defaultValues);
104 | errors.push(0);
105 | missing.push(0);
106 |
107 | // Callbacks
108 | if (this.props.onChange) {
109 | this.props.onChange(this.props.name, value.push(created));
110 | }
111 | if (this.props.onErrorCountChange) {
112 | this.props.onErrorCountChange(this.props.name, this.numErrors(errors));
113 | }
114 | if (this.props.onMissingCountChange) {
115 | this.props.onMissingCountChange(this.props.name, this.numMissing(missing));
116 | }
117 |
118 | this.setState({ selected: this.props.value.size });
119 | }
120 |
121 | //Determine the total count of missing fields in the entire list
122 | numMissing(missing) {
123 | let total = 0;
124 | _.each(missing, c => {
125 | total += c;
126 | });
127 | return total;
128 | }
129 |
130 | //Determine the total count of error fields in the entire list
131 | numErrors(errors) {
132 | let total = 0;
133 | _.each(errors, c => {
134 | total += c;
135 | });
136 | return total;
137 | }
138 |
139 | componentWillReceiveProps(nextProps) {
140 | if (nextProps.edit === false) {
141 | this.setState({ selected: null });
142 | }
143 | }
144 |
145 | render() {
146 | const itemComponents = [];
147 | this.props.value.forEach((item, index) => {
148 | const { key = index } = item;
149 | const props = {
150 | key,
151 | name: index,
152 | edit: this.props.edit,
153 | innerForm: true,
154 | hideMinus: hideEditRemove && index < this.props.value.size - 1,
155 | types: this.props.types,
156 | options: this.props.options,
157 | actions: this.props.actions,
158 | onErrorCountChange: (name, errorCount) =>
159 | this.handleErrorCountChange(name, errorCount),
160 | onMissingCountChange: (name, missingCount) =>
161 | this.handleMissingCountChange(name, missingCount),
162 | onChange: (name, value) => {
163 | this.handleChangeItem(name, value);
164 | }
165 | };
166 | itemComponents.push(
167 |
173 | );
174 | });
175 |
176 | const errors = _.find(this.state.errors, item => {
177 | return item >= 1;
178 | });
179 | const missing = _.find(this.state.missing, item => {
180 | return item >= 1;
181 | });
182 |
183 | const plusElement = (errors || missing) && hideEditRemove ?
: null;
184 | const { canAddItems = true, canRemoveItems = true } = this.props;
185 |
186 | return (
187 | this.handleAddItem()}
196 | onRemoveItem={index => this.handleRemovedItem(index)}
197 | onSelectItem={index => this.handleSelectItem(index)}
198 | />
199 | );
200 | }
201 | };
202 | }
203 |
--------------------------------------------------------------------------------
/packages/react-dynamic-forms/tests/ChooserTests.js:
--------------------------------------------------------------------------------
1 | /**
2 | * Copyright (c) 2017, The Regents of the University of California,
3 | * through Lawrence Berkeley National Laboratory (subject to receipt
4 | * of any required approvals from the U.S. Dept. of Energy).
5 | * All rights reserved.
6 | *
7 | * This source code is licensed under the BSD-style license found in the
8 | * LICENSE file in the root directory of this source tree.
9 | */
10 |
11 | import React from "react";
12 | import {
13 | ChooserBasic,
14 | ChooserWider,
15 | ChooserSortedList,
16 | ChooserInitialValue,
17 | ChooserInitialNull,
18 | ChooserSortedInitial,
19 | ChooserDisabled,
20 | ChooserSearchDisabled,
21 | ChooserSingleDeselect,
22 | ChooserLongList
23 | } from "./components_test/ChooserExamples";
24 |
25 | export default React.createClass({
26 | render() {
27 | return (
28 |
29 |
30 |
31 |
Chooser Tests
32 | Chooser with simple list
33 |
34 | Wider chooser
35 |
36 | Chooser with a sorted list
37 |
38 | Chooser with initial value
39 |
40 | Chooser with a null initial value
41 |
42 | Chooser with sorted list and initial value
43 |
44 | Disabled chooser
45 |
46 | Chooser with no search
47 |
48 | Chooser allowing clearing single selection
49 |
50 | Chooser with a very long list
51 |
52 |
53 |
54 |
55 | );
56 | }
57 | });
58 |
--------------------------------------------------------------------------------
/packages/react-dynamic-forms/tests/TextEditTests.js:
--------------------------------------------------------------------------------
1 | /**
2 | * Copyright (c) 2017, The Regents of the University of California,
3 | * through Lawrence Berkeley National Laboratory (subject to receipt
4 | * of any required approvals from the U.S. Dept. of Energy).
5 | * All rights reserved.
6 | *
7 | * This source code is licensed under the BSD-style license found in the
8 | * LICENSE file in the root directory of this source tree.
9 | */
10 |
11 | import React from "react";
12 | import {
13 | TestBasic // TextEditDisabled, // TextEditPlaceholder,
14 | } from // TextEditPassword,
15 | // TextEditRequired1,
16 | // TextEditRequired2,
17 | // TextEditRequired3,
18 | // TextEditValidate,
19 | // TextEditValidateInt
20 | "./components_test/TextEditExamples";
21 |
22 | export default React.createClass({
23 | render() {
24 | return (
25 |
26 |
27 |
28 |
TextEdit Tests
29 | TextEdit initial value
30 |
31 | {/*}
32 | Diabled TextEdit
33 |
34 | With a placeholder
35 |
36 | Password type
37 |
38 | Required field (with showRequired turned ON):
39 |
40 | Required field (with showRequired turned OFF):
41 |
42 | Required field (with showRequired turned ON and initial value):
43 |
44 | Validated field (email address)
45 |
46 | Validated field (integer)
47 | */}
48 |
49 |
50 |
51 | );
52 | }
53 | });
54 |
--------------------------------------------------------------------------------
/packages/react-dynamic-forms/tests/__snapshots__/textedit.test.js.snap:
--------------------------------------------------------------------------------
1 | exports[`test Required field (with showRequired turned ON and initial value 1`] = `
2 |
23 | `;
24 |
25 | exports[`test TextEdit email address validate 1`] = `
26 |
28 |
40 |
42 | Value is not a valid email
43 |
44 |
45 | `;
46 |
47 | exports[`test TextEdit email address validate 2`] = `
48 |
65 | `;
66 |
67 | exports[`test TextEdit isRequired snapshot test 1`] = `
68 |
85 | `;
86 |
87 | exports[`test TextEdit isRequired snapshot test 2`] = `
88 |
105 | `;
106 |
107 | exports[`test TextEdit that is disabled 1`] = `
108 |
110 |
124 |
126 |
127 |
128 |
129 | `;
130 |
131 | exports[`test TextEdit with a placeholder 1`] = `
132 |
134 |
148 |
150 |
151 |
152 |
153 | `;
154 |
155 | exports[`test TextEdit with an initial value and width 1`] = `
156 |
158 |
172 |
174 |
175 |
176 |
177 | `;
178 |
179 | exports[`test TextEdit with required field (with showRequired turned OFF) 1`] = `
180 |
182 |
196 |
198 |
199 |
200 |
201 | `;
202 |
203 | exports[`test TextEdit with required field (with showRequired turned ON) 1`] = `
204 |
206 |
220 |
222 |
223 |
224 |
225 | `;
226 |
227 | exports[`test Validated field (email address) 1`] = `
228 |
230 |
244 |
246 | Value is not a valid email
247 |
248 |
249 | `;
250 |
251 | exports[`test Validated field (integer) 1`] = `
252 |
254 |
268 |
270 |
271 |
272 |
273 | `;
274 |
--------------------------------------------------------------------------------
/packages/react-dynamic-forms/tests/components_test/ChooserExamples.js:
--------------------------------------------------------------------------------
1 | /**
2 | * Copyright (c) 2017 - present, The Regents of the University of California,
3 | * through Lawrence Berkeley National Laboratory (subject to receipt
4 | * of any required approvals from the U.S. Dept. of Energy).
5 | * All rights reserved.
6 | *
7 | * This source code is licensed under the BSD-style license found in the
8 | * LICENSE file in the root directory of this source tree.
9 | */
10 |
11 | import Chooser from "../../src/components/Chooser";
12 | import React from "react";
13 | import _ from "underscore";
14 | import Chance from "chance";
15 |
16 | const chance = Chance.Chance();
17 |
18 | const animals = {
19 | 1: "dog",
20 | 2: "duck",
21 | 3: "cat",
22 | 4: "donkey",
23 | 5: "fish",
24 | 6: "hedgehog",
25 | 7: "banana slug"
26 | };
27 | const animalList = _.map(animals, (value, key) => ({ id: key, label: value }));
28 | const sortedAnimalList = _.sortBy(animalList, item => item.label);
29 |
30 | let locationList = [
31 | { id: 12, label: "Spain" },
32 | { id: 14, label: "Portugal" },
33 | { id: 16, label: "Italy" },
34 | { id: 78, label: "France" },
35 | { id: 99, label: "Germany" },
36 | { id: 104, label: "Norway" },
37 | { id: 112, label: "Denmark" },
38 | { id: 154, label: "Greece" },
39 | { id: 206, label: "Holland" }
40 | ];
41 |
42 | let largeList = [];
43 | for (let i = 1; i < 5000; i++) {
44 | largeList.push({ id: `${i}`, label: chance.word() });
45 | }
46 |
47 | export class ChooserBasic extends React.Component {
48 | constructor(props) {
49 | super(props);
50 | this.state = {
51 | animalList
52 | };
53 | }
54 |
55 | render() {
56 | return (
57 |
62 | );
63 | }
64 | };
65 |
66 | export class ChooserWider extends React.Component {
67 | constructor(props) {
68 | super(props);
69 | this.state = {
70 | animalList
71 | };
72 | }
73 |
74 | render() {
75 | return ;
76 | }
77 | };
78 |
79 | export class ChooserSortedList extends React.Component {
80 | constructor(props) {
81 | super(props);
82 | this.state = {
83 | sortedAnimalList
84 | };
85 | }
86 |
87 | render() {
88 | return ;
89 | }
90 | };
91 |
92 | export class ChooserInitialValue extends React.Component {
93 | constructor(props) {
94 | super(props);
95 | this.state = {
96 | animalList
97 | };
98 | }
99 |
100 | render() {
101 | return ;
102 | }
103 | };
104 |
105 | export class ChooserInitialNull extends React.Component {
106 | constructor(props) {
107 | super(props);
108 | this.state = {
109 | animalList
110 | };
111 | }
112 |
113 | render() {
114 | return (
115 |
116 | );
117 | }
118 | };
119 |
120 | export class ChooserSortedInitial extends React.Component {
121 | constructor(props) {
122 | super(props);
123 | this.state = {
124 | sortedAnimalList
125 | };
126 | }
127 |
128 | render() {
129 | return (
130 |
135 | );
136 | }
137 | };
138 |
139 | export class ChooserDisabled extends React.Component {
140 | constructor(props) {
141 | super(props);
142 | this.state = {
143 | animalList
144 | };
145 | }
146 |
147 | render() {
148 | return (
149 |
155 | );
156 | }
157 | };
158 |
159 | export class ChooserItemDisabled extends React.Component {
160 | constructor(props) {
161 | super(props);
162 | this.state = {
163 | animalList
164 | };
165 | }
166 |
167 | render() {
168 | return (
169 |
176 | );
177 | }
178 | };
179 |
180 | export class ChooserSearchDisabled extends React.Component {
181 | constructor(props) {
182 | super(props);
183 | this.state = {
184 | animalList
185 | };
186 | }
187 |
188 | render() {
189 | return (
190 |
196 | );
197 | }
198 | };
199 |
200 | export class ChooserSingleDeselect extends React.Component {
201 | constructor(props) {
202 | super(props);
203 | this.state = {
204 | animalList
205 | };
206 | }
207 |
208 | render() {
209 | return (
210 |
217 | );
218 | }
219 | };
220 |
221 | export class ChooserLongList extends React.Component {
222 | constructor(props) {
223 | super(props);
224 | this.state = {
225 | locationList
226 | };
227 | }
228 |
229 | render() {
230 | return ;
231 | }
232 | };
--------------------------------------------------------------------------------
/packages/react-dynamic-forms/tests/components_test/TextEditExamples.js:
--------------------------------------------------------------------------------
1 | /**
2 | * Copyright (c) 2017 - present, The Regents of the University of California,
3 | * through Lawrence Berkeley National Laboratory (subject to receipt
4 | * of any required approvals from the U.S. Dept. of Energy).
5 | * All rights reserved.
6 | *
7 | * This source code is licensed under the BSD-style license found in the
8 | * LICENSE file in the root directory of this source tree.
9 | */
10 |
11 | import React from "react";
12 | import TextEdit from "../../src/components/TextEdit";
13 |
14 | export class TestBasic extends React.Component {
15 | render() {
16 | const attr = {
17 | name: "Basic"
18 | };
19 | return ;
20 | }
21 | };
--------------------------------------------------------------------------------
/packages/react-dynamic-forms/tests/textedit.test.js:
--------------------------------------------------------------------------------
1 | /**
2 | * Copyright (c) 2017 - present, The Regents of the University of California,
3 | * through Lawrence Berkeley National Laboratory (subject to receipt
4 | * of any required approvals from the U.S. Dept. of Energy).
5 | * All rights reserved.
6 | *
7 | * This source code is licensed under the BSD-style license found in the
8 | * LICENSE file in the root directory of this source tree.
9 | */
10 |
11 | import renderer from "react-test-renderer";
12 | import React from "react";
13 | import { shallow, mount } from "enzyme";
14 | import toJson from "enzyme-to-json";
15 |
16 | import {
17 | TestBasic,
18 | TextEditDisabled,
19 | TextEditPlaceholder,
20 | TextEditRequired1,
21 | TextEditRequired2,
22 | TextEditRequired3,
23 | TextEditValidate,
24 | TextEditValidateInt
25 | } from "./components_test/TextEditExamples";
26 |
27 | import TextEdit from "../src/components/TextEdit";
28 |
29 | //
30 | // Visual appearance snapshot tests
31 | //
32 | test("TextEdit with an initial value and width", () => {
33 | const tree = renderer.create( ).toJSON();
34 | expect(tree).toMatchSnapshot();
35 | });
36 |
37 | test("TextEdit that is disabled", () => {
38 | const tree = renderer.create( ).toJSON();
39 | expect(tree).toMatchSnapshot();
40 | });
41 |
42 | test("TextEdit with a placeholder", () => {
43 | const tree = renderer.create( ).toJSON();
44 | expect(tree).toMatchSnapshot();
45 | });
46 |
47 | test("TextEdit with required field (with showRequired turned ON)", () => {
48 | const tree = renderer.create( ).toJSON();
49 | expect(tree).toMatchSnapshot();
50 | });
51 |
52 | test("TextEdit with required field (with showRequired turned OFF)", () => {
53 | const tree = renderer.create( ).toJSON();
54 | expect(tree).toMatchSnapshot();
55 | });
56 |
57 | test("Required field (with showRequired turned ON and initial value", () => {
58 | const tree = renderer.create( ).toJSON();
59 | expect(tree).toMatchSnapshot();
60 | });
61 |
62 | test("Validated field (email address)", () => {
63 | const tree = renderer.create( ).toJSON();
64 | expect(tree).toMatchSnapshot();
65 | });
66 |
67 | test("Validated field (integer)", () => {
68 | const tree = renderer.create( ).toJSON();
69 | expect(tree).toMatchSnapshot();
70 | });
71 |
72 | //
73 | // Test callbacks
74 | //
75 | test("TextEdit onChange callback", () => {
76 | const handleChange = jest.fn();
77 |
78 | const wrapper = mount(
79 |
80 | );
81 |
82 | // Simulate user typing
83 | const input = wrapper.find("input");
84 | input.node.value = "fred";
85 | input.simulate("blur");
86 |
87 | // Get the result of the handleChange callback
88 | const [attr, value] = handleChange.mock.calls[0];
89 | expect(handleChange).toHaveBeenCalled();
90 | expect(attr).toBe("mytextedit");
91 | expect(value).toBe("fred");
92 | });
93 |
94 | test("TextEdit isRequired callback", () => {
95 | const handleMissingCountChange = jest.fn();
96 |
97 | const wrapper = mount(
98 |
104 | );
105 |
106 | // The TextEdit will evoke onMissingCountChange initially to report
107 | // up initial missing value counts, so handleMissingCountChange
108 | // should have been called once at this point, and since we provided
109 | // an initialValue the missing count should be 0
110 | const [attr, missingBefore] = handleMissingCountChange.mock.calls[0];
111 | expect(handleMissingCountChange.mock.calls.length).toBe(1);
112 | expect(attr).toBe("mytextedit");
113 | expect(missingBefore).toBe(0);
114 |
115 | // Simulate the user clearing the input field
116 | const input = wrapper.find("input");
117 | input.node.value = "";
118 | input.simulate("blur");
119 |
120 | // Get the result of the handleChange callback
121 | expect(handleMissingCountChange.mock.calls.length).toBe(2);
122 | const [_, missingAfter] = handleMissingCountChange.mock.calls[1];
123 | expect(missingAfter).toBe(1);
124 | });
125 |
126 | test("TextEdit isRequired snapshot test", () => {
127 | const handleMissingCountChange = jest.fn();
128 |
129 | const wrapper = mount(
130 |
137 | );
138 | const input = wrapper.find("input");
139 | const div = wrapper.find("div");
140 |
141 | // Get an initial snapshot of the TextEdit
142 | expect(toJson(div)).toMatchSnapshot();
143 |
144 | // Check if it shows an error (it shouldn't yet)
145 | expect(div.node.className).toBe("");
146 |
147 | // Simulate the user clearing the input field
148 | input.node.value = "";
149 | input.simulate("blur");
150 |
151 | // Check if it shows an error now
152 | expect(div.node.className).toBe("has-error");
153 |
154 | // Get an after snapshot of the TextEdit
155 | expect(toJson(div)).toMatchSnapshot();
156 | });
157 |
158 | test("TextEdit email address validate", () => {
159 | const handleErrorCountChange = jest.fn();
160 |
161 | const wrapper = mount(
162 |
167 | );
168 | const input = wrapper.find("input");
169 | const div = wrapper.find("div");
170 |
171 | const helptext = div.find(".has-error");
172 | expect(helptext.node.textContent).toEqual("Value is not a valid email");
173 |
174 | // Get an initial snapshot of the TextEdit
175 | expect(toJson(div)).toMatchSnapshot();
176 |
177 | // Check if it shows an error (it should because it starts with an invalid email)
178 | expect(div.node.className).toBe("has-error");
179 |
180 | // Get the result of the initial call to the error count callback
181 | expect(handleErrorCountChange.mock.calls.length).toBe(1);
182 | const [, errorBefore] = handleErrorCountChange.mock.calls[0];
183 | expect(errorBefore).toBe(1);
184 |
185 | // Simulate the user clearing the input field
186 | input.node.value = "bob@gmail.com";
187 | input.simulate("blur");
188 |
189 | // Check if it shows an error now
190 | expect(div.node.className).toBe("");
191 |
192 | // Get an after snapshot of the TextEdit
193 | expect(toJson(div)).toMatchSnapshot();
194 |
195 | // Get the result of the error change callback
196 | expect(handleErrorCountChange.mock.calls.length).toBe(2);
197 | const [, errorAfter] = handleErrorCountChange.mock.calls[1];
198 | expect(errorAfter).toBe(0);
199 | });
200 |
--------------------------------------------------------------------------------
/packages/website/.gitignore:
--------------------------------------------------------------------------------
1 | # See https://help.github.com/ignore-files/ for more about ignoring files.
2 |
3 | # dependencies
4 | /node_modules
5 |
6 | # testing
7 | /coverage
8 |
9 | # production
10 | /build
11 |
12 | # misc
13 | .DS_Store
14 | .env.local
15 | .env.development.local
16 | .env.test.local
17 | .env.production.local
18 |
19 | npm-debug.log*
20 | yarn-debug.log*
21 | yarn-error.log*
22 |
--------------------------------------------------------------------------------
/packages/website/README.md:
--------------------------------------------------------------------------------
1 |
2 |
--------------------------------------------------------------------------------
/packages/website/forms.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/esnet/react-dynamic-forms/0f24c808fa1cadb3df6b1635cde377a0959acdd6/packages/website/forms.png
--------------------------------------------------------------------------------
/packages/website/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "website",
3 | "version": "1.0.3",
4 | "homepage": "http://software.es.net/react-dynamic-forms",
5 | "private": true,
6 | "dependencies": {
7 | "bootstrap": "^3.3.7",
8 | "chance": "^1.0.6",
9 | "flexbox-react": "^4.4.0",
10 | "immutable": "^3.8.2",
11 | "lodash": "^4.17.5",
12 | "prismjs": "^1.12.0",
13 | "react": "^16.2.0",
14 | "react-bootstrap": "^0.32.1",
15 | "react-dom": "^16.2.0",
16 | "react-dynamic-forms": "^1.0.3",
17 | "react-markdown": "^3.1.4",
18 | "react-overlays": "^0.8.3",
19 | "react-router-dom": "^4.2.2",
20 | "react-scripts": "1.1.1",
21 | "underscore": "^1.8.3"
22 | },
23 | "scripts": {
24 | "start": "react-scripts start",
25 | "build": "react-scripts build",
26 | "test": "react-scripts test --env=jsdom",
27 | "eject": "react-scripts eject"
28 | }
29 | }
30 |
--------------------------------------------------------------------------------
/packages/website/public/favicon.ico:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/esnet/react-dynamic-forms/0f24c808fa1cadb3df6b1635cde377a0959acdd6/packages/website/public/favicon.ico
--------------------------------------------------------------------------------
/packages/website/public/index.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 | React Dynamic Forms
16 |
17 |
18 |
19 |
20 |
29 |
30 |
31 |
32 |
33 |
34 | You need to enable JavaScript to run this app.
35 |
36 |
37 |
38 |
39 |
40 |
41 |
42 |
43 |
44 |
45 |
--------------------------------------------------------------------------------
/packages/website/public/manifest.json:
--------------------------------------------------------------------------------
1 | {
2 | "short_name": "React App",
3 | "name": "Create React App Sample",
4 | "icons": [
5 | {
6 | "src": "favicon.ico",
7 | "sizes": "64x64 32x32 24x24 16x16",
8 | "type": "image/x-icon"
9 | }
10 | ],
11 | "start_url": "./index.html",
12 | "display": "standalone",
13 | "theme_color": "#000000",
14 | "background_color": "#ffffff"
15 | }
16 |
--------------------------------------------------------------------------------
/packages/website/src/App.css:
--------------------------------------------------------------------------------
1 | /**
2 | * Copyright (c) 2017, The Regents of the University of California,
3 | * through Lawrence Berkeley National Laboratory (subject to receipt
4 | * of any required approvals from the U.S. Dept. of Energy).
5 | * All rights reserved.
6 | *
7 | * This source code is licensed under the BSD-style license found in the
8 | * LICENSE file in the root directory of this source tree.
9 | */
10 |
11 | body {
12 | padding: 0;
13 | margin: 0;
14 | overflow: hidden;
15 | }
16 |
17 | h2 {
18 | font-size: 27px;
19 | font-weight: 400;
20 | color: #333;
21 | }
22 |
23 | h4 {
24 | padding-top: 20px;
25 | }
26 |
27 | /* react-select dropdown conflicts with Bootstrap controls */
28 |
29 | .list-group-item.active,
30 | .list-group-item.active:focus,
31 | .list-group-item.active:hover {
32 | z-index: 0;
33 | }
34 |
35 | /* Hamburger sidebar expander */
36 |
37 | .sidebar-icon {
38 | font-size: 25px;
39 | margin-right: 45px;
40 | color: #a4a4a4;
41 | }
42 |
43 | .sidebar-icon:hover,
44 | .sidebar-icon.active {
45 | color: #4ec1e0;
46 | }
47 |
48 | .sidebar-link {
49 | display: block;
50 | font-weight: 500;
51 | font-family: "Open Sans Condensed", sans-serif;
52 | font-size: 14px;
53 | padding: 5px 0px;
54 | color: #757575;
55 | text-decoration: none;
56 | cursor: pointer;
57 | }
58 |
59 | .sidebar-link:hover {
60 | color: #4ec1e0;
61 | text-decoration: none;
62 | cursor: hand;
63 | }
64 |
65 | .sidebar-link.active {
66 | color: #4ec1e0;
67 | font-weight: 700;
68 | text-decoration: none;
69 | }
70 |
71 | /* Header customization */
72 |
73 | .navbar {
74 | height: 80px;
75 | background: -webkit-gradient(
76 | linear,
77 | left top,
78 | left bottom,
79 | color-stop(0, #fafafa),
80 | color-stop(1, #f5f5f5)
81 | );
82 | background: linear-gradient(to bottom, #fafafa, #f5f5f5);
83 | border-bottom: 1px solid #eee;
84 | border-top: 1px solid #eee;
85 | }
86 |
87 | .navbar-brand {
88 | font-family: "Open Sans", sans-serif;
89 | font-weight: 700;
90 | font-size: 32px;
91 | color: #6d6e71;
92 | }
93 |
94 | /* ESnet fasterdata and ESnet main site links */
95 |
96 | .tools-links > li:first-child a {
97 | border-left: 0;
98 | }
99 |
100 | .tools-links > li > a {
101 | text-align: left;
102 | font-size: 14px;
103 | margin-top: 20px;
104 | padding: 8px 10px;
105 | background-color: #6d6e71;
106 | border-left: 1px solid #fff;
107 | color: #fff;
108 | width: 119px;
109 | height: 34px;
110 | display: block;
111 | }
112 |
113 | .tools-links {
114 | margin-right: 10px !important;
115 | list-style-type: none;
116 | padding: 0;
117 | margin: 0;
118 | font-family: "Open Sans", sans-serif;
119 | font-weight: 700;
120 | text-align: right;
121 | font-size: 0;
122 | }
123 |
124 | .tools-links > li a.selected,
125 | .tools-links > li a:hover {
126 | background-color: #4ec1e0 !important;
127 | }
128 |
129 | /* Navigation pills altered to look like the links above */
130 |
131 | .nav-pills > li.active > a,
132 | .nav-pills > li.active > a:focus,
133 | .nav-pills > li.active > a:hover {
134 | background-color: #8c8d93 !important;
135 | }
136 |
137 | .nav-pills > li > a {
138 | border-radius: 0px !important;
139 | }
140 |
141 | .nav > li > a {
142 | padding: 7px 15px;
143 | }
144 |
145 | /* Hide the footer on small screens */
146 | @media (max-width: 600px) {
147 | .footer {
148 | display: none;
149 | }
150 | }
151 |
152 | .scrollable::-webkit-scrollbar {
153 | display: none;
154 | }
155 |
--------------------------------------------------------------------------------
/packages/website/src/App.js:
--------------------------------------------------------------------------------
1 | /**
2 | * Copyright (c) 2017, The Regents of the University of California,
3 | * through Lawrence Berkeley National Laboratory (subject to receipt
4 | * of any required approvals from the U.S. Dept. of Energy).
5 | * All rights reserved.
6 | *
7 | * This source code is licensed under the BSD-style license found in the
8 | * LICENSE file in the root directory of this source tree.
9 | */
10 |
11 | import "./App.css";
12 | import React, { Component } from "react";
13 | import { HashRouter as Router, Route, Switch } from "react-router-dom";
14 |
15 | import Prism from "prismjs"; // eslint-disable-line
16 | import "prismjs/components/prism-typescript";
17 | import "prismjs/themes/prism.css";
18 |
19 | import Header from "./Header";
20 | import Sidebar from "./Sidebar";
21 | import Guide from "./components/Guide";
22 | import Example from "./components/Example";
23 | import API from "./components/API";
24 |
25 | import { bodyStyle, mainStyle, contentStyle } from "./styles";
26 |
27 | class Page extends Component {
28 | render() {
29 | return (
30 |
31 |
32 | {" "}
33 |
34 |
35 |
36 |
37 |
38 |
39 |
40 |
41 |
42 | );
43 | }
44 | }
45 |
46 | class App extends Component {
47 | render() {
48 | return (
49 |
50 |
54 |
55 | );
56 | }
57 | }
58 |
59 | export default App;
60 |
--------------------------------------------------------------------------------
/packages/website/src/Header.js:
--------------------------------------------------------------------------------
1 | /**
2 | * Copyright (c) 2017, The Regents of the University of California,
3 | * through Lawrence Berkeley National Laboratory (subject to receipt
4 | * of any required approvals from the U.S. Dept. of Energy).
5 | * All rights reserved.
6 | *
7 | * This source code is licensed under the BSD-style license found in the
8 | * LICENSE file in the root directory of this source tree.
9 | */
10 |
11 | import React, { Component } from "react";
12 | import logo from "./img/forms.png";
13 | import githubLogo from "./img/github.png";
14 |
15 | /* eslint-disable jsx-a11y/href-no-hash */
16 |
17 | export default class Header extends Component {
18 | render() {
19 | const githubLogoStyle = {
20 | width: 24,
21 | paddingRight: 5,
22 | marginTop: -4
23 | };
24 | return (
25 |
26 |
27 |
28 |
29 |
30 |
31 |
37 |
38 |
39 |
40 | React Dynamic Forms
41 |
42 |
43 |
44 |
64 |
65 |
66 | );
67 | }
68 | }
69 |
--------------------------------------------------------------------------------
/packages/website/src/Sidebar.js:
--------------------------------------------------------------------------------
1 | /**
2 | * Copyright (c) 2017, The Regents of the University of California,
3 | * through Lawrence Berkeley National Laboratory (subject to receipt
4 | * of any required approvals from the U.S. Dept. of Energy).
5 | * All rights reserved.
6 | *
7 | * This source code is licensed under the BSD-style license found in the
8 | * LICENSE file in the root directory of this source tree.
9 | */
10 |
11 | import React, { Component } from "react";
12 | import { Link } from "react-router-dom";
13 | import { sidebarStyle, sidebarItemStyle, sidebarTitleStyle } from "./styles";
14 | import { AutoAffix } from "react-overlays";
15 |
16 | export default class extends Component {
17 | render() {
18 | return (
19 |
20 |
21 | GUIDE
22 |
23 |
24 |
25 | Introduction
26 |
27 |
28 | Getting Started
29 |
30 |
31 |
32 |
33 | Examples
34 |
35 |
36 |
37 | Basic form
38 |
39 |
40 | Dynamic form
41 |
42 |
43 | List example
44 |
45 |
46 | Schema example
47 |
48 |
49 |
50 |
51 | API
52 |
53 |
54 |
55 | CheckBoxes
56 |
57 |
58 | Chooser
59 |
60 |
61 | DateEdit
62 |
63 |
64 | Field
65 |
66 |
67 | Form
68 |
69 |
70 | List
71 |
72 |
73 | RadioButtons
74 |
75 |
76 | Schema
77 |
78 |
79 | TagsEdit
80 |
81 |
82 | TextArea
83 |
84 |
85 | TextEdit
86 |
87 |
88 | View
89 |
90 |
91 |
92 |
93 | Links
94 |
95 |
106 |
107 |
108 | Related Projects
109 |
110 |
120 |
121 | );
122 | }
123 | }
124 |
--------------------------------------------------------------------------------
/packages/website/src/components/API.js:
--------------------------------------------------------------------------------
1 | /**
2 | * Copyright (c) 2015-present, The Regents of the University of California,
3 | * through Lawrence Berkeley National Laboratory (subject to receipt
4 | * of any required approvals from the U.S. Dept. of Energy).
5 | * All rights reserved.
6 | *
7 | * This source code is licensed under the BSD-style license found in the
8 | * LICENSE file in the root directory of this source tree.
9 | */
10 |
11 | /* eslint max-len:0 */
12 |
13 | import React, {Component} from "react";
14 | import { Link } from "react-router-dom";
15 | import _ from "underscore";
16 | import Flexbox from "flexbox-react";
17 |
18 | import Prism from "prismjs";
19 | import APIDoc from "./APIDoc";
20 |
21 | import Meta from "../examples/examples.json";
22 | import Examples from "../examples/examples.js";
23 | import docsFile from "../api/docs.json";
24 |
25 | import { headingStyle } from "../styles";
26 |
27 | class Example extends Component {
28 | render() {
29 | const style = {
30 | display: "inline-block",
31 | margin: 5,
32 | padding: 20,
33 | borderStyle: "solid",
34 | borderWidth: 1,
35 | borderColor: "#DDD",
36 | width: 160,
37 | height: 160
38 | };
39 | const { example } = this.props;
40 | const name = example.key;
41 | const imgName = `${name}_thumbnail`;
42 | const img = Examples[imgName];
43 | const link = {example.value.title};
44 | return (
45 |
46 |
47 |
48 |
49 |
50 | {link}
51 |
52 |
53 | );
54 | }
55 | };
56 |
57 | class TaggedExamples extends Component {
58 | render() {
59 | const exampleList = [];
60 | _.forEach(Meta, (value, key) => {
61 | const tags = value.tags;
62 | if (_.contains(tags, this.props.tag)) {
63 | exampleList.push({ key, value });
64 | }
65 | });
66 | const examples = exampleList.map((example, i) => {
67 | return ;
68 | });
69 |
70 | if (examples.length > 0) {
71 | return (
72 |
73 |
Examples
74 |
75 | {examples}
76 |
77 |
78 | );
79 | } else {
80 | return
;
81 | }
82 | }
83 | };
84 |
85 | export default class extends Component {
86 | componentDidMount() {
87 | Prism.highlightAll();
88 | }
89 |
90 | componentDidUpdate() {
91 | Prism.highlightAll();
92 | }
93 |
94 | render() {
95 | const component = this.props.match.params.component;
96 | const path = `src/components/${component}.js`;
97 |
98 | if (!_.has(docsFile, path)) {
99 | return API could not be found
;
100 | }
101 | const title = component;
102 | return (
103 |
104 |
105 |
106 |
{`${title}`}
107 |
108 |
109 |
110 |
111 |
112 | );
113 | }
114 | }
115 |
116 |
--------------------------------------------------------------------------------
/packages/website/src/components/APIDoc.js:
--------------------------------------------------------------------------------
1 | import React, {Component} from "react";
2 | import _ from "underscore";
3 | import Markdown from "react-markdown";
4 | import docsFile from "../api/docs.json";
5 | import Prism from "prismjs";
6 | import { codeRenderer, codeBlockRenderer } from "../renderers";
7 | import { textStyle } from "../styles";
8 |
9 | /**
10 | * Displays API data from the docs.json file
11 | */
12 | export default class extends Component {
13 | componentDidMount() {
14 | Prism.highlightAll();
15 | }
16 |
17 | componentDidUpdate() {
18 | Prism.highlightAll();
19 | }
20 |
21 | renderArrayOf(value) {
22 | if (value.name === "shape") {
23 | return "shape {" +
24 | _.map(value.value, (value, key) => {
25 | return key;
26 | }).join(", ") +
27 | "}";
28 | } else {
29 | return `array of ${value.name}s`;
30 | }
31 | }
32 |
33 | renderPropType(type) {
34 | if (!type) {
35 | return "unknown type";
36 | }
37 | if (type.name === "enum") {
38 | return "enum (" +
39 | _.map(type.value, value => {
40 | return value.value;
41 | }).join(", ") +
42 | ")";
43 | }
44 | if (type.name === "union") {
45 | return "one of (" +
46 | _.map(type.value, value => {
47 | return this.renderPropType(value);
48 | }).join(", ") +
49 | ")";
50 | }
51 | if (type.name === "instanceOf") {
52 | return `instance of a ${type.value}`;
53 | }
54 | if (type.name === "arrayOf") {
55 | return `array of ${this.renderArrayOf(type.value)}`;
56 | }
57 | if (type.name === "shapes") {
58 | return `shape of {` +
59 | _.map(type.value, (value, key) => {
60 | return key;
61 | }).join(", ") +
62 | "}";
63 | } else {
64 | return `${type.name}`;
65 | }
66 | }
67 |
68 | renderProps(props) {
69 | const propNameStyle = {
70 | padding: 3,
71 | marginRight: 5,
72 | borderRadius: 2,
73 | fontFamily: "'Fira Mono',Menlo,monospace",
74 | color: "#c7254e",
75 | background: "#f9f2f4",
76 | letterSpacing: -0.015
77 | };
78 |
79 | const infoStyle = {
80 | color: "#626466",
81 | fontFamily: "Fira Sans,Helvetica Neue,Helvetica,Arial,sans-serif",
82 | fontSize: 16,
83 | lineHeight: 1.625
84 | };
85 |
86 | const typeStyle = {
87 | color: "#626466",
88 | background: "#F5F4F4",
89 | fontFamily: "Fira Sans,Helvetica Neue,Helvetica,Arial,sans-serif",
90 | fontSize: 16,
91 | lineHeight: 1.625
92 | };
93 |
94 | return _.map(props, (prop, propName) => (
95 |
96 |
97 | {propName}
98 |
99 |
100 | {prop.defaultValue ? ` = ${prop.defaultValue.value}` : ""}
101 |
102 |
103 | {prop.required ? "Required" : ""}
104 |
105 |
106 |
110 |
111 |
112 | Type: {this.renderPropType(prop.type)}
113 |
114 |
115 |
116 | ));
117 | }
118 |
119 | /**
120 | * If we add back in auto props, add this to the JSX below:
121 | * {docs.props ? this.renderProps(docs.props) : ""}
122 | */
123 | render() {
124 | const file = this.props.file;
125 | const docs = docsFile[file];
126 | return (
127 |
128 |
API
129 |
133 |
134 | Props
135 |
136 | {docs.props ? this.renderProps(docs.props) : "none"}
137 |
138 | );
139 | }
140 | };
141 |
--------------------------------------------------------------------------------
/packages/website/src/components/Example.js:
--------------------------------------------------------------------------------
1 | /**
2 | * Copyright (c) 2016-present, The Regents of the University of California,
3 | * through Lawrence Berkeley National Laboratory (subject to receipt
4 | * of any required approvals from the U.S. Dept. of Energy).
5 | * All rights reserved.
6 | *
7 | * This source code is licensed under the BSD-style license found in the
8 | * LICENSE file in the root directory of this source tree.
9 | */
10 |
11 | import React, {Component} from "react";
12 | import Markdown from "react-markdown";
13 |
14 | import Examples from "../examples/examples.js";
15 | // import Meta from "../examples/examples.json";
16 |
17 | import Prism from "prismjs";
18 | import { codeRenderer, codeBlockRenderer } from "../renderers";
19 |
20 | export default class extends Component {
21 | constructor(props) {
22 | super(props);
23 | this.state = {
24 | markdown: null
25 | };
26 | }
27 |
28 | fetchMarkdownForProps(props) {
29 | window.scrollTo(0, 0);
30 | const exampleName = props.match.params.example;
31 | const markdownFile = Examples[`${exampleName}_docs`];
32 | fetch(markdownFile)
33 | .then(response => {
34 | return response.text();
35 | })
36 | .then(markdown => {
37 | this.setState({ markdown });
38 | });
39 | }
40 |
41 | componentDidMount() {
42 | Prism.highlightAll();
43 | this.fetchMarkdownForProps(this.props);
44 | }
45 |
46 | componentWillReceiveProps(nextProps) {
47 | this.fetchMarkdownForProps(nextProps);
48 | }
49 |
50 | componentDidUpdate() {
51 | Prism.highlightAll();
52 | }
53 |
54 | renderMarkdown() {
55 | if (this.state.markdown) {
56 | return (
57 |
65 | );
66 | } else {
67 | return (
68 |
69 |
70 | Loading...
71 |
72 |
73 | );
74 | }
75 | }
76 |
77 | render() {
78 | /* const tagStyle = {
79 | background: "#EEE",
80 | padding: 5,
81 | borderRadius: 2,
82 | margin: 2,
83 | fontSize: "smaller"
84 | }; */
85 |
86 | const exampleName = this.props.match.params.example;
87 | // const ExampleMetaData = Meta[exampleName];
88 | const Component = Examples[exampleName];
89 | // const Link = Meta[exampleName].link;
90 | // const sourceCode = `https://github.com/esnet/react-dynamic-forms/tree/inline-editing-layouts2/src/website/examples/${Link}.js`;
91 |
92 | return (
93 |
94 |
95 |
96 |
97 |
98 | {this.renderMarkdown()}
99 |
100 |
101 |
102 | );
103 | }
104 | }
105 |
--------------------------------------------------------------------------------
/packages/website/src/components/Guide.js:
--------------------------------------------------------------------------------
1 | /**
2 | * Copyright (c) 2016-present, The Regents of the University of California,
3 | * through Lawrence Berkeley National Laboratory (subject to receipt
4 | * of any required approvals from the U.S. Dept. of Energy).
5 | * All rights reserved.
6 | *
7 | * This source code is licensed under the BSD-style license found in the
8 | * LICENSE file in the root directory of this source tree.
9 | */
10 |
11 | import React, {Component} from "react";
12 | import Markdown from "react-markdown";
13 | import Prism from "prismjs";
14 |
15 | import Guides from "../guides/guides";
16 | import { codeRenderer, codeBlockRenderer } from "../renderers";
17 |
18 | export default class extends Component {
19 | constructor(props) {
20 | super(props);
21 | this.state = {
22 | markdown: null
23 | };
24 | }
25 |
26 | componentDidMount() {
27 | window.scrollTo(0, 0);
28 | Prism.highlightAll();
29 | const guideName = this.props.match.params.doc || "intro";
30 | const markdownFile = Guides[guideName];
31 | fetch(markdownFile)
32 | .then(response => {
33 | return response.text();
34 | })
35 | .then(markdown => {
36 | this.setState({ markdown });
37 | });
38 | this.setState({ markdown: null });
39 | }
40 |
41 | componentWillReceiveProps(nextProps) {
42 | window.scrollTo(0, 0);
43 | const guideName = nextProps.match.params.doc || "intro";
44 | const markdownFile = Guides[guideName];
45 | fetch(markdownFile)
46 | .then(response => {
47 | return response.text();
48 | })
49 | .then(markdown => {
50 | this.setState({ markdown });
51 | });
52 | this.setState({ markdown: null });
53 | }
54 |
55 | componentDidUpdate() {
56 | Prism.highlightAll();
57 | }
58 |
59 | render() {
60 | if (this.state.markdown !== null) {
61 | return (
62 |
72 | );
73 | } else {
74 | return (
75 |
78 | );
79 | }
80 | }
81 | }
82 |
--------------------------------------------------------------------------------
/packages/website/src/components/Highlighter.js:
--------------------------------------------------------------------------------
1 | export default {
2 | highlightCodeBlocks() {
3 | const els = document.querySelectorAll("pre code");
4 | for (let i = 0; i < els.length; i++) {
5 | if (!els[i].classList.contains("hljs")) {
6 | window.hljs.highlightBlock(els[i]);
7 | }
8 | }
9 | },
10 |
11 | componentDidMount() {
12 | this.highlightCodeBlocks();
13 | },
14 |
15 | componentDidUpdate() {
16 | this.highlightCodeBlocks();
17 | }
18 | };
19 |
--------------------------------------------------------------------------------
/packages/website/src/examples/dynamic/dynamic_docs.md:
--------------------------------------------------------------------------------
1 | ### Description
2 |
3 | The forms library allows you to create forms that dynamically change depending on other filled out fields. An example of this is a form which has a type field and that field controls several other fields that only apply to that type. In this case we want to:
4 |
5 | * Hide and show fields in reaction to a change in the type
6 | * Have hidden fields not be required, i.e. support conditional requires
7 |
8 | #### Render
9 |
10 | The above example begins with a pretty simple `renderForm()` implementation. In fact there's not much to see here. Regardless of the visibility that we'll control in a minute, we can just render all the fields and the forms code will take care of selectively hiding fields for us. Here is the rendered ``, part of the `renderForm()` function, excluding a little code to get out bookmarks map for the Bookmark chooser choice list.
11 |
12 | ```jsx
13 | this.handleChange(formName, value)}
22 | onMissingCountChange={(formName, missing) => this.setState({ hasMissing: missing > 0 })}
23 | onErrorCountChange={(formName, errors) => this.setState({ hasErrors: errors > 0 })}
24 | >
25 | Bookmarked endpoints
26 |
27 |
28 | General information
29 |
30 |
31 |
32 | Endpoint type
33 |
34 |
35 |
36 |
37 |
38 |
39 |
40 |
41 |
42 |
43 |
44 | ```
45 |
46 | #### Tags
47 |
48 | The forms library `schema` supports visibility tags, which can be used to quickly control which set of fields show be visible and which should not, rather than setting each one. The schema for our example looks like
49 | this:
50 |
51 | ```jsx
52 |
53 |
54 |
55 |
56 |
57 |
58 |
59 |
65 |
66 |
67 |
68 |
69 |
70 |
71 | ```
72 |
73 | You can see that for each Field we've defined a `tags` prop. This is a list of visibility tags. Here we've named our tags based on our type values ("Equipment Port", "Patch Panel" and "Foreign"). A special tag "all" can also be added meaning that the attr will always be visible.
74 |
75 | To turn on visibility we use the `visibility` prop on the `Form`. This method takes as its argument the tag to match against the schema to control the visibility of the fields. For example, if we passed in "Equipment Port" then all the attrs with a tag of "all" would be shown, as would those with a tag of "Equipment Port" ("device_name" and "interface"). All others would be hidden.
76 |
77 | ## Dynamic changing the form
78 |
79 | In this form we have a bookmark chooser. When the user selects a preset from this chooser it will fill the form with values. The subtle thing here is that this also sets the type chooser further down the form, which itself controls what fields will be shown. It's this kind of behavior that the forms code is designed to handle.
80 |
81 | Let's think this through:
82 |
83 | 1. The first thing that happens is that the user selects a bookmark from the top chooser.
84 | 2. We know when the user changes something by handling `onChange` in `handleChange()`, so we can compare the previous and next version of the form value
85 | 3. If the bookmark has indeed changed then we can merge in some pre-baked data for that bookmark into the form value before setting it as our source of truth. In this way the change of a single field can cause a change to many fields.
86 |
87 | ```js
88 | if (value.get("bookmarked") !== this.state.value.get("bookmarked")) {
89 | const bookmark = bookmarked[value.get("bookmarked")];
90 | const merged = value.merge(bookmark);
91 | this.setState({ value: merged });
92 | } else {
93 | this.setState({ value });
94 | }
95 | ```
96 |
97 | 4. The form will then re-render and update to show the new values. However we need to handle the visibility state of the form. The visibility of the form is a function of the data in the form (at least in this case), meaning that if the form data is in a particular state, we only show certain fields. Specifically, in this case, when we set the "type" between to one of three possible values we show different fields that only apply to that "type". Therefore, in our `render()` function we get the "type" out of our form state and then set our visibility based on that:
98 |
99 | ```js
100 | render() {
101 |
102 | // Current type
103 | const currentType = values.get("type");
104 |
105 | // Find the visibility tag given our current type
106 | const visibilityTag = getVisibilityTag(currentType);
107 |
108 | ...
109 | }
110 | ```
111 |
112 | As mentioned above, we encode the tags within the `Schema`, so here we are simply mapping between the current type value and the tags in the schema.
113 |
114 | 5. Finally, to complete the dynamically updating form, we simply render
115 | the form but set the visibility prop to our `visibilityTag`.
116 |
117 | ```
118 | render() {
119 | ...
120 | return (
121 |
126 | ...
127 |
128 | );
129 | }
130 | ```
131 |
--------------------------------------------------------------------------------
/packages/website/src/examples/dynamic/dynamic_thumbnail.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/esnet/react-dynamic-forms/0f24c808fa1cadb3df6b1635cde377a0959acdd6/packages/website/src/examples/dynamic/dynamic_thumbnail.png
--------------------------------------------------------------------------------
/packages/website/src/examples/examples.js:
--------------------------------------------------------------------------------
1 | /**
2 | * Copyright (c) 2016-present, The Regents of the University of California,
3 | * through Lawrence Berkeley National Laboratory (subject to receipt
4 | * of any required approvals from the U.S. Dept. of Energy).
5 | * All rights reserved.
6 | *
7 | * This source code is licensed under the BSD-style license found in the
8 | * LICENSE file in the root directory of this source tree.
9 | */
10 |
11 | //
12 | // Export all of the examples
13 | //
14 |
15 | import dynamic from "./dynamic/Index";
16 | import form from "./form/Index";
17 | import list from "./list/Index";
18 | import schema from "./schema/Index";
19 |
20 | export default {
21 | ...dynamic,
22 | ...form,
23 | ...list,
24 | ...schema
25 | };
26 |
--------------------------------------------------------------------------------
/packages/website/src/examples/examples.json:
--------------------------------------------------------------------------------
1 | {
2 | "dynamic": {
3 | "title": "Dynamic",
4 | "description": "This example demonstrates the use of a Dynamic Form",
5 | "tags": ["Form"],
6 | "link": "DynamicExample"
7 | },
8 | "form": {
9 | "title": "Form",
10 | "description": "This example demonstrates the use of a Basic Form",
11 | "tags": ["Form"],
12 | "link": "FormExample"
13 | },
14 | "list": {
15 | "title": "List",
16 | "description": "This example demonstrates the use of a List",
17 | "tags": ["List"],
18 | "link": "LinkExample"
19 | },
20 | "schema": {
21 | "title": "Schema",
22 | "description": "This example demonstrates the use of a Schema",
23 | "tags": ["Schema"],
24 | "link": "SchemaExample"
25 | }
26 | }
27 |
--------------------------------------------------------------------------------
/packages/website/src/examples/form/form_docs.md:
--------------------------------------------------------------------------------
1 | ### Forms example
2 |
3 | The forms library is designed to help you build a complete form. In this example
4 | we create a simple contacts form. There are other examples too of forms which change
5 | their structure as the user interacts with tham, as well as demostrating the use
6 | of lists within the forms. But here we keep it relatively simple.
7 |
8 | **What do we want from our form?**
9 |
10 | Essentially we want to provide perhaps some initial data, our form `"value"`,
11 | defaults in the case of a new form, or maybe our current
12 | database state in the case of editing an existing entity.
13 |
14 | As the user edits the data, we'll want to track that. We may choose to save
15 | it on submit (if it's a new form, that's likely), or save it as the user edits it
16 | (perhaps if they are using inline editing we might
17 | want to save the data when any fields are changed). Either way, the forms library
18 | allows you to provide a callback function, which will be called whenever the values
19 | in the form change. How you want to respond to that is up to you, but this example
20 | demostrates one possible approach.
21 |
22 | In addition to knowing that the form values have changed, we also need to know if
23 | the form has any errors or missing fields. We do this via callbacks as well, where
24 | each callback will tell you the number of missing or empty fields that exist within
25 | the form. You can use that to control if the user can submit the form or not, as
26 | we do in this example.
27 |
28 | Okay, so we have initial values and we have some callbacks.
29 |
30 | **How do we get a form up and running to use those?**
31 |
32 | Forms have two concerns. Each form has a schema which we use to provide the meta
33 | data for fields within the form. This includes UI elements like the label for each
34 | fields, the placeholder text, etc, but also rules around the field itself. For
35 | example a field (called an Field in this library),
36 |
37 | The form elements are defined by a **schema**. Schemas can be defined with JSX or manually. Here's the schema used in this page:
38 |
39 | const schema = (
40 |
41 |
43 |
45 |
47 |
48 |
49 |
50 | );
51 |
52 | As you can see the schema is used to associate the Field name (`"first_name"` for example) with some properties which define how it looks and what is a valid value for that Field. Here we define a label (`"First name"`), a placeholder text, and some validation properties. Required can be set true to have the form track that this Field field needs to be filled out before the form is submitted. More on errors and missing value counts below. In addition to being required or not, the Field can have a validation prop set which will be passed to Revalidator for field validation while the user interacts with the form. It is most common to use it to specify the type (`"string", "integer", or "number"`), but you can also specify a format, such as in the example above where the email Field is checked to make sure it is a valid email address. Maximum string lengths, or ranges of numeric values can also be specified. For full details see the [Revalidator website](https://github.com/flatiron/revalidator).
53 |
54 | Rendering is not automatic. Instead the form itself is a React component that you define. We define the form itself like this:
55 |
56 | class ContactForm extends React.Component {
57 |
58 | }
59 |
60 | And then implement the form layout like this:
61 |
62 | renderForm() {
63 | const disableSubmit = this.hasErrors();
64 | return (
65 |
66 |
67 |
68 |
69 |
70 |
71 |
72 |
73 | );
74 | }
75 |
76 | As you can see, we return a `` element which contains further JSX, which is a convenience. In fact, you can define this with a ` ` too. You can use any JSX in here to render the form however you like. This makes the layout of the form as flexible as any other React code.
77 |
78 | The special elements here are the `TextEdit`s. They specify an `field` prop which references the schema (we'll see how to get the schema hooked up in a minute). Each TextEditGroup will generate a label and a form control (in this case a `TextEdit`). We use Bootstrap for the layout. In addition to TextEditGroups there's also: `TextAreaGroup`, `ChooserGroup`, `OptionsGroup` and `TagsGroup`. You can also wrap your own controls in the generic `Group`.
79 |
80 | Now that we have out form it's time to use it. Typically the form will be contained (rendered by) another React component which will hold the business logic of sourcing the schema and initial values, as well as handling the submit of the form in some way.
81 |
82 | To render the form we created above we need to pass in the initial values and schema. Here is the key part of render function for this page's example:
83 |
84 | render: function() {
85 | ...
86 |
91 | ...
92 | }
93 |
94 | Note that the schema is required, so you cannot render the form until one is available. If this is being loaded from the server you would display a Spinner until it is available.
95 |
96 | ---
--------------------------------------------------------------------------------
/packages/website/src/examples/form/form_thumbnail.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/esnet/react-dynamic-forms/0f24c808fa1cadb3df6b1635cde377a0959acdd6/packages/website/src/examples/form/form_thumbnail.png
--------------------------------------------------------------------------------
/packages/website/src/examples/list/list_docs.md:
--------------------------------------------------------------------------------
1 | ### List example
2 |
3 | The first step is to render a form for entering an email address. In the case of this example we do have a little form that asks for the email address and email type. In that case we specify a schema and a form component to render that form:
4 |
5 | const schema = (
6 |
7 |
14 |
15 |
16 | );
17 |
18 | /**
19 | * Renders a form for entering an email address
20 | */
21 | class EmailForm extends React.Component {
22 |
23 | renderForm() {
24 | const id = this.value("email_type");
25 | return (
26 |
34 |
40 |
41 |
42 | );
43 | }
44 | };
45 |
46 | const EmailList = formList(EmailForm);
47 | const Emails = formGroup(EmailList);
48 |
49 | Having defined that, we can now create a form to edit a contact:
50 |
51 | class ContactForm extends React.Component {
52 |
53 | schema() {
54 | return (
55 |
56 |
63 |
70 |
71 |
72 | );
73 | }
74 |
75 | render() {
76 | const disableSubmit = false;
77 | const style = { background: "#FAFAFA", padding: 10, borderRadius: 5 };
78 | const { value } = this.props;
79 | const emails = value.get("emails");
80 |
81 | return (
82 | this.handleChange(fieldName, value)}
90 | onMissingCountChange={(form, missing) =>
91 | this.handleMissingCountChange(form, missing)}
92 | onErrorCountChange={(form, errors) => this.handleErrorCountChange(form, errors)}
93 | >
94 |
95 |
96 |
97 |
98 |
99 | );
100 | }
101 |
102 | });
103 | ---
--------------------------------------------------------------------------------
/packages/website/src/examples/list/list_thumbnail.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/esnet/react-dynamic-forms/0f24c808fa1cadb3df6b1635cde377a0959acdd6/packages/website/src/examples/list/list_thumbnail.png
--------------------------------------------------------------------------------
/packages/website/src/examples/schema/schema_docs.md:
--------------------------------------------------------------------------------
1 | #
--------------------------------------------------------------------------------
/packages/website/src/examples/schema/schema_thumbnail.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/esnet/react-dynamic-forms/0f24c808fa1cadb3df6b1635cde377a0959acdd6/packages/website/src/examples/schema/schema_thumbnail.png
--------------------------------------------------------------------------------
/packages/website/src/guides/guides.js:
--------------------------------------------------------------------------------
1 | /**
2 | * Copyright (c) 2016-present, The Regents of the University of California,
3 | * through Lawrence Berkeley National Laboratory (subject to receipt
4 | * of any required approvals from the U.S. Dept. of Energy).
5 | * All rights reserved.
6 | *
7 | * This source code is licensed under the BSD-style license found in the
8 | * LICENSE file in the root directory of this source tree.
9 | */
10 |
11 | import intro from "./intro.md";
12 | import start from "./getting_started.md";
13 |
14 | export default {
15 | intro,
16 | start,
17 | };
18 |
--------------------------------------------------------------------------------
/packages/website/src/guides/intro.md:
--------------------------------------------------------------------------------
1 | ## Introduction
2 |
3 | ---
4 |
5 | This repository contains a set of React based forms components which are used within ESnet for our network database application (ESDB), but could be used by any React based project needing to build complex forms.
6 |
7 | Our approach is to treat a form as a controlled input, essentially an input with many inputs (which may have many inputs, and so on...) You maintain your form's state however you want, you pass that state down into the form as its value prop. If the form is edited, a callback is called and you can update your form state. When it comes time to save the form, that's up to you, you always have your form's state. On top of this the form has a schema defining rules. Therefore, you can also listen to changes in the count of either missing values or errors. With this information it is simple to control if the user can submit the form as well.
8 |
9 | The library is built on Immutable.js, so form state should be passed into the form as an Immutable.Map. This allows efficient operations on your form data, minimizing copying while ensuring safety as the form state is mutated.
10 |
11 | While part of defining a form is to specify a schema for your form, you still maintain complete control over the layout in the form in your `render()` method, just like any other react app. The schema and presentation are entirely separate. This React friendly approach makes it easy to build forms which dynamically change values or structure based on the current state of the form.
12 |
13 | This library contains:
14 |
15 | * Low level forms control wrappers that communicate errors and missing values to parent components and style themselves appropriately for errors and missing value state. You can write your own in the same way. Supplied standard form controls:
16 | * Textedit
17 | * TextArea
18 | * Checkboxes
19 | * RadioButtons
20 | * Chooser (internally we use react-select)
21 | * TagsEdit (again using react-select)
22 | * DateEdit (react-datepicker)
23 | * A `` component that lets you define the rules for each field. Each field is specified in a `` component
24 | * A `` component that acts as a top level controlled input for all of the form state, to assemble controls together and track state change, errors and missing values and enabling dynamic forms with via a declarative schema
25 | * Higher Order Components:
26 | * for grouping of controls with their labels, required state and editing control
27 | * building lists of forms
28 | * Inline editing
29 | * List editing
30 |
31 | The library is built on several other open source libraries, especially:
32 |
33 | * react
34 | * immutable.js
35 | * revalidator
36 | * react-bootstrap
37 | * react-select
38 | * react-virtualized
39 | * react-datepicker
40 |
41 | Please browse the examples for a feel for the library, or read on to get started.
42 |
--------------------------------------------------------------------------------
/packages/website/src/img/forms.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/esnet/react-dynamic-forms/0f24c808fa1cadb3df6b1635cde377a0959acdd6/packages/website/src/img/forms.png
--------------------------------------------------------------------------------
/packages/website/src/img/github.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/esnet/react-dynamic-forms/0f24c808fa1cadb3df6b1635cde377a0959acdd6/packages/website/src/img/github.png
--------------------------------------------------------------------------------
/packages/website/src/index.css:
--------------------------------------------------------------------------------
1 | body {
2 | margin: 0;
3 | padding: 0;
4 | font-family: sans-serif;
5 | }
6 |
7 | pre {
8 | display: block;
9 | margin: 0 0 10px;
10 | padding: 0px;
11 | font-size: 13px;
12 | line-height: 1.42857143;
13 | word-break: break-all;
14 | word-wrap: break-word;
15 | color: #333333;
16 | background-color: #f8f8f8;
17 | border-style: none;
18 | border-radius: 0px;
19 | border-left-color: #64a0af;
20 | border-left-style: solid;
21 | border-left-width: 3px;
22 | padding-left: 10px;
23 | }
--------------------------------------------------------------------------------
/packages/website/src/index.js:
--------------------------------------------------------------------------------
1 | import App from "./App";
2 | import React from "react";
3 | import ReactDOM from "react-dom";
4 | import "bootstrap/dist/css/bootstrap.css";
5 | import "bootstrap/dist/css/bootstrap-theme.css";
6 | import "./index.css";
7 |
8 | ReactDOM.render( , document.getElementById('root'));
--------------------------------------------------------------------------------
/packages/website/src/renderers.js:
--------------------------------------------------------------------------------
1 | /**
2 | * Copyright (c) 2017, The Regents of the University of California,
3 | * through Lawrence Berkeley National Laboratory (subject to receipt
4 | * of any required approvals from the U.S. Dept. of Energy).
5 | * All rights reserved.
6 | *
7 | * This source code is licensed under the BSD-style license found in the
8 | * LICENSE file in the root directory of this source tree.
9 | */
10 |
11 | import _ from "lodash";
12 | import React from "react";
13 |
14 | import { codeStyle } from "./styles";
15 |
16 | export function codeRenderer(props) {
17 | const availableLinks = [];
18 | return _.includes(availableLinks, props.literal) ? (
19 |
20 | {props.literal}
21 |
22 | ) : (
23 | {props.literal}
24 | );
25 | }
26 |
27 | export function codeBlockRenderer(props) {
28 | return (
29 |
30 | {props.literal}
31 |
32 | );
33 | }
34 |
--------------------------------------------------------------------------------
/packages/website/src/styles.js:
--------------------------------------------------------------------------------
1 | /**
2 | * Copyright (c) 2017, The Regents of the University of California,
3 | * through Lawrence Berkeley National Laboratory (subject to receipt
4 | * of any required approvals from the U.S. Dept. of Energy).
5 | * All rights reserved.
6 | *
7 | * This source code is licensed under the BSD-style license found in the
8 | * LICENSE file in the root directory of this source tree.
9 | */
10 |
11 | export const sidebarStyle = {
12 | position: "fixed",
13 | right: 0,
14 | top: 80,
15 | width: 250,
16 | bottom: 0,
17 | overflowY: "auto",
18 | background: "#FEFEFE",
19 | color: "#4183C4",
20 | textDecoration: "none",
21 | borderWidth: 1,
22 | borderLeftStyle: "solid",
23 | borderLeftColor: "#ddd",
24 | marginLeft: 40
25 | };
26 |
27 | export const sidebarTitleStyle = {
28 | textTransform: "uppercase",
29 | letterSpacing: ".08em",
30 | color: "#5c666f",
31 | fontSize: 13,
32 | fontWeight: 500,
33 | marginBottom: 15,
34 | marginTop: 30,
35 | padding: "0 20px"
36 | };
37 |
38 | export const sidebarItemStyle = {
39 | fontFamily: "fakt-web,Helvetica Neue,Hevetica,sans-serif",
40 | fontSize: 14,
41 | fontWeight: 400,
42 | letterSpacing: 0,
43 | padding: "10px 20px",
44 | color: "#5c666f"
45 | };
46 |
47 | export const activeStyle = {
48 | color: "black",
49 | textDecoration: "none"
50 | };
51 |
52 | export const activeLinkStyle = {
53 | color: "#626466",
54 | fontWeight: "bold"
55 | };
56 |
57 | export const bodyStyle = {
58 | marginTop: 100,
59 | marginRight: 300,
60 | display: "flex",
61 | minHeight: "100vh",
62 | flexDirection: "column",
63 | overflowY: "hidden"
64 | };
65 |
66 | export const mainStyle = {
67 | display: "flex",
68 | flex: 1,
69 | marginLeft: 20,
70 | marginRight: 40
71 | };
72 |
73 | export const footerStyle = {
74 | flex: "none",
75 | height: 10,
76 | background: "#DDD"
77 | };
78 |
79 | export const contentStyle = {
80 | flex: 1
81 | };
82 |
83 | export const githubLogoStyle = {
84 | width: 24,
85 | paddingRight: 5,
86 | marginTop: -4
87 | };
88 |
89 | export const linkStyle = {
90 | color: "#4183C4",
91 | textDecoration: "none"
92 | };
93 |
94 | export const discussionStyle = {
95 | color: "#555",
96 | fontSize: 18,
97 | letterSpacing: ".25ch",
98 | lineHeight: "16px",
99 | margin: "1rem 0 .125rem",
100 | textTransform: "uppercase"
101 | };
102 |
103 | export const groupStyle = {
104 | color: "#9A9C9E",
105 | // fontSize: 12,
106 | fontSize: "1.5em",
107 | fontWeight: 300,
108 | margin: "2rem 0 2rem"
109 | };
110 |
111 | export const headingStyle = {
112 | fontFamily: 'fakt-web, "Helvetica Neue", Hevetica, sans-serif',
113 | fontSize: 32,
114 | fontWeight: 500,
115 | lineHeight: "72px",
116 | color: "#000"
117 | };
118 |
119 | export const methodHeadingStyle = {
120 | fontFamily: 'fakt-web, "Helvetica Neue", Hevetica, sans-serif',
121 | fontSize: 24,
122 | fontWeight: 500,
123 | lineHeight: "26px",
124 | color: "#000"
125 | };
126 |
127 | export const textStyle = {
128 | color: "#626466",
129 | fontFamily: 'fakt-web, "Helvetica Neue", Hevetica, sans-serif',
130 | fontSize: 14,
131 | lineHeight: "28px",
132 | padding: "3px 0px 0px 0px"
133 | };
134 |
135 | export const codeStyle = {
136 | backgroundColor: "rgb(245, 247, 249)",
137 | borderBottomLeftRadius: 3,
138 | borderBottomRightRadius: 3,
139 | borderTopLeftRadius: 3,
140 | borderTopRightRadius: 3,
141 | borderCollapse: "collapse",
142 | color: "rgba(0, 0, 0, 0.86)",
143 | fontFamily: "'Roboto Mono', Menlo, Monaco, Consolas, 'Courier New', monospace",
144 | fontSize: 12.6,
145 | lineHeight: "25.2px",
146 | paddingBottom: 2,
147 | paddingLeft: 6,
148 | paddingRight: 6,
149 | paddingTop: 0
150 | };
151 |
--------------------------------------------------------------------------------