diff --git a/package-lock.json b/package-lock.json index 91f65225288fc4360e2d155dbbc512aefde7bcd0..e55462eedd4644d7f7d553b395ef6a6fcb1548f4 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,9 +1,11 @@ { - "name": "llmlab-app", + "name": "transformerlab-app", + "version": "0.0.1", "lockfileVersion": 3, "requires": true, "packages": { "": { + "version": "0.0.1", "hasInstallScript": true, "license": "MIT", "dependencies": { @@ -11,6 +13,9 @@ "@emotion/styled": "^11.11.0", "@monaco-editor/react": "^4.6.0", "@mui/joy": "^5.0.0-beta.8", + "@rjsf/core": "^5.15.1", + "@rjsf/utils": "^5.15.1", + "@rjsf/validator-ajv8": "^5.15.1", "@uppy/dashboard": "^3.5.1", "@uppy/drag-drop": "^3.0.3", "@uppy/file-input": "^3.0.3", @@ -3839,6 +3844,97 @@ "node": ">=14.0.0" } }, + "node_modules/@rjsf/core": { + "version": "5.15.1", + "resolved": "https://registry.npmjs.org/@rjsf/core/-/core-5.15.1.tgz", + "integrity": "sha512-Ysn9G7sAS9A/fY4tCXv0LUUM8rNgXpVUkkoeOg3Yx6Y0vTctLVM7eorfmKuRKOrUZFCVe/MY0RjJfP3n2v1Fbg==", + "dependencies": { + "lodash": "^4.17.21", + "lodash-es": "^4.17.21", + "markdown-to-jsx": "^7.3.2", + "nanoid": "^3.3.6", + "prop-types": "^15.8.1" + }, + "engines": { + "node": ">=14" + }, + "peerDependencies": { + "@rjsf/utils": "^5.12.x", + "react": "^16.14.0 || >=17" + } + }, + "node_modules/@rjsf/core/node_modules/nanoid": { + "version": "3.3.7", + "resolved": "https://registry.npmjs.org/nanoid/-/nanoid-3.3.7.tgz", + "integrity": "sha512-eSRppjcPIatRIMC1U6UngP8XFcz8MQWGQdt1MTBQ7NaAmvXDfvNxbvWV3x2y6CdEUciCSsDHDQZbhYaB8QEo2g==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/ai" + } + ], + "bin": { + "nanoid": "bin/nanoid.cjs" + }, + "engines": { + "node": "^10 || ^12 || ^13.7 || ^14 || >=15.0.1" + } + }, + "node_modules/@rjsf/utils": { + "version": "5.15.1", + "resolved": "https://registry.npmjs.org/@rjsf/utils/-/utils-5.15.1.tgz", + "integrity": "sha512-ko1hpwy5gK7qwUpiD9fULekBShSrnFDWaIuhLkrN6HsNYGhN9PHZKrlTGcxl3seQvAzXkWfh1aRxNYw4YLCywg==", + "dependencies": { + "json-schema-merge-allof": "^0.8.1", + "jsonpointer": "^5.0.1", + "lodash": "^4.17.21", + "lodash-es": "^4.17.21", + "react-is": "^18.2.0" + }, + "engines": { + "node": ">=14" + }, + "peerDependencies": { + "react": "^16.14.0 || >=17" + } + }, + "node_modules/@rjsf/validator-ajv8": { + "version": "5.15.1", + "resolved": "https://registry.npmjs.org/@rjsf/validator-ajv8/-/validator-ajv8-5.15.1.tgz", + "integrity": "sha512-QEbjdpLTmDCq4pdmeNaCiMiq3CId7IJ/Iri5FI794fhH8mn8Geu5hWqisMBTbrptfGdItY4RapKvoIglQEZKOg==", + "dependencies": { + "ajv": "^8.12.0", + "ajv-formats": "^2.1.1", + "lodash": "^4.17.21", + "lodash-es": "^4.17.21" + }, + "engines": { + "node": ">=14" + }, + "peerDependencies": { + "@rjsf/utils": "^5.12.x" + } + }, + "node_modules/@rjsf/validator-ajv8/node_modules/ajv": { + "version": "8.12.0", + "resolved": "https://registry.npmjs.org/ajv/-/ajv-8.12.0.tgz", + "integrity": "sha512-sRu1kpcO9yLtYxBKvqfTeh9KzZEwO3STyX1HT+4CaDzC6HpTGYhIhPIzj9XuKU7KYDwnaeh5hcOwjy1QuJzBPA==", + "dependencies": { + "fast-deep-equal": "^3.1.1", + "json-schema-traverse": "^1.0.0", + "require-from-string": "^2.0.2", + "uri-js": "^4.2.2" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/epoberezkin" + } + }, + "node_modules/@rjsf/validator-ajv8/node_modules/json-schema-traverse": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-1.0.0.tgz", + "integrity": "sha512-NM8/P9n3XjXhIZn1lLhkFaACTOURQXjWhV4BA/RnOv8xvgqtqpAX9IO4mRQxSx1Rlo4tqzeqb0sOlruaOy3dug==" + }, "node_modules/@sinclair/typebox": { "version": "0.27.8", "resolved": "https://registry.npmjs.org/@sinclair/typebox/-/typebox-0.27.8.tgz", @@ -7416,6 +7512,27 @@ "integrity": "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==", "dev": true }, + "node_modules/compute-gcd": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/compute-gcd/-/compute-gcd-1.2.1.tgz", + "integrity": "sha512-TwMbxBNz0l71+8Sc4czv13h4kEqnchV9igQZBi6QUaz09dnz13juGnnaWWJTRsP3brxOoxeB4SA2WELLw1hCtg==", + "dependencies": { + "validate.io-array": "^1.0.3", + "validate.io-function": "^1.0.2", + "validate.io-integer-array": "^1.0.0" + } + }, + "node_modules/compute-lcm": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/compute-lcm/-/compute-lcm-1.1.2.tgz", + "integrity": "sha512-OFNPdQAXnQhDSKioX8/XYT6sdUlXwpeMjfd6ApxMJfyZ4GxmLR1xvMERctlYhlHwIiz6CSpBc2+qYKjHGZw4TQ==", + "dependencies": { + "compute-gcd": "^1.2.1", + "validate.io-array": "^1.0.3", + "validate.io-function": "^1.0.2", + "validate.io-integer-array": "^1.0.0" + } + }, "node_modules/concat-map": { "version": "0.0.1", "resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz", @@ -13957,6 +14074,27 @@ "resolved": "https://registry.npmjs.org/json-schema/-/json-schema-0.4.0.tgz", "integrity": "sha512-es94M3nTIfsEPisRafak+HDLfHXnKBhV3vU5eqPcS3flIWqcxJWgXHXiey3YrpaNsanY5ei1VoYEbOzijuq9BA==" }, + "node_modules/json-schema-compare": { + "version": "0.2.2", + "resolved": "https://registry.npmjs.org/json-schema-compare/-/json-schema-compare-0.2.2.tgz", + "integrity": "sha512-c4WYmDKyJXhs7WWvAWm3uIYnfyWFoIp+JEoX34rctVvEkMYCPGhXtvmFFXiffBbxfZsvQ0RNnV5H7GvDF5HCqQ==", + "dependencies": { + "lodash": "^4.17.4" + } + }, + "node_modules/json-schema-merge-allof": { + "version": "0.8.1", + "resolved": "https://registry.npmjs.org/json-schema-merge-allof/-/json-schema-merge-allof-0.8.1.tgz", + "integrity": "sha512-CTUKmIlPJbsWfzRRnOXz+0MjIqvnleIXwFTzz+t9T86HnYX/Rozria6ZVGLktAU9e+NygNljveP+yxqtQp/Q4w==", + "dependencies": { + "compute-lcm": "^1.1.2", + "json-schema-compare": "^0.2.2", + "lodash": "^4.17.20" + }, + "engines": { + "node": ">=12.0.0" + } + }, "node_modules/json-schema-traverse": { "version": "0.4.1", "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-0.4.1.tgz", @@ -14003,6 +14141,14 @@ "graceful-fs": "^4.1.6" } }, + "node_modules/jsonpointer": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/jsonpointer/-/jsonpointer-5.0.1.tgz", + "integrity": "sha512-p/nXbhSEcu3pZRdkW1OfJhpsVtW1gd4Wa1fnQc9YLiTfAjn0312eMKimbdIQzuZl9aa9xUGaRlP9T/CJE/ditQ==", + "engines": { + "node": ">=0.10.0" + } + }, "node_modules/jsprim": { "version": "2.0.2", "resolved": "https://registry.npmjs.org/jsprim/-/jsprim-2.0.2.tgz", @@ -14256,6 +14402,11 @@ "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.21.tgz", "integrity": "sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg==" }, + "node_modules/lodash-es": { + "version": "4.17.21", + "resolved": "https://registry.npmjs.org/lodash-es/-/lodash-es-4.17.21.tgz", + "integrity": "sha512-mKnC+QJ9pWVzv+C4/U3rRsHapFfHvQFoFB92e52xeyGMcX6/OlIl78je1u8vePzYZSkkogMPJ2yjxxsb89cxyw==" + }, "node_modules/lodash.debounce": { "version": "4.0.8", "resolved": "https://registry.npmjs.org/lodash.debounce/-/lodash.debounce-4.0.8.tgz", @@ -14493,6 +14644,17 @@ "url": "https://github.com/sponsors/wooorm" } }, + "node_modules/markdown-to-jsx": { + "version": "7.3.2", + "resolved": "https://registry.npmjs.org/markdown-to-jsx/-/markdown-to-jsx-7.3.2.tgz", + "integrity": "sha512-B+28F5ucp83aQm+OxNrPkS8z0tMKaeHiy0lHJs3LqCyDQFtWuenaIrkaVTgAm1pf1AU85LXltva86hlaT17i8Q==", + "engines": { + "node": ">= 10" + }, + "peerDependencies": { + "react": ">= 0.14.0" + } + }, "node_modules/matcher": { "version": "3.0.0", "resolved": "https://registry.npmjs.org/matcher/-/matcher-3.0.0.tgz", @@ -20768,6 +20930,38 @@ "node": ">=10.12.0" } }, + "node_modules/validate.io-array": { + "version": "1.0.6", + "resolved": "https://registry.npmjs.org/validate.io-array/-/validate.io-array-1.0.6.tgz", + "integrity": "sha512-DeOy7CnPEziggrOO5CZhVKJw6S3Yi7e9e65R1Nl/RTN1vTQKnzjfvks0/8kQ40FP/dsjRAOd4hxmJ7uLa6vxkg==" + }, + "node_modules/validate.io-function": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/validate.io-function/-/validate.io-function-1.0.2.tgz", + "integrity": "sha512-LlFybRJEriSuBnUhQyG5bwglhh50EpTL2ul23MPIuR1odjO7XaMLFV8vHGwp7AZciFxtYOeiSCT5st+XSPONiQ==" + }, + "node_modules/validate.io-integer": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/validate.io-integer/-/validate.io-integer-1.0.5.tgz", + "integrity": "sha512-22izsYSLojN/P6bppBqhgUDjCkr5RY2jd+N2a3DCAUey8ydvrZ/OkGvFPR7qfOpwR2LC5p4Ngzxz36g5Vgr/hQ==", + "dependencies": { + "validate.io-number": "^1.0.3" + } + }, + "node_modules/validate.io-integer-array": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/validate.io-integer-array/-/validate.io-integer-array-1.0.0.tgz", + "integrity": "sha512-mTrMk/1ytQHtCY0oNO3dztafHYyGU88KL+jRxWuzfOmQb+4qqnWmI+gykvGp8usKZOM0H7keJHEbRaFiYA0VrA==", + "dependencies": { + "validate.io-array": "^1.0.3", + "validate.io-integer": "^1.0.4" + } + }, + "node_modules/validate.io-number": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/validate.io-number/-/validate.io-number-1.0.3.tgz", + "integrity": "sha512-kRAyotcbNaSYoDnXvb4MHg/0a1egJdLwS6oJ38TJY7aw9n93Fl/3blIXdyYvPOp55CNxywooG/3BcrwNrBpcSg==" + }, "node_modules/validator": { "version": "13.11.0", "resolved": "https://registry.npmjs.org/validator/-/validator-13.11.0.tgz", diff --git a/package.json b/package.json index 555d241fa1edd714ccb07a8a7d0050b8c528510e..77bdca04d19228654af38835411ef992672b9bb8 100644 --- a/package.json +++ b/package.json @@ -93,6 +93,9 @@ "@emotion/styled": "^11.11.0", "@monaco-editor/react": "^4.6.0", "@mui/joy": "^5.0.0-beta.8", + "@rjsf/core": "^5.15.1", + "@rjsf/utils": "^5.15.1", + "@rjsf/validator-ajv8": "^5.15.1", "@uppy/dashboard": "^3.5.1", "@uppy/drag-drop": "^3.0.3", "@uppy/file-input": "^3.0.3", @@ -275,4 +278,4 @@ ], "logLevel": "quiet" } -} \ No newline at end of file +} diff --git a/src/renderer/components/Experiment/Train/DynamicPluginForm.tsx b/src/renderer/components/Experiment/Train/DynamicPluginForm.tsx new file mode 100644 index 0000000000000000000000000000000000000000..cea7555739c71c0a304130cca80603662eb13b93 --- /dev/null +++ b/src/renderer/components/Experiment/Train/DynamicPluginForm.tsx @@ -0,0 +1,32 @@ +/* eslint-disable jsx-a11y/anchor-is-valid */ +import * as React from 'react'; + +import { RJSFSchema } from '@rjsf/utils'; +import validator from '@rjsf/validator-ajv8'; +import Form from '@rjsf/core'; + +const schema: RJSFSchema = { + title: 'Todo', + type: 'object', + required: ['title'], + properties: { + title: { type: 'string', title: 'Title', default: 'A new task' }, + number: { type: 'integer', title: 'Integer' }, + done: { type: 'boolean', title: 'Done?', default: false }, + }, +}; + +const log = (type) => console.log.bind(console, type); + +export default function DynamicPluginForm({ plugin }) { + return ( + <> + {plugin} + {plugin ? ( + <Form className="pure-form" schema={schema} validator={validator} /> + ) : ( + 'No plugin selected' + )} + </> + ); +} diff --git a/src/renderer/components/Experiment/Train/TrainingModalLoRA.tsx b/src/renderer/components/Experiment/Train/TrainingModalLoRA.tsx index 7097f0957dfbde8d3216f351240bd4782d124fcc..ac0c096fc0eb4c83d98be46d281ef5bb3e7a3d41 100644 --- a/src/renderer/components/Experiment/Train/TrainingModalLoRA.tsx +++ b/src/renderer/components/Experiment/Train/TrainingModalLoRA.tsx @@ -26,6 +26,7 @@ import { CircularProgress, Sheet, } from '@mui/joy'; +import DynamicPluginForm from './DynamicPluginForm'; const DefaultLoraConfig = { model_max_length: 2048, @@ -41,6 +42,7 @@ const fetcher = (url) => fetch(url).then((res) => res.json()); export default function TrainingModalLoRA({ open, onClose, experimentInfo }) { // Store the current selected Dataset in this modal const [selectedDataset, setSelectedDataset] = useState(null); + const [selectedPlugin, setSelectedPlugin] = useState(null); const [config, setConfig] = useState(DefaultLoraConfig); // Fetch available datasets from the API @@ -142,6 +144,7 @@ export default function TrainingModalLoRA({ open, onClose, experimentInfo }) { <Tab>Training Data</Tab> {/* <Tab>Training Settings</Tab> */} <Tab>LoRA Settings</Tab> + <Tab>Form Test</Tab> </TabList> <TabPanel value={0} sx={{ p: 2 }} keepMounted> <Stack spacing={2}> @@ -168,7 +171,8 @@ export default function TrainingModalLoRA({ open, onClose, experimentInfo }) { variant="soft" size="lg" name="plugin_name" - onChange={(e, newValue) => setSelectedDataset(newValue)} + value={selectedPlugin} + onChange={(e, newValue) => setSelectedPlugin(newValue)} > {pluginsData?.map((row) => ( <Option value={row?.uniqueId} key={row.uniqueId}> @@ -445,6 +449,9 @@ export default function TrainingModalLoRA({ open, onClose, experimentInfo }) { </Stack> </Sheet> </TabPanel> + <TabPanel value={2} sx={{ p: 2 }} keepMounted> + <DynamicPluginForm plugin={selectedPlugin} /> + </TabPanel> </Tabs> <Stack spacing={2} direction="row" justifyContent="flex-end"> <Button color="danger" variant="soft" onClick={() => onClose()}> diff --git a/src/renderer/styles.css b/src/renderer/styles.css index 985192b3936745aab76de17068d1b8e600e26a14..ab2c6ef3e899d198cb77be5f20bdd32abecf4137 100644 --- a/src/renderer/styles.css +++ b/src/renderer/styles.css @@ -135,3 +135,311 @@ not allowed */ /* p > div { border: 10px solid red; } */ + +/** Pure Forms CSS **/ +/** From https://raw.githubusercontent.com/pure-css/pure/master/src/forms/css/forms.css **/ + +/*csslint box-model:false*/ +/* +Box-model set to false because we're setting a height on select elements, which +also have border and padding. This is done because some browsers don't render +the padding. We explicitly set the box-model for select elements to border-box, +so we can ignore the csslint warning. +*/ + +.pure-form input[type='text'], +.pure-form input[type='password'], +.pure-form input[type='email'], +.pure-form input[type='url'], +.pure-form input[type='date'], +.pure-form input[type='month'], +.pure-form input[type='time'], +.pure-form input[type='datetime'], +.pure-form input[type='datetime-local'], +.pure-form input[type='week'], +.pure-form input[type='number'], +.pure-form input[type='search'], +.pure-form input[type='tel'], +.pure-form input[type='color'], +.pure-form select, +.pure-form textarea { + padding: 0.5em 0.6em; + display: inline-block; + border: 1px solid #ccc; + box-shadow: inset 0 1px 3px #ddd; + border-radius: 4px; + vertical-align: middle; + box-sizing: border-box; +} + +/* +Need to separate out the :not() selector from the rest of the CSS 2.1 selectors +since IE8 won't execute CSS that contains a CSS3 selector. +*/ +.pure-form input:not([type]) { + padding: 0.5em 0.6em; + display: inline-block; + border: 1px solid #ccc; + box-shadow: inset 0 1px 3px #ddd; + border-radius: 4px; + box-sizing: border-box; +} + +/* Chrome (as of v.32/34 on OS X) needs additional room for color to display. */ +/* May be able to remove this tweak as color inputs become more standardized across browsers. */ +.pure-form input[type='color'] { + padding: 0.2em 0.5em; +} + +.pure-form input[type='text']:focus, +.pure-form input[type='password']:focus, +.pure-form input[type='email']:focus, +.pure-form input[type='url']:focus, +.pure-form input[type='date']:focus, +.pure-form input[type='month']:focus, +.pure-form input[type='time']:focus, +.pure-form input[type='datetime']:focus, +.pure-form input[type='datetime-local']:focus, +.pure-form input[type='week']:focus, +.pure-form input[type='number']:focus, +.pure-form input[type='search']:focus, +.pure-form input[type='tel']:focus, +.pure-form input[type='color']:focus, +.pure-form select:focus, +.pure-form textarea:focus { + outline: 0; + border-color: #129fea; +} + +/* +Need to separate out the :not() selector from the rest of the CSS 2.1 selectors +since IE8 won't execute CSS that contains a CSS3 selector. +*/ +.pure-form input:not([type]):focus { + outline: 0; + border-color: #129fea; +} + +.pure-form input[type='file']:focus, +.pure-form input[type='radio']:focus, +.pure-form input[type='checkbox']:focus { + outline: thin solid #129fea; + outline: 1px auto #129fea; +} +.pure-form .pure-checkbox, +.pure-form .pure-radio { + margin: 0.5em 0; + display: block; +} + +.pure-form input[type='text'][disabled], +.pure-form input[type='password'][disabled], +.pure-form input[type='email'][disabled], +.pure-form input[type='url'][disabled], +.pure-form input[type='date'][disabled], +.pure-form input[type='month'][disabled], +.pure-form input[type='time'][disabled], +.pure-form input[type='datetime'][disabled], +.pure-form input[type='datetime-local'][disabled], +.pure-form input[type='week'][disabled], +.pure-form input[type='number'][disabled], +.pure-form input[type='search'][disabled], +.pure-form input[type='tel'][disabled], +.pure-form input[type='color'][disabled], +.pure-form select[disabled], +.pure-form textarea[disabled] { + cursor: not-allowed; + background-color: #eaeded; + color: #cad2d3; +} + +/* +Need to separate out the :not() selector from the rest of the CSS 2.1 selectors +since IE8 won't execute CSS that contains a CSS3 selector. +*/ +.pure-form input:not([type])[disabled] { + cursor: not-allowed; + background-color: #eaeded; + color: #cad2d3; +} +.pure-form input[readonly], +.pure-form select[readonly], +.pure-form textarea[readonly] { + background-color: #eee; /* menu hover bg color */ + color: #777; /* menu text color */ + border-color: #ccc; +} + +.pure-form input:focus:invalid, +.pure-form textarea:focus:invalid, +.pure-form select:focus:invalid { + color: #b94a48; + border-color: #e9322d; +} +.pure-form input[type='file']:focus:invalid:focus, +.pure-form input[type='radio']:focus:invalid:focus, +.pure-form input[type='checkbox']:focus:invalid:focus { + outline-color: #e9322d; +} +.pure-form select { + /* Normalizes the height; padding is not sufficient. */ + height: 2.25em; + border: 1px solid #ccc; + background-color: white; +} +.pure-form select[multiple] { + height: auto; +} +.pure-form label { + margin: 0.5em 0 0.2em; +} +.pure-form fieldset { + margin: 0; + padding: 0.35em 0 0.75em; + border: 0; +} +.pure-form legend { + display: block; + width: 100%; + padding: 0.3em 0; + margin-bottom: 0.3em; + color: #333; + border-bottom: 1px solid #e5e5e5; +} + +.pure-form-stacked input[type='text'], +.pure-form-stacked input[type='password'], +.pure-form-stacked input[type='email'], +.pure-form-stacked input[type='url'], +.pure-form-stacked input[type='date'], +.pure-form-stacked input[type='month'], +.pure-form-stacked input[type='time'], +.pure-form-stacked input[type='datetime'], +.pure-form-stacked input[type='datetime-local'], +.pure-form-stacked input[type='week'], +.pure-form-stacked input[type='number'], +.pure-form-stacked input[type='search'], +.pure-form-stacked input[type='tel'], +.pure-form-stacked input[type='color'], +.pure-form-stacked input[type='file'], +.pure-form-stacked select, +.pure-form-stacked label, +.pure-form-stacked textarea { + display: block; + margin: 0.25em 0; +} + +/* +Need to separate out the :not() selector from the rest of the CSS 2.1 selectors +since IE8 won't execute CSS that contains a CSS3 selector. +*/ +.pure-form-stacked input:not([type]) { + display: block; + margin: 0.25em 0; +} +.pure-form-aligned input, +.pure-form-aligned textarea, +.pure-form-aligned select, +.pure-form-message-inline { + display: inline-block; + vertical-align: middle; +} +.pure-form-aligned textarea { + vertical-align: top; +} + +/* Aligned Forms */ +.pure-form-aligned .pure-control-group { + margin-bottom: 0.5em; +} +.pure-form-aligned .pure-control-group label { + text-align: right; + display: inline-block; + vertical-align: middle; + width: 10em; + margin: 0 1em 0 0; +} +.pure-form-aligned .pure-controls { + margin: 1.5em 0 0 11em; +} + +/* Rounded Inputs */ +.pure-form input.pure-input-rounded, +.pure-form .pure-input-rounded { + border-radius: 2em; + padding: 0.5em 1em; +} + +/* Grouped Inputs */ +.pure-form .pure-group fieldset { + margin-bottom: 10px; +} +.pure-form .pure-group input, +.pure-form .pure-group textarea { + display: block; + padding: 10px; + margin: 0 0 -1px; + border-radius: 0; + position: relative; + top: -1px; +} +.pure-form .pure-group input:focus, +.pure-form .pure-group textarea:focus { + z-index: 3; +} +.pure-form .pure-group input:first-child, +.pure-form .pure-group textarea:first-child { + top: 1px; + border-radius: 4px 4px 0 0; + margin: 0; +} +.pure-form .pure-group input:first-child:last-child, +.pure-form .pure-group textarea:first-child:last-child { + top: 1px; + border-radius: 4px; + margin: 0; +} +.pure-form .pure-group input:last-child, +.pure-form .pure-group textarea:last-child { + top: -2px; + border-radius: 0 0 4px 4px; + margin: 0; +} +.pure-form .pure-group button { + margin: 0.35em 0; +} + +.pure-form .pure-input-1 { + width: 100%; +} +.pure-form .pure-input-3-4 { + width: 75%; +} +.pure-form .pure-input-2-3 { + width: 66%; +} +.pure-form .pure-input-1-2 { + width: 50%; +} +.pure-form .pure-input-1-3 { + width: 33%; +} +.pure-form .pure-input-1-4 { + width: 25%; +} + +/* Inline help for forms */ +.pure-form-message-inline { + display: inline-block; + padding-left: 0.3em; + color: #666; + vertical-align: middle; + font-size: 0.875em; +} + +/* Block help for forms */ +.pure-form-message { + display: block; + color: #666; + font-size: 0.875em; +}