diff --git a/example/src/FormElementsPage.react.js b/example/src/FormElementsPage.react.js
index 198856be..5102475d 100644
--- a/example/src/FormElementsPage.react.js
+++ b/example/src/FormElementsPage.react.js
@@ -141,7 +141,7 @@ function FormElements() {
-
+
-
+
diff --git a/src/components/Button/Button.react.js b/src/components/Button/Button.react.js
index 4dcdb90f..4b9da341 100644
--- a/src/components/Button/Button.react.js
+++ b/src/components/Button/Button.react.js
@@ -24,6 +24,7 @@ type PropsForAll = {|
+to?: string,
+isOption?: boolean,
+rootRef?: (?HTMLElement) => void,
+ +onClick?: (event: SyntheticMouseEvent) => mixed,
|};
type DefaultButtonComponent = {|
@@ -70,6 +71,8 @@ const Button = (props: Props): React.Node => {
isDropdownToggle,
isOption,
rootRef,
+ to,
+ onClick,
} = props;
const classes = cn(
@@ -148,8 +151,6 @@ const Button = (props: Props): React.Node => {
);
} else {
- const { onClick, to } = props;
-
const Component: React.ElementType = props.RootComponent;
return (
@@ -163,4 +164,6 @@ const Button = (props: Props): React.Node => {
Button.List = ButtonList;
Button.Dropdown = ButtonDropdown;
+Button.displayName = "Button";
+
export default Button;
diff --git a/src/components/Form/Form.examples.md b/src/components/Form/Form.examples.md
index 8b137891..09052fde 100644
--- a/src/components/Form/Form.examples.md
+++ b/src/components/Form/Form.examples.md
@@ -1 +1,7 @@
+```jsx
+
+
+
+```
diff --git a/src/components/Form/Form.react.js b/src/components/Form/Form.react.js
index a1606310..442b243a 100644
--- a/src/components/Form/Form.react.js
+++ b/src/components/Form/Form.react.js
@@ -29,7 +29,7 @@ import FormInputGroupPrepend from "./FormInputGroupPrepend.react";
import FormMaskedInput from "./FormMaskedInput.react";
import FormDatePicker from "./FormDatePicker.react";
-type Props = {|
+export type Props = {|
+children?: React.Node,
+className?: string,
+action?: string,
diff --git a/src/components/Form/FormCheckbox.react.js b/src/components/Form/FormCheckbox.react.js
index ef00e97c..5d3c7670 100644
--- a/src/components/Form/FormCheckbox.react.js
+++ b/src/components/Form/FormCheckbox.react.js
@@ -6,6 +6,9 @@ import Form from "./";
export type Props = {|
+className?: string,
+ /**
+ * Wrap the checkbox with a label
+ */
+label?: string,
+value?: string | number | boolean,
+name?: string,
@@ -33,23 +36,30 @@ function FormCheckbox({
{ "custom-control-inline": isInline },
className
);
- return (
+ const inputComponent = (
+
+ );
+
+ return label ? (
+ ) : (
+ inputComponent
);
}
FormCheckbox.displayName = "Form.Checkbox";
+/** @component */
export default FormCheckbox;
diff --git a/src/components/Form/FormGroup.react.js b/src/components/Form/FormGroup.react.js
index 82e858fe..1fe49524 100644
--- a/src/components/Form/FormGroup.react.js
+++ b/src/components/Form/FormGroup.react.js
@@ -3,12 +3,15 @@
import * as React from "react";
import cn from "classnames";
import FormLabel from "./FormLabel.react";
+import FormInput from "./FormInput.react";
+import type { Props as InputProps } from "./FormInput.react";
type Props = {|
+children?: React.Node,
+className?: string,
+label?: React.Node,
+isRequired?: boolean,
+ +inputProps?: InputProps,
|};
function FormGroup({
@@ -16,8 +19,11 @@ function FormGroup({
children,
label,
isRequired,
+ inputProps,
}: Props): React.Node {
const classes = cn("form-group", className);
+ const inputComponent =
+ inputProps && React.createElement(FormInput, inputProps);
return (
{!label ? null : typeof label === "string" ? (
@@ -28,7 +34,7 @@ function FormGroup({
) : (
label
)}
- {children}
+ {inputComponent || children}
);
}
diff --git a/src/components/Form/FormInput.examples.md b/src/components/Form/FormInput.examples.md
index 963af54c..fe118c1a 100644
--- a/src/components/Form/FormInput.examples.md
+++ b/src/components/Form/FormInput.examples.md
@@ -1,4 +1,32 @@
-### Icon input
+```jsx
+
+```
+
+#### Input Label
+Render an input wrapped in a Form.Group with a Label
+
+```jsx
+
+```
+
+is the same as
+
+```jsx
+
+ Username
+
+
+```
+
+#### Input Icons
+
+```jsx
+
+
+
+```
+
+#### Append the Icon
```jsx
@@ -6,8 +34,6 @@
icon="search"
placeholder="Search for..."
position="append"
- className={"mb-3"}
/>
-
```
diff --git a/src/components/Form/FormInput.react.js b/src/components/Form/FormInput.react.js
index 36d6af76..b807665e 100644
--- a/src/components/Form/FormInput.react.js
+++ b/src/components/Form/FormInput.react.js
@@ -3,6 +3,7 @@
import * as React from "react";
import { Icon } from "../";
import cn from "classnames";
+import FormGroup from "./FormGroup.react";
type FormStyle = {|
+className?: string,
@@ -30,8 +31,15 @@ export type Props = {|
+placeholder?: string,
+type?: "checkbox" | "radio" | "text" | "email" | "password",
+value?: string | number | boolean,
+ /**
+ * Wraps the input in Form.Group and adds a label
+ */
+ +label?: string,
|};
+/**
+ * A an input field
+ */
function FormInput(props: Props): React.Node {
const {
className,
@@ -50,6 +58,7 @@ function FormInput(props: Props): React.Node {
onBlur,
disabled,
readOnly,
+ label,
} = props;
const type = props.type || "text";
@@ -79,7 +88,7 @@ function FormInput(props: Props): React.Node {
onBlur,
};
- return !icon ? (
+ const contents = !icon ? (
{type === "checkbox" || type === "radio" ? (
@@ -106,6 +115,8 @@ function FormInput(props: Props): React.Node {
{feedback && {feedback}}
);
+
+ return label ? {contents} : contents;
}
FormInput.displayName = "Form.Input";
diff --git a/src/components/Form/FormInputGroup.examples.md b/src/components/Form/FormInputGroup.examples.md
new file mode 100644
index 00000000..6657ed4b
--- /dev/null
+++ b/src/components/Form/FormInputGroup.examples.md
@@ -0,0 +1,20 @@
+```jsx
+Go!
+ }>
+
+
+```
+
+```jsx
+Go!
+ } />
+```
+
diff --git a/src/components/Form/FormInputGroup.react.js b/src/components/Form/FormInputGroup.react.js
index 1d432d26..11b5d1c9 100644
--- a/src/components/Form/FormInputGroup.react.js
+++ b/src/components/Form/FormInputGroup.react.js
@@ -2,32 +2,46 @@
import * as React from "react";
import cn from "classnames";
+import Form from "./Form.react";
+import FormInputGroupAppend from "./FormInputGroupAppend.react";
+import FormInputGroupPrepend from "./FormInputGroupPrepend.react";
+import type { Props as InputProps } from "./FormInput.react";
type Props = {|
+children?: React.Node,
+className?: string,
- +append?: boolean,
- +prepend?: boolean,
+ +append?: React.Node,
+ +prepend?: React.Node,
+RootComponent?: React.ElementType,
+ +inputProps?: InputProps,
|};
-function FormInputGroup({
- className,
- children,
- append,
- prepend,
- RootComponent,
-}: Props): React.Node {
+function FormInputGroup(props: Props): React.Node {
+ const { className, append, prepend, RootComponent, inputProps } = props;
const classes = cn(
{
- "input-group": !append && !prepend,
- "input-group-append": append,
- "input-group-prepend": prepend,
+ "input-group": true,
},
className
);
const Component = RootComponent || "div";
- return {children};
+ const children = inputProps ? : props.children;
+
+ if (prepend === true) {
+ return {children};
+ }
+
+ if (append === true) {
+ return {children};
+ }
+
+ return (
+
+ {prepend && {prepend}}
+ {children}
+ {append && {append}}
+
+ );
}
FormInputGroup.displayName = "Form.InputGroup";
diff --git a/src/components/Form/FormInputGroupAppend.examples.md b/src/components/Form/FormInputGroupAppend.examples.md
new file mode 100644
index 00000000..eb7dcfbb
--- /dev/null
+++ b/src/components/Form/FormInputGroupAppend.examples.md
@@ -0,0 +1,14 @@
+```jsx
+
+
+
+
+
+
+```
\ No newline at end of file
diff --git a/src/components/Form/FormInputGroupAppend.react.js b/src/components/Form/FormInputGroupAppend.react.js
index de258b86..278be2cc 100644
--- a/src/components/Form/FormInputGroupAppend.react.js
+++ b/src/components/Form/FormInputGroupAppend.react.js
@@ -2,7 +2,6 @@
import * as React from "react";
import cn from "classnames";
-import FormInputGroup from "./FormInputGroup.react";
type Props = {|
+children?: React.Node,
@@ -10,12 +9,8 @@ type Props = {|
|};
function FormInputGroupAppend({ className, children }: Props): React.Node {
- const classes = cn(className);
- return (
-
- {children}
-
- );
+ const classes = cn("input-group-append", className);
+ return {children};
}
FormInputGroupAppend.displayName = "Form.InputGroupAppend";
diff --git a/src/components/Form/FormInputGroupPrepend.examples.md b/src/components/Form/FormInputGroupPrepend.examples.md
new file mode 100644
index 00000000..8eb002a9
--- /dev/null
+++ b/src/components/Form/FormInputGroupPrepend.examples.md
@@ -0,0 +1,14 @@
+```jsx
+
+
+
+
+
+
+```
\ No newline at end of file
diff --git a/src/components/Form/FormInputGroupPrepend.react.js b/src/components/Form/FormInputGroupPrepend.react.js
index be8f95d3..beec62bc 100644
--- a/src/components/Form/FormInputGroupPrepend.react.js
+++ b/src/components/Form/FormInputGroupPrepend.react.js
@@ -2,7 +2,6 @@
import * as React from "react";
import cn from "classnames";
-import FormInputGroup from "./FormInputGroup.react";
type Props = {|
+children?: React.Node,
@@ -10,12 +9,8 @@ type Props = {|
|};
function FormInputGroupPrepend({ className, children }: Props): React.Node {
- const classes = cn(className);
- return (
-
- {children}
-
- );
+ const classes = cn("input-group-prepend", className);
+ return {children};
}
FormInputGroupPrepend.displayName = "Form.InputGroupPrepend";
diff --git a/src/components/Form/FormRadio.react.js b/src/components/Form/FormRadio.react.js
index 29bad02f..60605f7c 100644
--- a/src/components/Form/FormRadio.react.js
+++ b/src/components/Form/FormRadio.react.js
@@ -6,6 +6,9 @@ import Form from "./";
type Props = {|
+className?: string,
+ /**
+ * Wrap the checkbox with a label
+ */
+label?: string,
+value?: string | number | boolean,
+name?: string,
@@ -32,20 +35,26 @@ function FormRadio({
{ "custom-control-inline": isInline },
className
);
- return (
+ const inputComponent = (
+
+ );
+
+ return label ? (
+ ) : (
+ inputComponent
);
}
diff --git a/src/components/Form/FormSelect.react.js b/src/components/Form/FormSelect.react.js
index 45092f77..adf71685 100644
--- a/src/components/Form/FormSelect.react.js
+++ b/src/components/Form/FormSelect.react.js
@@ -2,25 +2,81 @@
import * as React from "react";
import cn from "classnames";
+import FormGroup from "./FormGroup.react";
type Props = {|
+children?: React.Node,
+className?: string,
+onChange?: (SyntheticInputEvent) => mixed,
+ +onBlur?: (SyntheticInputEvent) => mixed,
+ +valid?: boolean,
+ +tick?: boolean,
+ +invalid?: boolean,
+ +cross?: boolean,
+ +feedback?: string,
+ +error?: string,
+ /**
+ * Wraps the select in Form.Group and adds a label
+ */
+ +label?: string,
+ +name?: string,
+ +value?: string | number,
+ +disabled?: boolean,
+ +readOnly?: boolean,
|};
-function FormSelect({ className, children, onChange }: Props): React.Node {
+function FormSelect(props: Props): React.Node {
+ const {
+ className,
+ children,
+ onChange,
+ valid,
+ tick,
+ invalid,
+ cross,
+ error,
+ label,
+ onBlur,
+ disabled,
+ readOnly,
+ name,
+ value,
+ } = props;
const classes = cn(
- { "form-control": true, "custom-select": true },
+ {
+ "form-control": true,
+ "custom-select": true,
+ "is-valid": valid,
+ "state-valid": tick,
+ "is-invalid": invalid || !!error,
+ "state-invalid": cross || !!error,
+ },
className
);
- return (
-
+
+ const feedback = error || props.feedback;
+
+ const contents = (
+
+
+ {feedback && {feedback}}
+
);
+
+ return label ? {contents} : contents;
}
FormSelect.displayName = "Form.Select";
+/** @component */
export default FormSelect;
diff --git a/src/components/Form/FormTextarea.react.js b/src/components/Form/FormTextarea.react.js
index e054289f..26896055 100644
--- a/src/components/Form/FormTextarea.react.js
+++ b/src/components/Form/FormTextarea.react.js
@@ -2,6 +2,7 @@
import * as React from "react";
import cn from "classnames";
+import FormGroup from "./FormGroup.react";
type Props = {|
+className?: string,
@@ -20,6 +21,7 @@ type Props = {|
+children?: string,
+onChange?: (event: SyntheticInputEvent) => void,
+onBlur?: (event: SyntheticInputEvent) => void,
+ +label?: string,
|};
function FormTextarea(props: Props): React.Node {
@@ -38,6 +40,7 @@ function FormTextarea(props: Props): React.Node {
rows,
children,
onChange,
+ label,
} = props;
const classes = cn(
"form-control",
@@ -51,7 +54,7 @@ function FormTextarea(props: Props): React.Node {
);
const feedback = error || props.feedback;
- return (
+ const contents = (
);
+
+ return label ? {contents} : contents;
}
FormTextarea.displayName = "Form.Textarea";
+/** @component */
export default FormTextarea;
diff --git a/src/forms/FormWithSingleInputAndButton.react.js b/src/forms/FormWithSingleInputAndButton.react.js
new file mode 100644
index 00000000..16072c0c
--- /dev/null
+++ b/src/forms/FormWithSingleInputAndButton.react.js
@@ -0,0 +1,32 @@
+// @flow
+
+import * as React from "react";
+import Form from "../components/Form/Form.react";
+import Button from "../components/Button/Button.react";
+import type { Props as FormProps } from "../components/Form/Form.react";
+import type { Props as FormInputProps } from "../components/Form/FormInput.react";
+import type { Props as ButtonProps } from "../components/Button/Button.react";
+
+type Props = {|
+ formProps?: FormProps,
+ inputProps?: FormInputProps,
+ buttonProps?: ButtonProps,
+|};
+
+/**
+ * A form containing a single input field with an appended Button
+ */
+function FormWithSingleInputAndButton({
+ formProps,
+ inputProps,
+ buttonProps,
+}: Props): React.Node {
+ const button = React.createElement(Button, buttonProps);
+ return (
+
+
+ );
+}
+
+export default FormWithSingleInputAndButton;