+
+ );
+ }
+}
+
+export default Example; // export is replaced with `ReactDOM.render(, mountNode);` at runtime
diff --git a/components/forms/checkbox/__examples__/error.jsx b/components/checkbox/__examples__/error.jsx
similarity index 77%
rename from components/forms/checkbox/__examples__/error.jsx
rename to components/checkbox/__examples__/error.jsx
index 7240092fd5..937933cebc 100644
--- a/components/forms/checkbox/__examples__/error.jsx
+++ b/components/checkbox/__examples__/error.jsx
@@ -1,11 +1,9 @@
import React from 'react';
-import createReactClass from 'create-react-class';
+// `~` is replaced with design-system-react at runtime
import IconSettings from '~/components/icon-settings';
-import Checkbox from '~/components/forms/checkbox'; // `~` is replaced with design-system-react at runtime
-
-const Example = createReactClass({
- displayName: 'CheckboxExample',
+import Checkbox from '~/components/checkbox';
+class Example extends React.Component {
render () {
return (
@@ -19,7 +17,9 @@ const Example = createReactClass({
@@ -33,7 +33,9 @@ const Example = createReactClass({
);
- },
-});
+ }
+}
+
+Example.displayName = 'CheckboxExample';
export default Example; // export is replaced with `ReactDOM.render(, mountNode);` at runtime
diff --git a/components/forms/checkbox/__examples__/snapshot-base.jsx b/components/checkbox/__examples__/snapshot-base.jsx
similarity index 87%
rename from components/forms/checkbox/__examples__/snapshot-base.jsx
rename to components/checkbox/__examples__/snapshot-base.jsx
index be6aeb34cd..c4dc002092 100644
--- a/components/forms/checkbox/__examples__/snapshot-base.jsx
+++ b/components/checkbox/__examples__/snapshot-base.jsx
@@ -1,12 +1,8 @@
import React from 'react';
-import createReactClass from 'create-react-class';
-
// `~` is replaced with design-system-react at runtime
-import Checkbox from '~/components/forms/checkbox';
-
-const Example = createReactClass({
- displayName: 'CheckboxExample',
+import Checkbox from '~/components/checkbox';
+class Example extends React.Component {
render () {
return (
@@ -36,7 +32,9 @@ const Example = createReactClass({
@@ -64,7 +62,9 @@ const Example = createReactClass({
);
- },
-});
+ }
+}
+
+Example.displayName = 'CheckboxExample';
export default Example; // export is replaced with `ReactDOM.render(, mountNode);` at runtime
diff --git a/components/forms/checkbox/__examples__/snapshot-toggle.jsx b/components/checkbox/__examples__/snapshot-toggle.jsx
similarity index 87%
rename from components/forms/checkbox/__examples__/snapshot-toggle.jsx
rename to components/checkbox/__examples__/snapshot-toggle.jsx
index b38937eb25..1db2e01859 100644
--- a/components/forms/checkbox/__examples__/snapshot-toggle.jsx
+++ b/components/checkbox/__examples__/snapshot-toggle.jsx
@@ -1,12 +1,9 @@
import React from 'react';
-import createReactClass from 'create-react-class';
// `~` is replaced with design-system-react at runtime
-import Checkbox from '~/components/forms/checkbox';
-
-const Example = createReactClass({
- displayName: 'CheckboxExample',
+import Checkbox from '~/components/checkbox';
+class Example extends React.Component {
render () {
return (
@@ -43,7 +40,9 @@ const Example = createReactClass({
@@ -67,7 +66,9 @@ const Example = createReactClass({
);
- },
-});
+ }
+}
+
+Example.displayName = 'CheckboxExample';
export default Example; // export is replaced with `ReactDOM.render(, mountNode);` at runtime
diff --git a/components/forms/checkbox/__examples__/toggle.jsx b/components/checkbox/__examples__/toggle.jsx
similarity index 91%
rename from components/forms/checkbox/__examples__/toggle.jsx
rename to components/checkbox/__examples__/toggle.jsx
index 1bf66f8ac4..afcb7bd425 100644
--- a/components/forms/checkbox/__examples__/toggle.jsx
+++ b/components/checkbox/__examples__/toggle.jsx
@@ -1,13 +1,9 @@
import React from 'react';
-import createReactClass from 'create-react-class';
-import IconSettings from '~/components/icon-settings';
-
// `~` is replaced with design-system-react at runtime
-import Checkbox from '~/components/forms/checkbox';
-
-const Example = createReactClass({
- displayName: 'CheckboxExample',
+import IconSettings from '~/components/icon-settings';
+import Checkbox from '~/components/checkbox';
+class Example extends React.Component {
render () {
return (
@@ -74,7 +70,9 @@ const Example = createReactClass({
);
- },
-});
+ }
+}
+
+Example.displayName = 'CheckboxExample';
export default Example; // export is replaced with `ReactDOM.render(, mountNode);` at runtime
diff --git a/components/forms/checkbox/__tests__/__snapshots__/checkbox.snapshot-test.jsx.snap b/components/checkbox/__tests__/__snapshots__/checkbox.snapshot-test.jsx.snap
similarity index 100%
rename from components/forms/checkbox/__tests__/__snapshots__/checkbox.snapshot-test.jsx.snap
rename to components/checkbox/__tests__/__snapshots__/checkbox.snapshot-test.jsx.snap
diff --git a/components/forms/checkbox/__tests__/checkbox.snapshot-test.jsx b/components/checkbox/__tests__/checkbox.snapshot-test.jsx
similarity index 91%
rename from components/forms/checkbox/__tests__/checkbox.snapshot-test.jsx
rename to components/checkbox/__tests__/checkbox.snapshot-test.jsx
index fbdf6af13a..aec92c08c4 100644
--- a/components/forms/checkbox/__tests__/checkbox.snapshot-test.jsx
+++ b/components/checkbox/__tests__/checkbox.snapshot-test.jsx
@@ -1,6 +1,6 @@
import React from 'react';
import renderer from 'react-test-renderer';
-import { renderMarkup } from '../../../../tests/snapshot-helpers';
+import { renderMarkup } from '../../../tests/snapshot-helpers';
import CheckboxBase from '../__examples__/snapshot-base';
import CheckboxToggle from '../__examples__/snapshot-toggle';
diff --git a/components/checkbox/check-props.js b/components/checkbox/check-props.js
new file mode 100644
index 0000000000..16a20db239
--- /dev/null
+++ b/components/checkbox/check-props.js
@@ -0,0 +1,36 @@
+/* Copyright (c) 2015-present, salesforce.com, inc. All rights reserved */
+/* Licensed under BSD 3-Clause - see LICENSE.txt or git.io/sfdc-license */
+/* eslint-disable import/no-mutable-exports */
+/* eslint-disable max-len */
+
+import deprecatedEventParameter from '../../utilities/warning/deprecated-event-parameter';
+import onlyOneOfProperties from '../../utilities/warning/only-one-of-properties';
+
+let checkProps = function () {};
+
+if (process.env.NODE_ENV !== 'production') {
+ checkProps = function (COMPONENT, props) {
+ deprecatedEventParameter(
+ COMPONENT,
+ {
+ oldEventParameterOrder: props.oldEventParameterOrder,
+ propAsString: 'onChange',
+ propAsValue: props.onChange,
+ },
+ '`components/forms/checkbox` is deprecated. `components/checkbox` should be used. When this path update is made `onChange` event parameters will change from `onChange(value, event, { value } to `onChange(event, { value }). Please update your event parameters when you change paths.` If you are using the CommonJS named import, `Checkbox` events will break at v1.0 and this warning will be present until then. Please review https://github.com/salesforce/design-system-react/releases when you upgrade.'
+ );
+
+ if (props.variant === 'toggle' && props.indeterminate === true) {
+ onlyOneOfProperties(
+ COMPONENT,
+ {
+ variant: props.variant,
+ indeterminate: props.indeterminate,
+ },
+ 'Currently SLDS does not support the `indeterminate` state in Checkbox Toggle. See SLDS documentation about [Checkbox Toggle](https://lightningdesignsystem.com/components/forms/#flavor-checkbox-toggle-checkbox-toggle) for more information.'
+ );
+ }
+ };
+}
+
+export default checkProps;
diff --git a/components/checkbox/index.jsx b/components/checkbox/index.jsx
new file mode 100644
index 0000000000..857ac0537c
--- /dev/null
+++ b/components/checkbox/index.jsx
@@ -0,0 +1,391 @@
+/* Copyright (c) 2015-present, salesforce.com, inc. All rights reserved */
+/* Licensed under BSD 3-Clause - see LICENSE.txt or git.io/sfdc-license */
+
+// # Checkbox Component
+
+// Implements the [Checkbox design pattern](https://www.lightningdesignsystem.com/components/forms/#checkbox) in React.
+
+import React from 'react';
+import PropTypes from 'prop-types';
+
+import classNames from 'classnames';
+
+// ### shortid
+// [npmjs.com/package/shortid](https://www.npmjs.com/package/shortid)
+// shortid is a short, non-sequential, url-friendly, unique id generator
+import shortid from 'shortid';
+
+// ### Event Helpers
+import KEYS from '../../utilities/key-code';
+import EventUtil from '../../utilities/event';
+
+// This component's `checkProps` which issues warnings to developers about properties when in development mode (similar to React's built in development tools)
+import checkProps from './check-props';
+
+import { FORMS_CHECKBOX } from '../../utilities/constants';
+
+const propTypes = {
+ /**
+ * An HTML ID that is shared with ARIA-supported devices with the
+ * `aria-controls` attribute in order to relate the input with
+ * another region of the page. An example would be a select box
+ * that shows or hides a panel.
+ */
+ 'aria-controls': PropTypes.string,
+ /**
+ * The `aria-describedby` attribute is used to indicate the IDs of the elements that describe the object. It is used to establish a relationship between widgets or groups and text that described them. This is very similar to aria-labelledby: a label describes the essence of an object, while a description provides more information that the user might need.
+ */
+ 'aria-describedby': PropTypes.string,
+ /**
+ * `aria-owns` indicate that an element depends on the current one when the relation can't be determined by the hierarchy structure.
+ */
+ 'aria-owns': PropTypes.string,
+ /**
+ * The `aria-required` attribute is used to indicate that user input is required on an element before a form can be submitted.
+ */
+ 'aria-required': PropTypes.bool,
+ /**
+ * **Assistive text for accessibility**
+ * This object is merged with the default props object on every render.
+ * * `label`: This is used as a visually hidden label if, no `labels.label` is provided.
+ */
+ assistiveText: PropTypes.shape({
+ label: PropTypes.string,
+ }),
+ /**
+ * The Checkbox should be a controlled component, and will always be in the state specified. If checked is not defined, the state of the uncontrolled native `input` component will be used.
+ */
+ checked: PropTypes.bool,
+ /**
+ * This is the initial value of an uncontrolled form element and is present only
+ * to provide compatibility with hybrid framework applications that are not
+ * entirely React. It should only be used in an application without centralized
+ * state (Redux, Flux). "Controlled components" with centralized state is highly recommended. See [Code Overview](https://github.com/salesforce/design-system-react/blob/master/docs/codebase-overview.md#controlled-and-uncontrolled-components) for more information.
+ */
+ defaultChecked: PropTypes.bool,
+ /**
+ * Class names to be added to the outer container of the Checkbox.
+ */
+ className: PropTypes.oneOfType([
+ PropTypes.array,
+ PropTypes.object,
+ PropTypes.string,
+ ]),
+ /**
+ * Disables the Checkbox and prevents clicking it.
+ */
+ disabled: PropTypes.bool,
+ /**
+ * Message to display when the Checkbox is in an error state. When this is present, also visually highlights the component as in error.
+ */
+ errorText: PropTypes.string,
+ /**
+ * A unique ID is needed in order to support keyboard navigation and ARIA support. This ID is added to the `input` element
+ */
+ id: PropTypes.string,
+ /**
+ * The Checkbox will be indeterminate if its state can not be figured out or is partially checked. Once a checkbox is indeterminate, a click should cause it to be checked. Since a user cannot put a checkbox into an indeterminate state, it is assumed you are controlling the value of `checked` with the parent, also, and that this is a controlled component. **Note:** `indeterminate` proptype does nothing in the `toggle` variant, as [SLDS does not support it](https://lightningdesignsystem.com/components/forms/#flavor-checkbox-toggle-checkbox-toggle).
+ */
+ indeterminate: PropTypes.bool,
+ /**
+ * **Text labels for internationalization**
+ * This object is merged with the default props object on every render.
+ * * `label`: Label for the _enabled_ state of the Toggle variant. Defaults to "Enabled".
+ * * `toggleDisabled`: Label for the _disabled_ state of the Toggle variant. Defaults to "Disabled". Note that this uses SLDS language, and meaning, of "Enabled" and "Disabled"; referring to the state of whatever the checkbox is _toggling_, not whether the checkbox itself is enabled or disabled.
+ * * `toggleEnabled`: Label for the _enabled_ state of the Toggle variant. Defaults to "Enabled".
+ */
+ labels: PropTypes.shape({
+ label: PropTypes.string,
+ toggleDisabled: PropTypes.string,
+ toggleEnabled: PropTypes.string,
+ }),
+ /**
+ * Name of the submitted form parameter.
+ */
+ name: PropTypes.string,
+ /**
+ * This event fires when the Checkbox looses focus. It passes in `{ event }`.
+ */
+ onBlur: PropTypes.func,
+ /**
+ * This event fires when the Checkbox changes. Passes in `event, { checked }`. This used to be `checked, event, { checked }`.
+ */
+ onChange: PropTypes.func,
+ /**
+ * This event fires when the Checkbox is focused. It passes in `{ event }`.
+ */
+ onFocus: PropTypes.func,
+ /**
+ * This event fires when a key is pressed down. It passes in `{ event }`.
+ */
+ onKeyDown: PropTypes.func,
+ /**
+ * This event fires when a character is typed. See [this article](http://www.bloggingdeveloper.com/post/KeyPress-KeyDown-KeyUp-The-Difference-Between-Javascript-Key-Events.aspx) for more information. It passes in `{ event }`.
+ */
+ onKeyPress: PropTypes.func,
+ /**
+ * This event fires when a pressed key is released. It passes in `{ event }`.
+ */
+ onKeyUp: PropTypes.func,
+ /**
+ * Displays the value of the input, but does not allow changes.
+ */
+ readOnly: PropTypes.bool,
+ /**
+ * Highlights the Checkbox as a required field (does not perform any validation).
+ */
+ required: PropTypes.bool,
+ /**
+ * The aria-role of the checkbox.
+ */
+ role: PropTypes.string,
+ /**
+ * Which UX pattern of checkbox? The default is `base` while other option is `toggle`. (**Note:** `toggle` variant does not support the `indeterminate` feature, because [SLDS does not support it](https://lightningdesignsystem.com/components/forms/#flavor-checkbox-toggle-checkbox-toggle).)
+ */
+ variant: PropTypes.oneOf(['base', 'toggle', 'button-group']),
+};
+
+const defaultProps = {
+ assistiveText: {},
+ labels: {
+ toggleDisabled: 'Disabled',
+ toggleEnabled: 'Enabled',
+ },
+ variant: 'base',
+};
+
+/**
+ * The ability to style checkboxes with CSS varies across browsers. Using this component ensures checkboxes look the same everywhere.
+ */
+class Checkbox extends React.Component {
+ componentWillMount () {
+ checkProps(FORMS_CHECKBOX, this.props);
+ this.generatedId = shortid.generate();
+ }
+
+ getId = () => this.props.id || this.generatedId;
+
+ handleChange = (event) => {
+ const { checked, indeterminate, onChange } = this.props;
+
+ if (typeof onChange === 'function') {
+ // `target.checked` is present twice to maintain backwards compatibility. Please remove first parameter `value` on the next breaking change or when `forms/checkbox` is removed.
+ if (this.props.oldEventParameterOrder) {
+ onChange(event.target.checked, event, {
+ checked: indeterminate ? true : !checked,
+ indeterminate: false,
+ });
+ } else {
+ // NEW API
+ onChange(event, {
+ checked: indeterminate ? true : !checked,
+ indeterminate: false,
+ });
+ }
+ }
+ };
+
+ handleKeyDown = (event) => {
+ if (event.keyCode) {
+ if (event.keyCode === KEYS.ENTER || event.keyCode === KEYS.SPACE) {
+ EventUtil.trapImmediate(event);
+ this.handleChange(event);
+ }
+ }
+ };
+
+ renderButtonGroupVariant = (props, assistiveText, labels) => (
+
+ {
+ this.input = component;
+ }}
+ role={props.role}
+ required={props.required}
+ type="checkbox"
+ />
+
+
+ );
+
+ renderBaseVariant = (props, assistiveText, labels) => (
+
+ );
+
+ render () {
+ const assistiveText = {
+ ...defaultProps.assistiveText,
+ /* Remove backward compatibility at next breaking change */
+ ...(typeof this.props.assistiveText === 'string'
+ ? { label: this.props.assistiveText }
+ : {}),
+ ...(typeof this.props.assistiveText === 'object'
+ ? this.props.assistiveText
+ : {}),
+ };
+ const labels = {
+ ...defaultProps.labels,
+ /* Remove backward compatibility at next breaking change */
+ ...(this.props.label ? { label: this.props.label } : {}),
+ ...this.props.labels,
+ };
+
+ const subRenders = {
+ base: this.renderBaseVariant,
+ 'button-group': this.renderButtonGroupVariant,
+ toggle: this.renderToggleVariant,
+ };
+ const variantExists = subRenders[this.props.variant];
+
+ return variantExists
+ ? subRenders[this.props.variant](this.props, assistiveText, labels)
+ : subRenders.base(this.props, assistiveText, labels);
+ }
+}
+
+Checkbox.displayName = FORMS_CHECKBOX;
+Checkbox.propTypes = propTypes;
+Checkbox.defaultProps = defaultProps;
+
+export default Checkbox;
diff --git a/components/combobox/combobox.jsx b/components/combobox/combobox.jsx
index 3669c099c8..581f9e52b5 100644
--- a/components/combobox/combobox.jsx
+++ b/components/combobox/combobox.jsx
@@ -20,7 +20,7 @@ import classNames from 'classnames';
import shortid from 'shortid';
import Dialog from '../utilities/dialog';
-import InnerInput from '../../components/forms/input/private/inner-input';
+import InnerInput from '../../components/input/private/inner-input';
import InputIcon from '../icon/input-icon';
import Menu from './private/menu';
import Label from '../forms/private/label';
@@ -387,11 +387,11 @@ class Combobox extends React.Component {
* Menu open/close and sub-render methods
*/
- handleClickOutside = () => {
- this.handleRequestClose();
+ handleClickOutside = (event) => {
+ this.handleRequestClose(event, {});
};
- handleClose = () => {
+ handleClose = (event) => {
const isOpen = this.getIsOpen();
if (isOpen) {
@@ -406,7 +406,7 @@ class Combobox extends React.Component {
});
if (this.props.events.onClose) {
- this.props.events.onClose();
+ this.props.events.onClose(event, {});
}
}
};
@@ -414,7 +414,7 @@ class Combobox extends React.Component {
handleInputBlur = (event) => {
// If menu is open when the input's onBlur event fires, it will close before the onClick of the menu item can fire.
setTimeout(() => {
- this.handleClose();
+ this.handleClose(event);
}, 200);
if (this.props.events.onBlur) {
@@ -429,7 +429,7 @@ class Combobox extends React.Component {
handleInputFocus = (event) => {
if (this.props.events.onFocus) {
- this.props.events.onFocus(event);
+ this.props.events.onFocus(event, {});
}
};
@@ -542,7 +542,7 @@ class Combobox extends React.Component {
});
};
- handleOpen = () => {
+ handleOpen = (event, data) => {
const isOpen = this.getIsOpen();
if (!isOpen) {
@@ -557,7 +557,7 @@ class Combobox extends React.Component {
});
if (this.props.events.onOpen) {
- this.props.events.onOpen();
+ this.props.events.onOpen(event, data);
}
}
};
@@ -612,9 +612,9 @@ class Combobox extends React.Component {
}
};
- handleRequestClose = () => {
+ handleRequestClose = (event, data) => {
if (this.props.events.onRequestClose) {
- this.props.events.onRequestClose();
+ this.props.events.onRequestClose(event, data);
}
if (this.getIsOpen()) {
diff --git a/components/data-table/index.jsx b/components/data-table/index.jsx
index 29ca3c2c7f..eecac9d825 100644
--- a/components/data-table/index.jsx
+++ b/components/data-table/index.jsx
@@ -23,9 +23,6 @@ import classNames from 'classnames';
// ### assign
import assign from 'lodash.assign';
-// ### isFunction
-import isFunction from 'lodash.isfunction';
-
// ### reject
import reject from 'lodash.reject';
@@ -190,16 +187,16 @@ const DataTable = createReactClass({
checkProps(DATA_TABLE, this.props);
},
- handleToggleAll (selected, e) {
- if (isFunction(this.props.onChange)) {
- const selection = selected ? [...this.props.items] : [];
+ handleToggleAll (e, { checked }) {
+ if (typeof this.props.onChange === 'function') {
+ const selection = checked ? [...this.props.items] : [];
this.props.onChange(selection, e);
}
},
handleRowToggle (item, selected, e) {
- if (isFunction(this.props.onChange)) {
+ if (typeof this.props.onChange === 'function') {
let selection;
if (selected) {
diff --git a/components/data-table/private/head.jsx b/components/data-table/private/head.jsx
index 21ee552bb6..381a8ced9f 100644
--- a/components/data-table/private/head.jsx
+++ b/components/data-table/private/head.jsx
@@ -7,7 +7,7 @@ import createReactClass from 'create-react-class';
import PropTypes from 'prop-types';
// ## Children
-import Checkbox from '../../forms/checkbox';
+import Checkbox from '../../checkbox';
import HeaderCell from './header-cell';
// ## Constants
@@ -65,7 +65,9 @@ const DataTableHead = createReactClass({
>
{
if (event.keyCode === KEYS.ESCAPE) {
EventUtil.trapEvent(event);
- this.props.onRequestClose(event);
+ this.props.onRequestClose(event, {});
}
};
@@ -160,9 +160,9 @@ class DatepickerCalendarWrapper extends React.Component {
}
};
- handleRequestClose = () => {
+ handleRequestClose = (event) => {
if (this.props.onRequestClose) {
- this.props.onRequestClose();
+ this.props.onRequestClose(event, {});
}
};
diff --git a/components/date-picker/private/calendar.jsx b/components/date-picker/private/calendar.jsx
index ec93db2e06..8c8b3c1f11 100644
--- a/components/date-picker/private/calendar.jsx
+++ b/components/date-picker/private/calendar.jsx
@@ -112,9 +112,9 @@ const DatepickerCalendar = createReactClass({
}
},
- handleRequestClose () {
+ handleRequestClose (event) {
if (this.props.onRequestClose) {
- this.props.onRequestClose();
+ this.props.onRequestClose(event, {});
}
},
diff --git a/components/date-picker/private/day.jsx b/components/date-picker/private/day.jsx
index 348b1bffa5..7cf9229a73 100644
--- a/components/date-picker/private/day.jsx
+++ b/components/date-picker/private/day.jsx
@@ -173,10 +173,6 @@ DatepickerCalendarDay.propTypes = {
* For keyboard navigation. Changes the focus to the same day in the previous week on the calendar. Triggered when up arrow button is pressed.
*/
onKeyboardNavigateToPreviousWeek: PropTypes.func.isRequired,
- /**
- * Triggered when the calendar is cancelled.
- */
- onRequestClose: PropTypes.func.isRequired,
/**
* Triggered when a date on the calendar is clicked.
*/
diff --git a/components/date-picker/private/week.jsx b/components/date-picker/private/week.jsx
index ee64af0776..b85d6f9c01 100644
--- a/components/date-picker/private/week.jsx
+++ b/components/date-picker/private/week.jsx
@@ -28,7 +28,6 @@ const DatepickerWeek = (props) => {
props.onKeyboardNavigateToPreviousWeek
}
onCalendarBlur={props.onCalendarBlur}
- onRequestClose={props.onRequestClose}
onRequestInternalFocusDate={props.onRequestInternalFocusDate}
onSelectDate={props.onSelectDate}
selectedDate={props.selectedDate}
@@ -87,10 +86,6 @@ DatepickerWeek.propTypes = {
* For keyboard navigation. Changes the focus to the same day in the previous week on the calendar. Triggered when up arrow button is pressed.
*/
onKeyboardNavigateToPreviousWeek: PropTypes.func.isRequired,
- /**
- * Triggered when the calendar is cancelled.
- */
- onRequestClose: PropTypes.func.isRequired,
/**
* Triggered when the user wants to focus on a new day witht he keyboard. It returns the keyboard event a data object with the shape: `{date: [Date object]}`. Keyboard event is ommited if a new month is rendered. _Tested with Mocha framework._
*/
diff --git a/components/forms/checkbox/__examples__/default.jsx b/components/forms/checkbox/__examples__/default.jsx
deleted file mode 100644
index f158ce33da..0000000000
--- a/components/forms/checkbox/__examples__/default.jsx
+++ /dev/null
@@ -1,35 +0,0 @@
-import React from 'react';
-import createReactClass from 'create-react-class';
-import IconSettings from '~/components/icon-settings';
-import Checkbox from '~/components/forms/checkbox'; // `~` is replaced with design-system-react at runtime
-
-const Example = createReactClass({
- displayName: 'CheckboxExample',
-
- render () {
- return (
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
- );
- },
-});
-
-export default Example; // export is replaced with `ReactDOM.render(, mountNode);` at runtime
diff --git a/components/forms/checkbox/check-props.js b/components/forms/checkbox/check-props.js
deleted file mode 100644
index d3e38e7b3d..0000000000
--- a/components/forms/checkbox/check-props.js
+++ /dev/null
@@ -1,25 +0,0 @@
-/* Copyright (c) 2015-present, salesforce.com, inc. All rights reserved */
-/* Licensed under BSD 3-Clause - see LICENSE.txt or git.io/sfdc-license */
-/* eslint-disable import/no-mutable-exports */
-/* eslint-disable max-len */
-
-import onlyOneOfProperties from '../../../utilities/warning/only-one-of-properties';
-
-let checkProps = function () {};
-
-if (process.env.NODE_ENV !== 'production') {
- checkProps = function (COMPONENT, props) {
- if (props.variant === 'toggle' && props.indeterminate === true) {
- onlyOneOfProperties(
- COMPONENT,
- {
- variant: props.variant,
- indeterminate: props.indeterminate,
- },
- 'Currently SLDS does not support the `indeterminate` state in Checkbox Toggle. See SLDS documentation about [Checkbox Toggle](https://lightningdesignsystem.com/components/forms/#flavor-checkbox-toggle-checkbox-toggle) for more information.'
- );
- }
- };
-}
-
-export default checkProps;
diff --git a/components/forms/checkbox/index.jsx b/components/forms/checkbox/index.jsx
index 3b2fc57302..60b1013e48 100644
--- a/components/forms/checkbox/index.jsx
+++ b/components/forms/checkbox/index.jsx
@@ -1,390 +1,10 @@
/* Copyright (c) 2015-present, salesforce.com, inc. All rights reserved */
/* Licensed under BSD 3-Clause - see LICENSE.txt or git.io/sfdc-license */
-
-// # Checkbox Component
-
-// Implements the [Checkbox design pattern](https://www.lightningdesignsystem.com/components/forms/#checkbox) in React.
-
-// ### React
import React from 'react';
-import createReactClass from 'create-react-class';
-import PropTypes from 'prop-types';
-
-// ### isFunction
-import isFunction from 'lodash.isfunction';
-
-// ### classNames
-import classNames from 'classnames';
-
-// ### shortid
-// [npmjs.com/package/shortid](https://www.npmjs.com/package/shortid)
-// shortid is a short, non-sequential, url-friendly, unique id generator
-import shortid from 'shortid';
-
-// ### Event Helpers
-import KEYS from '../../../utilities/key-code';
-import EventUtil from '../../../utilities/event';
-
-// This component's `checkProps` which issues warnings to developers about properties when in development mode (similar to React's built in development tools)
-import checkProps from './check-props';
-
-import { FORMS_CHECKBOX } from '../../../utilities/constants';
-
-/**
- * The ability to style checkboxes with CSS varies across browsers. Using this component ensures checkboxes look the same everywhere.
- */
-const Checkbox = createReactClass({
- // ### Display Name
- // Always use the canonical component name as the React display name.
- displayName: FORMS_CHECKBOX,
-
- // ### Prop Types
- propTypes: {
- /**
- * An HTML ID that is shared with ARIA-supported devices with the
- * `aria-controls` attribute in order to relate the input with
- * another region of the page. An example would be a select box
- * that shows or hides a panel.
- */
- 'aria-controls': PropTypes.string,
- /**
- * The `aria-describedby` attribute is used to indicate the IDs of the elements that describe the object. It is used to establish a relationship between widgets or groups and text that described them. This is very similar to aria-labelledby: a label describes the essence of an object, while a description provides more information that the user might need.
- */
- 'aria-describedby': PropTypes.string,
- /**
- * `aria-owns` indicate that an element depends on the current one when the relation can't be determined by the hierarchy structure.
- */
- 'aria-owns': PropTypes.string,
- /**
- * The `aria-required` attribute is used to indicate that user input is required on an element before a form can be submitted.
- */
- 'aria-required': PropTypes.bool,
- /**
- * Text that is visually hidden but read aloud by screenreaders to tell the user what the Checkbox is for.
- * If the Checkbox has a visible label, you can omit the assistiveText prop and use the label prop.
- */
- assistiveText: PropTypes.string,
- /**
- * The Checkbox is a controlled component, and will always be in this state. If checked is not defined, the state of the uncontrolled native `input` component will be used.
- */
- checked: PropTypes.bool,
- /**
- * This is the initial value of an uncontrolled form element and is present only to provide compatibility with
- * hybrid framework applications that are not entirely React. It should only be used in an application without
- * centralized state (Redux, Flux). "Controlled components" with centralized state is highly recommended.
- * See [Code Overview](https://github.com/salesforce/design-system-react/blob/master/docs/codebase-overview.md#controlled-and-uncontrolled-components) for more information.
- */
- defaultChecked: PropTypes.bool,
- /**
- * Class names to be added to the outer container of the Checkbox.
- */
- className: PropTypes.oneOfType([
- PropTypes.array,
- PropTypes.object,
- PropTypes.string,
- ]),
- /**
- * Disables the Checkbox and prevents clicking it.
- */
- disabled: PropTypes.bool,
- /**
- * Message to display when the Checkbox is in an error state. When this is present, also visually highlights the component as in error.
- */
- errorText: PropTypes.string,
- /**
- * A unique ID is needed in order to support keyboard navigation and ARIA support. This ID is added to the `input` element
- */
- id: PropTypes.string,
- /**
- * The Checkbox will be indeterminate if its state can not be figured out or is partially checked. Once a checkbox is indeterminate, a click should cause it to be checked. Since a user cannot put a checkbox into an indeterminate state, it is assumed you are controlling the value of `checked` with the parent, also, and that this is a controlled component. **Note:** `indeterminate` proptype does nothing in the `toggle` variant, as [SLDS does not support it](https://lightningdesignsystem.com/components/forms/#flavor-checkbox-toggle-checkbox-toggle).
- */
- indeterminate: PropTypes.bool,
- /**
- * An optional label for the Checkbox.
- */
- label: PropTypes.string,
- /**
- * Label for the _enabled_ state of the Toggle variant. Defaults to "Enabled".
- */
- labelToggleEnabled: PropTypes.string,
- /**
- * Label for the _disabled_ state of the Toggle variant. Defaults to "Disabled". Note that this uses SLDS language, and meaning, of "Enabled" and "Disabled"; referring to the state of whatever the checkbox is _toggling_, not whether the checkbox itself is enabled or disabled.
- */
- labelToggleDisabled: PropTypes.string,
- /**
- * Name of the submitted form parameter.
- */
- name: PropTypes.string,
- /**
- * This event fires when the Checkbox focused is blurred.
- */
- onBlur: PropTypes.func,
- /**
- * This event fires when the Checkbox changes.
- */
- onChange: PropTypes.func,
- /**
- * This event fires when the Checkbox is focused.
- */
- onFocus: PropTypes.func,
- /**
- * This event fires when a key is pressed down.
- */
- onKeyDown: PropTypes.func,
- /**
- * This event fires when a character is typed. Probably. 👀 See [this article](http://www.bloggingdeveloper.com/post/KeyPress-KeyDown-KeyUp-The-Difference-Between-Javascript-Key-Events.aspx) for more information.
- */
- onKeyPress: PropTypes.func,
- /**
- * This event fires when a pressed key is released.
- */
- onKeyUp: PropTypes.func,
- /**
- * Displays the value of the input, but does not allow changes.
- */
- readOnly: PropTypes.bool,
- /**
- * Highlights the Checkbox as a required field (does not perform any validation).
- */
- required: PropTypes.bool,
- /**
- * The aria-role of the checkbox.
- */
- role: PropTypes.string,
- /**
- * Which flavor of checkbox? Default is `base` while other option is `toggle`. (**Note:** `toggle` variant does not support the `indeterminate` feature, because [SLDS does not support it](https://lightningdesignsystem.com/components/forms/#flavor-checkbox-toggle-checkbox-toggle).)
- */
- variant: PropTypes.oneOf(['base', 'toggle', 'button-group']),
- },
-
- getDefaultProps () {
- return {
- variant: 'base',
- labelToggleEnabled: 'Enabled',
- labelToggleDisabled: 'Disabled',
- };
- },
-
- componentWillMount () {
- checkProps(FORMS_CHECKBOX, this.props);
- this.generatedId = shortid.generate();
- },
-
- getId () {
- return this.props.id || this.generatedId;
- },
-
- handleChange (event) {
- const value = event.target.checked;
- const { checked, indeterminate, onChange } = this.props;
-
- if (isFunction(onChange)) {
- // `checked` is present twice to maintain backwards compatibility. Please remove first parameter `value` on the next breaking change.
- onChange(value, event, {
- checked: indeterminate ? true : !checked,
- indeterminate: false,
- });
- }
- },
-
- handleKeyDown (event) {
- if (event.keyCode) {
- if (event.keyCode === KEYS.ENTER || event.keyCode === KEYS.SPACE) {
- EventUtil.trapImmediate(event);
- this.handleChange(event);
- }
- }
- },
-
- renderButtonGroupVariant (props) {
- return (
-
- {
- this.input = component;
- }}
- role={props.role}
- required={props.required}
- type="checkbox"
- />
-
-
- );
- },
-
- renderBaseVariant (props) {
- return (
-
- );
- },
+// Alias
+import Checkbox from '../../checkbox';
- // ### Render
- render () {
- let renderer;
- switch (this.props.variant) {
- case 'toggle':
- renderer = this.renderToggleVariant(this.props);
- break;
- case 'button-group':
- renderer = this.renderButtonGroupVariant(this.props);
- break;
- default:
- renderer = this.renderBaseVariant(this.props);
- }
- return renderer;
- },
-});
+const OldCheckbox = (props) => ;
-export default Checkbox;
+export default OldCheckbox;
diff --git a/components/forms/input/__docs__/inline/site-stories.js b/components/forms/input/__docs__/inline/site-stories.js
deleted file mode 100644
index 0fbb864752..0000000000
--- a/components/forms/input/__docs__/inline/site-stories.js
+++ /dev/null
@@ -1,10 +0,0 @@
-// This object is imported into the documentation site. An example for the documentation site should be part of the pull request for the component. The object key is the kabob case of the "URL folder". In the case of `http://localhost:8080/components/app-launcher/`, `app-launcher` is the `key`. The folder name is created by `components.component` value in `package.json`. The following uses webpack's raw-loader plugin to get "text files" that will be eval()'d by CodeMirror within the documentation site on page load.
-
-/* eslint-env node */
-/* eslint-disable global-require */
-
-const siteStories = [
- require('raw-loader!@salesforce/design-system-react/components/forms/input/__examples__/inline-default.jsx'),
-];
-
-module.exports = siteStories;
diff --git a/components/forms/input/__docs__/inline/storybook-stories.jsx b/components/forms/input/__docs__/inline/storybook-stories.jsx
index cce6ab5b65..e4d65351e8 100644
--- a/components/forms/input/__docs__/inline/storybook-stories.jsx
+++ b/components/forms/input/__docs__/inline/storybook-stories.jsx
@@ -6,7 +6,7 @@ import { storiesOf, action } from '@storybook/react';
import IconSettings from '../../../../../components/icon-settings';
import { FORMS_INLINE_EDIT } from '../../../../../utilities/constants';
-import InlineEdit from '../../../input/inline';
+import InlineEdit from '../../inline';
const DemoInlineEdit = createReactClass({
displayName: 'DemoInlineEdit',
diff --git a/components/forms/input/index.jsx b/components/forms/input/index.jsx
index 3283130dfe..cb89bfc627 100644
--- a/components/forms/input/index.jsx
+++ b/components/forms/input/index.jsx
@@ -1,414 +1,7 @@
/* Copyright (c) 2015-present, salesforce.com, inc. All rights reserved */
/* Licensed under BSD 3-Clause - see LICENSE.txt or git.io/sfdc-license */
-// # Input Component
-
-// Implements the [Input design pattern](https://lightningdesignsystem.com/components/forms/#flavor-input) in React. Does not yet implement [fixed text](https://lightningdesignsystem.com/components/forms/#flavor-input-input-fixed-text).
-// Based on SLDS v2.2.1
-//
-
-// ### React
-import React from 'react';
-import createReactClass from 'create-react-class';
-import PropTypes from 'prop-types';
-
-// ### classNames
-// [github.com/JedWatson/classnames](https://github.com/JedWatson/classnames)
-// This project uses `classnames`, "a simple javascript utility for conditionally
-// joining classNames together."
-import classNames from 'classnames';
-
-// ### shortid
-// [npmjs.com/package/shortid](https://www.npmjs.com/package/shortid)
-// shortid is a short, non-sequential, url-friendly, unique id generator
-import shortid from 'shortid';
-
-// ## Children
-import InputIcon from '../../icon/input-icon';
-import InnerInput from './private/inner-input';
-import Label from '../private/label';
-
-// This component's `checkProps` which issues warnings to developers about properties when in development mode (similar to React's built in development tools)
-import checkProps from './check-props';
-
-import { FORMS_INPUT } from '../../../utilities/constants';
-
-/**
- * The HTML `input` with a label and error messaging.
- */
-const Input = createReactClass({
- displayName: FORMS_INPUT,
-
- propTypes: {
- /**
- * The aria-activedescendant attribute contains the ID of the currently active child object that is part of a composite widget within the Document Object Model. It makes do with the overhead of having all or more than one child focusable. As the name specifies, it helps in managing the current active child of the composite widget.
- */
- 'aria-activedescendant': PropTypes.string,
- /**
- * Indicates if the suggestions in a composite widget are values that complete the current textbox input.
- */
- 'aria-autocomplete': PropTypes.string,
- /**
- * An HTML ID that is shared with ARIA-supported devices with the
- * `aria-controls` attribute in order to relate the input with
- * another region of the page. An example would be a select box
- * that shows or hides a panel.
- */
- 'aria-controls': PropTypes.string,
- /**
- * The `aria-describedby` attribute is used to indicate the IDs of the elements that describe the object. It is used to establish a relationship between widgets or groups and text that described them. This is very similar to aria-labelledby: a label describes the essence of an object, while a description provides more information that the user might need.
- */
- 'aria-describedby': PropTypes.string,
- /**
- * Use the `aria-expanded` state to indicate whether regions of the content are collapsible, and to expose whether a region is currently expanded or collapsed.
- */
- 'aria-expanded': PropTypes.bool,
- /**
- * Indicates that the element has a popup context menu or sub-level menu.
- */
- 'aria-haspopup': PropTypes.bool,
- /**
- * The aria-labelledby attribute contains the element IDs of labels in objects such as input elements, widgets, and groups. The attribute establishes relationships between objects and their labels. Assistive technology, such as screen readers, use this attribute to catalog the objects in a document so that users can navigate between them. Without an element ID, the assistive technology cannot catalog the object.
- */
- 'aria-labelledby': PropTypes.string,
- /**
- * An HTML ID that is shared with ARIA-supported devices with the
- * `aria-controls` attribute in order to relate the input with
- * another region of the page. An example would be a search field
- * that shows search results.
- */
- 'aria-owns': PropTypes.string,
- /**
- * The `aria-required` attribute is used to indicate that user input is required on an element before a form can be submitted.
- */
- 'aria-required': PropTypes.bool,
- /**
- * **Assistive text for accessibility**
- * * `label`: Visually hidden label but read out loud by screen readers.
- * * `spinner`: Text for loading spinner icon.
- */
- assistiveText: PropTypes.shape({
- label: PropTypes.string,
- spinner: PropTypes.string,
- }),
- /**
- * Elements are added after the `input`.
- */
- children: PropTypes.node,
- /**
- * Class names to be added to the outer container of the input.
- */
- className: PropTypes.oneOfType([
- PropTypes.array,
- PropTypes.object,
- PropTypes.string,
- ]),
- /**
- * Disables the input and prevents editing the contents.
- */
- disabled: PropTypes.bool,
- /**
- * Message to display when the input is in an error state. When this is present, also visually highlights the component as in error.
- */
- errorText: PropTypes.string,
- /**
- * Displays text or node to the left of the input. This follows the fixed text input UX pattern.
- */
- fixedTextLeft: PropTypes.oneOfType([PropTypes.node, PropTypes.string]),
- /**
- * Displays text or node to the right of the input. This follows the fixed text input UX pattern.
- */
- fixedTextRight: PropTypes.oneOfType([PropTypes.node, PropTypes.string]),
- /**
- * If true, loading spinner appears inside input on right hand side.
- */
- hasSpinner: PropTypes.bool,
- /**
- * Left aligned icon, must be instace of `design-system-react/components/icon/input-icon`
- */
- iconLeft: PropTypes.node,
- /**
- * [DEPRECATED] Please use `iconLeft` and `iconRight`.
- */
- iconPosition: PropTypes.string,
- /**
- * Right aligned icon, must be instace of `design-system-react/components/icon/input-icon`
- */
- iconRight: PropTypes.node,
- /**
- * Triggered when an `InlineEdit` becomes editable.
- */
- inlineEditTrigger: PropTypes.node,
- /**
- * Every input must have a unique ID in order to support keyboard navigation and ARIA support.
- */
- id: PropTypes.string,
- /**
- * This callback exposes the input reference / DOM node to parent components. ` this.input = inputComponent} />
- */
- inputRef: PropTypes.func,
- /**
- * Displays the value of the input statically. This follows the static input UX pattern.
- */
- isStatic: PropTypes.bool,
- /**
- * This label appears above the input.
- */
- label: PropTypes.string,
- /**
- * Triggered when focus is removed.
- */
- onBlur: PropTypes.func,
- /**
- * This callback fires when the input changes. The synthetic React event will be the first parameter to the callback. You will probably want to reference `event.target.value` in your callback. No custom data object is provided.
- */
- onChange: PropTypes.func,
- /**
- * This event fires when the input is clicked.
- */
- onClick: PropTypes.func,
- /**
- * Triggered when component is focused.
- */
- onFocus: PropTypes.func,
- /**
- * Similar to `onchange`. Triggered when an element gets user input.
- */
- onInput: PropTypes.func,
- /**
- * Triggered when a submittable `` element is invalid.
- */
- onInvalid: PropTypes.func,
- /**
- * Triggered when a key is pressed down
- */
- onKeyDown: PropTypes.func,
- /**
- * Triggered when a key is pressed and released
- */
- onKeyPress: PropTypes.func,
- /**
- * Triggered when a key is released
- */
- onKeyUp: PropTypes.func,
- /**
- * Triggered after some text has been selected in an element.
- */
- onSelect: PropTypes.func,
- /**
- * Fires when a form is submitted.
- */
- onSubmit: PropTypes.func,
- /**
- * Text that will appear in an empty input.
- */
- placeholder: PropTypes.string,
- /**
- * Sets the minimum number of characters that an `` can accept.
- */
- minLength: PropTypes.string,
- /**
- * Sets the maximum number of characters that an `` can accept.
- */
- maxLength: PropTypes.string,
- /**
- * Name of the submitted form parameter.
- */
- name: PropTypes.string,
- /**
- * Displays the value of the input as readOnly.
- */
- readOnly: PropTypes.bool,
- /**
- * Highlights the input as a required field (does not perform any validation).
- */
- required: PropTypes.bool,
- /**
- * The `` element includes support for all HTML5 types.
- */
- type: PropTypes.oneOf([
- 'text',
- 'password',
- 'datetime',
- 'datetime-local',
- 'date',
- 'month',
- 'time',
- 'week',
- 'number',
- 'email',
- 'url',
- 'search',
- 'tel',
- 'color',
- ]),
- /**
- * The input is a controlled component, and will always display this value.
- */
- value: PropTypes.string,
- /**
- * This is the initial value of an uncontrolled form element and is present only to provide compatibility
- * with hybrid framework applications that are not entirely React. It should only be used in an application
- * without centralized state (Redux, Flux). "Controlled components" with centralized state is highly recommended.
- * See [Code Overview](https://github.com/salesforce/design-system-react/blob/master/docs/codebase-overview.md#controlled-and-uncontrolled-components) for more information.
- */
- defaultValue: PropTypes.string,
- /**
- * ARIA role
- */
- role: PropTypes.string,
- },
-
- getDefaultProps () {
- return {
- type: 'text',
- };
- },
-
- componentWillMount () {
- // `checkProps` issues warnings to developers about properties (similar to React's built in development tools)
- checkProps(FORMS_INPUT, this.props);
-
- this.generatedId = shortid.generate();
- if (this.props.errorText) {
- this.generatedErrorId = shortid.generate();
- }
- },
-
- getId () {
- return this.props.id || this.generatedId;
- },
-
- getErrorId () {
- return this.props['aria-describedby'] || this.generatedErrorId;
- },
-
- // This is convuluted to maintain backwards compatibility. Please remove deprecatedProps on next breaking change.
- getIconRender (position, iconPositionProp) {
- let icon;
-
- /* eslint-disable react/prop-types */
- const deprecatedProps = {
- assistiveText:
- (this.props[iconPositionProp] &&
- this.props[iconPositionProp].props.assistiveText) ||
- this.props.iconAssistiveText,
- category:
- (this.props[iconPositionProp] &&
- this.props[iconPositionProp].props.category) ||
- this.props.iconCategory,
- name:
- (this.props[iconPositionProp] &&
- this.props[iconPositionProp].props.name) ||
- this.props.iconName,
- onClick:
- (this.props[iconPositionProp] &&
- this.props[iconPositionProp].props.onClick) ||
- this.props.onIconClick,
- };
- /* eslint-enable react/prop-types */
-
- if (
- this.props[iconPositionProp] &&
- position &&
- this.props[iconPositionProp]
- ) {
- icon = React.cloneElement(this.props[iconPositionProp], {
- iconPosition: `${position}`,
- });
- } else if (deprecatedProps.name) {
- icon = ;
- }
-
- return icon;
- },
-
- render () {
- // this is a hack to make left the default prop unless overwritten by `iconPosition="right"`
- const hasLeftIcon =
- !!this.props.iconLeft ||
- ((this.props.iconPosition === 'left' ||
- this.props.iconPosition === undefined) &&
- !!this.props.iconName);
- const hasRightIcon =
- !!this.props.iconRight ||
- (this.props.iconPosition === 'right' && !!this.props.iconName);
-
- return (
-
-
-
- {this.props.errorText && (
-
- {this.props.errorText}
-
- )}
- {this.props.children}
-
- );
- },
-});
+// Alias
+import Input from '../../input';
export default Input;
diff --git a/components/forms/input/inline-check-props.js b/components/forms/input/inline-check-props.js
new file mode 100644
index 0000000000..0cecdaa305
--- /dev/null
+++ b/components/forms/input/inline-check-props.js
@@ -0,0 +1,19 @@
+/* Copyright (c) 2015-present, salesforce.com, inc. All rights reserved */
+/* Licensed under BSD 3-Clause - see LICENSE.txt or git.io/sfdc-license */
+/* eslint-disable import/no-mutable-exports */
+/* eslint-disable max-len */
+
+import componentIsDeprecated from '../../../utilities/warning/component-is-deprecated';
+
+let checkProps = function () {};
+
+if (process.env.NODE_ENV !== 'production') {
+ checkProps = function (COMPONENT) {
+ componentIsDeprecated(
+ COMPONENT,
+ 'For a multiple input form, please use the pattern located at https://www.lightningdesignsystem.com/components/form-element/#Record-Detail that swaps out a read-only `Input` with a base `Input`. For a single input, please use a `Popover` paired with `` as the trigger.'
+ );
+ };
+}
+
+export default checkProps;
diff --git a/components/forms/input/inline.jsx b/components/forms/input/inline.jsx
index 5b11c2a82d..094897b8bf 100644
--- a/components/forms/input/inline.jsx
+++ b/components/forms/input/inline.jsx
@@ -22,6 +22,9 @@ import InputIcon from '../../icon/input-icon';
// ### Event Helpers
import KEYS from '../../../utilities/key-code';
+// This component's `checkProps` which issues warnings to developers about properties when in development mode (similar to React's built in development tools)
+import checkProps from './inline-check-props';
+
// ## Constants
import { FORMS_INLINE_EDIT } from '../../../utilities/constants';
@@ -106,6 +109,10 @@ class InlineEdit extends React.Component {
};
}
+ componentWillMount () {
+ checkProps(FORMS_INLINE_EDIT, this.props);
+ }
+
componentDidUpdate () {
if (this.autoFocus) {
if (this.inputNode) {
diff --git a/components/forms/input/search.jsx b/components/forms/input/search.jsx
index 5f72444318..095197079d 100644
--- a/components/forms/input/search.jsx
+++ b/components/forms/input/search.jsx
@@ -1,94 +1,7 @@
/* Copyright (c) 2015-present, salesforce.com, inc. All rights reserved */
/* Licensed under BSD 3-Clause - see LICENSE.txt or git.io/sfdc-license */
-// # Search Component
-
-// Wraps the input to default to a search style.
-
-// ## Dependencies
-
-// ### React
-import React from 'react';
-import PropTypes from 'prop-types';
-
-// ## Children
-import Input from './index';
-import InputIcon from '../../icon/input-icon';
-
-// ### Event Helpers
-import KEYS from '../../../utilities/key-code';
-import EventUtil from '../../../utilities/event';
-
-// ## Constants
-import { FORMS_SEARCH } from '../../../utilities/constants';
-
-const handleKeyDown = (event, onSearch) => {
- if (event.keyCode === KEYS.ENTER) {
- EventUtil.trapImmediate(event);
- onSearch(event);
- }
-};
-
-/**
- * A `Search` is an `Input` which renders the search icon by default. It can be cleared, too. All `Input` props not specified as props already may be used with this component and will override defaults.
- */
-const Search = ({
- assistiveText,
- clearable,
- onClear,
- onSearch,
- placeholder,
- ...props
-}) => (
-
- }
- iconRight={
- clearable ? (
-
- ) : null
- }
- onKeyDown={onSearch ? (event) => handleKeyDown(event, onSearch) : null}
- placeholder={placeholder}
- {...props}
- />
-);
-
-Search.displayName = FORMS_SEARCH;
-
-Search.propTypes = {
- /**
- * Assistive text to search input
- */
- assistiveText: PropTypes.string,
- /**
- * Adds a clear button to right side of the input
- */
- clearable: PropTypes.bool,
- /**
- * Triggers when the clear button is clicked
- */
- onClear: PropTypes.func,
- /**
- * This event fires when enter is pressed in the `input` or the search button is clicked.
- */
- onSearch: PropTypes.func,
- /**
- * Placeholder for the input
- */
- placeholder: PropTypes.string,
-};
+// Alias
+import Search from '../../input/search';
export default Search;
diff --git a/components/forms/radio/index.jsx b/components/forms/radio/index.jsx
index 5fe7bc7d05..4054dbe6e9 100644
--- a/components/forms/radio/index.jsx
+++ b/components/forms/radio/index.jsx
@@ -1,114 +1,7 @@
/* Copyright (c) 2015-present, salesforce.com, inc. All rights reserved */
/* Licensed under BSD 3-Clause - see LICENSE.txt or git.io/sfdc-license */
-import React from 'react';
-import PropTypes from 'prop-types';
-import shortid from 'shortid';
-import classNames from 'classnames';
-
-import { RADIO } from '../../../utilities/constants';
-
-const propTypes = {
- /**
- * The ID of an element that describes this radio input. Often used for error messages.
- */
- 'aria-describedby': PropTypes.string,
- /**
- * This is a controlled component. This radio is checked according to this value.
- */
- checked: PropTypes.bool,
- /**
- * This is the initial value of an uncontrolled form element and is present only to provide compatibility
- * with hybrid framework applications that are not entirely React. It should only be used in an application
- * without centralized state (Redux, Flux). "Controlled components" with centralized state is highly recommended.
- * See [Code Overview](https://github.com/salesforce/design-system-react/blob/master/docs/codebase-overview.md#controlled-and-uncontrolled-components) for more information.
- */
- defaultChecked: PropTypes.bool,
- /**
- * Disable this radio input.
- */
- disabled: PropTypes.bool,
- /**
- * A unique ID that is used to associating a label to the `input` element. This ID is added to the `input` element.
- */
- id: PropTypes.string,
- /**
- * The string or element that is shown as both the title and the label for this radio input.
- */
- label: PropTypes.oneOfType([PropTypes.string, PropTypes.element]).isRequired,
- /**
- * The name of the radio input group.
- */
- name: PropTypes.string,
- /**
- * This event fires when the radio selection changes.
- */
- onChange: PropTypes.func,
- /**
- * The value of this radio input.
- */
- value: PropTypes.string,
- /**
- * Variant of the Radio button. Base is the default and button-group makes the radio button look like a normal button (should be a child of ).
- */
- variant: PropTypes.oneOf(['base', 'button-group']),
-};
-
-const defaultProps = {
- variant: 'base',
-};
-
-/**
- * A radio input that can have a single input checked at any one time. Radios should be wrapped with
- * a [RadioGroup](/components/radio-group) or [RadioButtonGroup](/components/radio-button-group)
- */
-class Radio extends React.Component {
- constructor (props) {
- super(props);
- this.generatedId = shortid.generate();
- }
-
- getId () {
- return this.props.id || this.generatedId;
- }
-
- render () {
- return (
-
-
- {this.props.variant === 'button-group' ? (
-
- ) : (
-
- )}
-
- );
- }
-}
-
-Radio.displayName = RADIO;
-Radio.propTypes = propTypes;
-Radio.defaultProps = defaultProps;
+// Alias
+import Radio from '../../radio';
export default Radio;
diff --git a/components/forms/textarea/index.jsx b/components/forms/textarea/index.jsx
index 1ce03c1ac0..2271433a45 100644
--- a/components/forms/textarea/index.jsx
+++ b/components/forms/textarea/index.jsx
@@ -1,333 +1,7 @@
/* Copyright (c) 2015-present, salesforce.com, inc. All rights reserved */
/* Licensed under BSD 3-Clause - see LICENSE.txt or git.io/sfdc-license */
-/* eslint-disable jsx-a11y/no-autofocus */
+// Alias
+import TextArea from '../../textarea';
-// # Textarea Component
-
-// Implements the [Textarea design pattern](https://lightningdesignsystem.com/components/textarea).
-// Based on SLDS v2.4.0
-//
-
-// ### React
-import React from 'react';
-import createReactClass from 'create-react-class';
-import PropTypes from 'prop-types';
-
-// ### classNames
-// [github.com/JedWatson/classnames](https://github.com/JedWatson/classnames)
-// This project uses `classnames`, "a simple javascript utility for conditionally
-// joining classNames together."
-import classNames from 'classnames';
-
-// ### shortid
-// [npmjs.com/package/shortid](https://www.npmjs.com/package/shortid)
-// shortid is a short, non-sequential, url-friendly, unique id generator
-import shortid from 'shortid';
-
-// ## Children
-// This component's `checkProps` which issues warnings to developers about properties when in development mode (similar to React's built in development tools)
-import checkProps from './check-props';
-
-import { FORMS_TEXTAREA } from '../../../utilities/constants';
-
-/**
- * A multi-line plain-text editing control.
- */
-const Textarea = createReactClass({
- displayName: FORMS_TEXTAREA,
-
- propTypes: {
- /**
- * The aria-activedescendant attribute contains the ID of the currently active child object that is part of a composite widget within the Document Object Model. It makes do with the overhead of having all or more than one child focusable. As the name specifies, it helps in managing the current active child of the composite widget.
- */
- 'aria-activedescendant': PropTypes.string,
- /**
- * Indicates if the suggestions in a composite widget are values that complete the current textbox input.
- */
- 'aria-autocomplete': PropTypes.string,
- /**
- * An HTML ID that is shared with ARIA-supported devices with the
- * `aria-controls` attribute in order to relate the input with
- * another region of the page. An example would be a select box
- * that shows or hides a panel.
- */
- 'aria-controls': PropTypes.string,
- /**
- * The `aria-describedby` attribute is used to indicate the IDs of the elements that describe the object. It is used to establish a relationship between widgets or groups and text that described them. This is very similar to aria-labelledby: a label describes the essence of an object, while a description provides more information that the user might need.
- */
- 'aria-describedby': PropTypes.string,
- /**
- * Use the `aria-expanded` state to indicate whether regions of the content are collapsible, and to expose whether a region is currently expanded or collapsed.
- */
- 'aria-expanded': PropTypes.bool,
- /**
- * Indicates that the element has a popup context menu or sub-level menu.
- */
- 'aria-haspopup': PropTypes.bool,
- /**
- * The aria-labelledby attribute contains the element IDs of labels in objects such as input elements, widgets, and groups. The attribute establishes relationships between objects and their labels. Assistive technology, such as screen readers, use this attribute to catalog the objects in a document so that users can navigate between them. Without an element ID, the assistive technology cannot catalog the object.
- */
- 'aria-labelledby': PropTypes.string,
- /**
- * An HTML ID that is shared with ARIA-supported devices with the
- * `aria-controls` attribute in order to relate the input with
- * another region of the page. An example would be a search field
- * that shows search results.
- */
- 'aria-owns': PropTypes.string,
- /**
- * The `aria-required` attribute is used to indicate that user input is required on an element before a form can be submitted.
- */
- 'aria-required': PropTypes.bool,
- /**
- * Specifies is the textarea should automatically get focus when the page loads. This is typically a poor user experience.
- */
- autoFocus: PropTypes.bool,
- /**
- * If present, the label associated with this `textarea` is overwritten
- * by this text and is visually not shown.
- */
- assistiveText: PropTypes.string,
- /**
- * Elements are added after the `textarea`.
- */
- children: PropTypes.node,
- /**
- * Class names to be added to the textarea component.
- */
- className: PropTypes.oneOfType([
- PropTypes.array,
- PropTypes.object,
- PropTypes.string,
- ]),
- /** Allows for ability to apply classNames to outer textarea div.
- */
- classNameContainer: PropTypes.oneOfType([
- PropTypes.array,
- PropTypes.object,
- PropTypes.string,
- ]),
- /**
- * Disables the textarea and prevents editing the contents.
- */
- disabled: PropTypes.bool,
- /**
- * Message to display when the textarea is in an error state. When this is present, also visually highlights the component as in error.
- */
- errorText: PropTypes.string,
- /**
- * Every textarea must have a unique ID in order to support keyboard navigation and ARIA support.
- */
- id: PropTypes.string,
- /**
- * This callback exposes the textarea reference / DOM node to parent components. ` this.textarea = textareaComponent} />
- */
- textareaRef: PropTypes.func,
- /**
- * This label appears above the textarea.
- */
- label: PropTypes.string,
- /**
- * Triggered when focus is removed.
- */
- onBlur: PropTypes.func,
- /**
- * This callback fires when the textarea changes. The synthetic React event will be the first parameter to the callback. You will probably want to reference `event.target.value` in your callback. No custom data object is provided.
- */
- onChange: PropTypes.func,
- /**
- * This event fires when the textarea is clicked.
- */
- onClick: PropTypes.func,
- /**
- * Triggered when component is focused.
- */
- onFocus: PropTypes.func,
- /**
- * Similar to `onchange`. Triggered when an element gets user input.
- */
- onInput: PropTypes.func,
- /**
- * Triggered when a submittable element is invalid.
- */
- onInvalid: PropTypes.func,
- /**
- * Triggered when a key is pressed down
- */
- onKeyDown: PropTypes.func,
- /**
- * Triggered when a key is pressed and released
- */
- onKeyPress: PropTypes.func,
- /**
- * Triggered when a key is released
- */
- onKeyUp: PropTypes.func,
- /**
- * Triggered after some text has been selected in an element.
- */
- onSelect: PropTypes.func,
- /**
- * Fires when a form is submitted.
- */
- onSubmit: PropTypes.func,
- /**
- * Maximum number of characters allowed.
- */
- maxLength: PropTypes.string,
- /**
- * Name of the submitted form parameter.
- */
- name: PropTypes.string,
- /**
- * Text that will appear in an empty textarea.
- */
- placeholder: PropTypes.string,
- /**
- * Highlights the textarea as a required field (does not perform any validation).
- */
- required: PropTypes.bool,
- /**
- * The textarea is a controlled component, and will always display this value.
- */
- value: PropTypes.string,
- /**
- * The textarea is a uncontrolled component, and this will be the initial value.
- */
- defaultValue: PropTypes.string,
- /**
- * Specifies how the text in a text area is to be wrapped when submitted in a form.
- */
- wrap: PropTypes.oneOf(['soft', 'hard']),
- },
-
- componentWillMount () {
- // `checkProps` issues warnings to developers about properties (similar to React's built in development tools)
- checkProps(FORMS_TEXTAREA, this.props);
-
- this.generatedId = shortid.generate();
- if (this.props.errorText) {
- this.generatedErrorId = shortid.generate();
- }
- },
-
- getId () {
- return this.props.id || this.generatedId;
- },
-
- getErrorId () {
- return this.props['aria-describedby'] || this.generatedErrorId;
- },
-
- // ### Render
- render () {
- const {
- autoFocus,
- assistiveText,
- children,
- className,
- classNameContainer,
- disabled,
- errorText,
- textareaRef, // eslint-disable-line react/prop-types
- label,
- onBlur,
- onChange,
- onClick,
- onFocus,
- onInput,
- onInvalid,
- onKeyDown,
- onKeyPress,
- onKeyUp,
- onSelect,
- onSubmit,
- maxLength,
- name,
- placeholder,
- required,
- role,
- value,
- defaultValue,
- wrap,
-
- // ### Additional properties
- // Using [object destructuring](https://facebook.github.io/react/docs/transferring-props.html#transferring-with-...-in-jsx) to pass on any properties which are not explicitly defined.
- // ...props // Uncomment this if you actually need to send the rest of the props to other elements
- } = this.props;
-
- const labelText = label || assistiveText; // One of these is required to pass accessibility tests
-
- return (
-
- {labelText && (
-
- )}
-
-
-
- {errorText && (
-
- {errorText}
-
- )}
- {children}
-
- );
- },
-});
-
-export default Textarea;
+export default TextArea;
diff --git a/components/index.js b/components/index.js
index 8c33a5eafb..26828d5ec8 100644
--- a/components/index.js
+++ b/components/index.js
@@ -112,14 +112,11 @@ export Filter from './filter';
export SLDSInlineEdit from './forms/input/inline';
export InlineEdit from './forms/input/inline';
-export SLDSInput from './forms/input';
-export Input from './forms/input';
+export SLDSInput from './input';
+export Input from './input';
-export SLDSTextarea from './forms/textarea';
-export Textarea from './forms/textarea';
-
-export SLDSSearch from './forms/input/search';
-export Search from './forms/input/search';
+export SLDSSearch from './input/search';
+export Search from './input/search';
export SLDSInputIcon from './icon/input-icon';
export InputIcon from './icon/input-icon';
@@ -185,8 +182,8 @@ export ProgressIndicator from './progress-indicator';
export SLDSProgressRing from './progress-ring';
export ProgressRing from './progress-ring';
-export SLDSRadio from './forms/radio';
-export Radio from './forms/radio';
+export SLDSRadio from './radio';
+export Radio from './radio';
export SLDSRadioButtonGroup from './radio-button-group';
export RadioButtonGroup from './radio-button-group';
@@ -213,6 +210,9 @@ export SplitViewHeader from './split-view/header';
export SLDSSplitViewListbox from './split-view/listbox';
export SplitViewListbox from './split-view/listbox';
+export SLDSTextarea from './textarea';
+export Textarea from './textarea';
+
export SLDSTimepicker from './time-picker';
export Timepicker from './time-picker';
diff --git a/components/forms/input/__docs__/search/storybook-stories.jsx b/components/input/__docs__/search/storybook-stories.jsx
similarity index 80%
rename from components/forms/input/__docs__/search/storybook-stories.jsx
rename to components/input/__docs__/search/storybook-stories.jsx
index e5526fbecb..06cf039d76 100644
--- a/components/forms/input/__docs__/search/storybook-stories.jsx
+++ b/components/input/__docs__/search/storybook-stories.jsx
@@ -1,8 +1,8 @@
import React from 'react';
import { storiesOf, action } from '@storybook/react';
-import IconSettings from '../../../../icon-settings';
+import IconSettings from '../../../icon-settings';
-import { FORMS_SEARCH } from '../../../../../utilities/constants';
+import { FORMS_SEARCH } from '../../../../utilities/constants';
import Search from '../../search';
storiesOf(FORMS_SEARCH, module)
diff --git a/components/forms/input/__docs__/site-stories.js b/components/input/__docs__/site-stories.js
similarity index 84%
rename from components/forms/input/__docs__/site-stories.js
rename to components/input/__docs__/site-stories.js
index 01857495cd..877fdf625a 100644
--- a/components/forms/input/__docs__/site-stories.js
+++ b/components/input/__docs__/site-stories.js
@@ -4,10 +4,10 @@
/* eslint-disable global-require */
const siteStories = [
- require('raw-loader!@salesforce/design-system-react/components/forms/input/__examples__/default.jsx'),
- require('raw-loader!@salesforce/design-system-react/components/forms/input/__examples__/icons.jsx'),
- require('raw-loader!@salesforce/design-system-react/components/forms/input/__examples__/error.jsx'),
- require('raw-loader!@salesforce/design-system-react/components/forms/input/__examples__/inactiveInputs.jsx'),
+ require('raw-loader!@salesforce/design-system-react/components/input/__examples__/default.jsx'),
+ require('raw-loader!@salesforce/design-system-react/components/input/__examples__/icons.jsx'),
+ require('raw-loader!@salesforce/design-system-react/components/input/__examples__/error.jsx'),
+ require('raw-loader!@salesforce/design-system-react/components/input/__examples__/inactiveInputs.jsx'),
];
module.exports = siteStories;
diff --git a/components/forms/input/__docs__/storybook-stories.jsx b/components/input/__docs__/storybook-stories.jsx
similarity index 96%
rename from components/forms/input/__docs__/storybook-stories.jsx
rename to components/input/__docs__/storybook-stories.jsx
index 7890690144..8e2b89d224 100644
--- a/components/forms/input/__docs__/storybook-stories.jsx
+++ b/components/input/__docs__/storybook-stories.jsx
@@ -1,11 +1,11 @@
import React from 'react';
import { storiesOf, action } from '@storybook/react';
-import IconSettings from '../../../icon-settings';
+import IconSettings from '../../icon-settings';
-import { FORMS_INPUT } from '../../../../utilities/constants';
-import Button from '../../../button';
+import { FORMS_INPUT } from '../../../utilities/constants';
+import Button from '../../button';
import Input from '../';
-import InputIcon from '../../../icon/input-icon';
+import InputIcon from '../../icon/input-icon';
const iconClicked = action;
diff --git a/components/forms/input/__examples__/default.jsx b/components/input/__examples__/default.jsx
similarity index 93%
rename from components/forms/input/__examples__/default.jsx
rename to components/input/__examples__/default.jsx
index 0a251ad9a3..e1ead1db06 100644
--- a/components/forms/input/__examples__/default.jsx
+++ b/components/input/__examples__/default.jsx
@@ -1,7 +1,7 @@
import React from 'react';
import createReactClass from 'create-react-class';
import IconSettings from '~/components/icon-settings';
-import Input from '~/components/forms/input'; // `~` is replaced with design-system-react at runtime
+import Input from '~/components/input'; // `~` is replaced with design-system-react at runtime
const Example = createReactClass({
displayName: 'BaseInputExample',
diff --git a/components/forms/input/__examples__/error.jsx b/components/input/__examples__/error.jsx
similarity index 92%
rename from components/forms/input/__examples__/error.jsx
rename to components/input/__examples__/error.jsx
index 7289e4a855..f7da6cb205 100644
--- a/components/forms/input/__examples__/error.jsx
+++ b/components/input/__examples__/error.jsx
@@ -1,7 +1,7 @@
import React from 'react';
import createReactClass from 'create-react-class';
import IconSettings from '~/components/icon-settings';
-import Input from '~/components/forms/input'; // `~` is replaced with design-system-react at runtime
+import Input from '~/components/input'; // `~` is replaced with design-system-react at runtime
import InputIcon from '~/components/icon/input-icon'; // `~` is replaced with design-system-react at runtime
const Example = createReactClass({
diff --git a/components/forms/input/__examples__/icons.jsx b/components/input/__examples__/icons.jsx
similarity index 96%
rename from components/forms/input/__examples__/icons.jsx
rename to components/input/__examples__/icons.jsx
index fc762cc39e..b45db46de9 100644
--- a/components/forms/input/__examples__/icons.jsx
+++ b/components/input/__examples__/icons.jsx
@@ -1,7 +1,7 @@
import React from 'react';
import createReactClass from 'create-react-class';
import IconSettings from '~/components/icon-settings';
-import Input from '~/components/forms/input'; // `~` is replaced with design-system-react at runtime
+import Input from '~/components/input'; // `~` is replaced with design-system-react at runtime
import InputIcon from '~/components/icon/input-icon'; // `~` is replaced with design-system-react at runtime
const Example = createReactClass({
diff --git a/components/forms/input/__examples__/inactiveInputs.jsx b/components/input/__examples__/inactiveInputs.jsx
similarity index 93%
rename from components/forms/input/__examples__/inactiveInputs.jsx
rename to components/input/__examples__/inactiveInputs.jsx
index 29cea4c6ba..4f9846163f 100644
--- a/components/forms/input/__examples__/inactiveInputs.jsx
+++ b/components/input/__examples__/inactiveInputs.jsx
@@ -1,7 +1,7 @@
import React from 'react';
import createReactClass from 'create-react-class';
import IconSettings from '~/components/icon-settings';
-import Input from '~/components/forms/input'; // `~` is replaced with design-system-react at runtime
+import Input from '~/components/input'; // `~` is replaced with design-system-react at runtime
const Example = createReactClass({
displayName: 'InactiveInputExamples',
diff --git a/components/forms/input/__tests__/input.browser-test.jsx b/components/input/__tests__/input.browser-test.jsx
similarity index 98%
rename from components/forms/input/__tests__/input.browser-test.jsx
rename to components/input/__tests__/input.browser-test.jsx
index c5f2e24b63..64fe73f1ce 100644
--- a/components/forms/input/__tests__/input.browser-test.jsx
+++ b/components/input/__tests__/input.browser-test.jsx
@@ -5,10 +5,10 @@ import { expect } from 'chai';
import assign from 'lodash.assign';
import TestUtils from 'react-addons-test-utils';
-import Input from '../../../forms/input';
-import Icon from '../../../icon';
-import InputIcon from '../../../icon/input-icon';
-import IconSettings from '../../../icon-settings';
+import Input from '../../input';
+import Icon from '../../icon';
+import InputIcon from '../../icon/input-icon';
+import IconSettings from '../../icon-settings';
const {
findRenderedDOMComponentWithTag,
diff --git a/components/forms/input/check-props.js b/components/input/check-props.js
similarity index 90%
rename from components/forms/input/check-props.js
rename to components/input/check-props.js
index 530789d23c..3dc44b0895 100644
--- a/components/forms/input/check-props.js
+++ b/components/input/check-props.js
@@ -3,10 +3,10 @@
/* eslint-disable import/no-mutable-exports */
/* eslint-disable max-len */
-import deprecatedProperty from '../../../utilities/warning/deprecated-property';
-import sunsetProperty from '../../../utilities/warning/sunset-property';
+import deprecatedProperty from '../../utilities/warning/deprecated-property';
+import sunsetProperty from '../../utilities/warning/sunset-property';
// import oneOfRequiredProperty from '../../../utilities/warning/one-of-required-property';
-import onlyOneOfProperties from '../../../utilities/warning/only-one-of-properties';
+import onlyOneOfProperties from '../../utilities/warning/only-one-of-properties';
let checkProps = function () {};
diff --git a/components/input/index.jsx b/components/input/index.jsx
new file mode 100644
index 0000000000..99285bb985
--- /dev/null
+++ b/components/input/index.jsx
@@ -0,0 +1,410 @@
+/* Copyright (c) 2015-present, salesforce.com, inc. All rights reserved */
+/* Licensed under BSD 3-Clause - see LICENSE.txt or git.io/sfdc-license */
+
+// # Input Component
+
+// Implements the [Input design pattern](https://lightningdesignsystem.com/components/forms/#flavor-input) in React. Does not yet implement [fixed text](https://lightningdesignsystem.com/components/forms/#flavor-input-input-fixed-text).
+// Based on SLDS v2.2.1
+//
+
+// ### React
+import React from 'react';
+import createReactClass from 'create-react-class';
+import PropTypes from 'prop-types';
+
+// ### classNames
+// [github.com/JedWatson/classnames](https://github.com/JedWatson/classnames)
+// This project uses `classnames`, "a simple javascript utility for conditionally
+// joining classNames together."
+import classNames from 'classnames';
+
+// ### shortid
+// [npmjs.com/package/shortid](https://www.npmjs.com/package/shortid)
+// shortid is a short, non-sequential, url-friendly, unique id generator
+import shortid from 'shortid';
+
+// ## Children
+import InputIcon from '../icon/input-icon';
+import InnerInput from './private/inner-input';
+import Label from '../utilities/label';
+
+// This component's `checkProps` which issues warnings to developers about properties when in development mode (similar to React's built in development tools)
+import checkProps from './check-props';
+
+import { FORMS_INPUT } from '../../utilities/constants';
+
+/**
+ * The HTML `input` with a label and error messaging.
+ */
+const Input = createReactClass({
+ displayName: FORMS_INPUT,
+
+ propTypes: {
+ /**
+ * The aria-activedescendant attribute contains the ID of the currently active child object that is part of a composite widget within the Document Object Model. It makes do with the overhead of having all or more than one child focusable. As the name specifies, it helps in managing the current active child of the composite widget.
+ */
+ 'aria-activedescendant': PropTypes.string,
+ /**
+ * Indicates if the suggestions in a composite widget are values that complete the current textbox input.
+ */
+ 'aria-autocomplete': PropTypes.string,
+ /**
+ * An HTML ID that is shared with ARIA-supported devices with the
+ * `aria-controls` attribute in order to relate the input with
+ * another region of the page. An example would be a select box
+ * that shows or hides a panel.
+ */
+ 'aria-controls': PropTypes.string,
+ /**
+ * The `aria-describedby` attribute is used to indicate the IDs of the elements that describe the object. It is used to establish a relationship between widgets or groups and text that described them. This is very similar to aria-labelledby: a label describes the essence of an object, while a description provides more information that the user might need.
+ */
+ 'aria-describedby': PropTypes.string,
+ /**
+ * Use the `aria-expanded` state to indicate whether regions of the content are collapsible, and to expose whether a region is currently expanded or collapsed.
+ */
+ 'aria-expanded': PropTypes.bool,
+ /**
+ * Indicates that the element has a popup context menu or sub-level menu.
+ */
+ 'aria-haspopup': PropTypes.bool,
+ /**
+ * The aria-labelledby attribute contains the element IDs of labels in objects such as input elements, widgets, and groups. The attribute establishes relationships between objects and their labels. Assistive technology, such as screen readers, use this attribute to catalog the objects in a document so that users can navigate between them. Without an element ID, the assistive technology cannot catalog the object.
+ */
+ 'aria-labelledby': PropTypes.string,
+ /**
+ * An HTML ID that is shared with ARIA-supported devices with the
+ * `aria-controls` attribute in order to relate the input with
+ * another region of the page. An example would be a search field
+ * that shows search results.
+ */
+ 'aria-owns': PropTypes.string,
+ /**
+ * The `aria-required` attribute is used to indicate that user input is required on an element before a form can be submitted.
+ */
+ 'aria-required': PropTypes.bool,
+ /**
+ * **Assistive text for accessibility**
+ * * `label`: Visually hidden label but read out loud by screen readers.
+ * * `spinner`: Text for loading spinner icon.
+ */
+ assistiveText: PropTypes.shape({
+ label: PropTypes.string,
+ spinner: PropTypes.string,
+ }),
+ /**
+ * Elements are added after the `input`.
+ */
+ children: PropTypes.node,
+ /**
+ * Class names to be added to the outer container of the input.
+ */
+ className: PropTypes.oneOfType([
+ PropTypes.array,
+ PropTypes.object,
+ PropTypes.string,
+ ]),
+ /**
+ * This is the initial value of an uncontrolled form element and
+ * is present only to provide compatibility with hybrid framework
+ * applications that are not entirely React. It should only be used
+ * in an application without centralized state (Redux, Flux).
+ * "Controlled components" with centralized state is highly recommended.
+ * See [Code Overview](https://github.com/salesforce/design-system-react/blob/master/docs/codebase-overview.md#controlled-and-uncontrolled-components) for more information.
+ */
+ defaultValue: PropTypes.string,
+ /**
+ * Disables the input and prevents editing the contents.
+ */
+ disabled: PropTypes.bool,
+ /**
+ * Message to display when the input is in an error state. When this is present, also visually highlights the component as in error.
+ */
+ errorText: PropTypes.oneOfType([PropTypes.node, PropTypes.string]),
+ /**
+ * Displays text or node to the left of the input. This follows the fixed text input UX pattern.
+ */
+ fixedTextLeft: PropTypes.oneOfType([PropTypes.node, PropTypes.string]),
+ /**
+ * Displays text or node to the right of the input. This follows the fixed text input UX pattern.
+ */
+ fixedTextRight: PropTypes.oneOfType([PropTypes.node, PropTypes.string]),
+ /**
+ * If true, loading spinner appears inside input on right hand side.
+ */
+ hasSpinner: PropTypes.bool,
+ /**
+ * Left aligned icon, must be instace of `design-system-react/components/icon/input-icon`
+ */
+ iconLeft: PropTypes.node,
+ /**
+ * Right aligned icon, must be instace of `design-system-react/components/icon/input-icon`
+ */
+ iconRight: PropTypes.node,
+ /**
+ * Every input must have a unique ID in order to support keyboard navigation and ARIA support.
+ */
+ id: PropTypes.string,
+ /**
+ * This callback exposes the input reference / DOM node to parent components. ` this.input = inputComponent} />
+ */
+ inputRef: PropTypes.func,
+ /**
+ * Displays the value of the input statically. This follows the static input UX pattern.
+ */
+ isStatic: PropTypes.bool,
+ /**
+ * This label appears above the input.
+ */
+ label: PropTypes.string,
+ /**
+ * Triggered when focus is removed.
+ */
+ onBlur: PropTypes.func,
+ /**
+ * This callback fires when the input changes. The synthetic React event will be the first parameter to the callback. You will probably want to reference `event.target.value` in your callback. No custom data object is provided.
+ */
+ onChange: PropTypes.func,
+ /**
+ * This event fires when the input is clicked.
+ */
+ onClick: PropTypes.func,
+ /**
+ * Triggered when component is focused.
+ */
+ onFocus: PropTypes.func,
+ /**
+ * Similar to `onchange`. Triggered when an element gets user input.
+ */
+ onInput: PropTypes.func,
+ /**
+ * Triggered when a submittable `` element is invalid.
+ */
+ onInvalid: PropTypes.func,
+ /**
+ * Triggered when a key is pressed down
+ */
+ onKeyDown: PropTypes.func,
+ /**
+ * Triggered when a key is pressed and released
+ */
+ onKeyPress: PropTypes.func,
+ /**
+ * Triggered when a key is released
+ */
+ onKeyUp: PropTypes.func,
+ /**
+ * Triggered after some text has been selected in an element.
+ */
+ onSelect: PropTypes.func,
+ /**
+ * Fires when a form is submitted.
+ */
+ onSubmit: PropTypes.func,
+ /**
+ * Text that will appear in an empty input.
+ */
+ placeholder: PropTypes.string,
+ /**
+ * Sets the minimum number of characters that an `` can accept.
+ */
+ minLength: PropTypes.string,
+ /**
+ * Sets the maximum number of characters that an `` can accept.
+ */
+ maxLength: PropTypes.string,
+ /**
+ * Name of the submitted form parameter.
+ */
+ name: PropTypes.string,
+ /**
+ * Displays the value of the input as read-only. This is used in the inline edit UX pattern.
+ */
+ readOnly: PropTypes.bool,
+ /**
+ * Highlights the input as a required field (does not perform any validation).
+ */
+ required: PropTypes.bool,
+ /**
+ * ARIA role
+ */
+ role: PropTypes.string,
+ /**
+ * The `` element includes support for all HTML5 types.
+ */
+ type: PropTypes.oneOf([
+ 'text',
+ 'password',
+ 'datetime',
+ 'datetime-local',
+ 'date',
+ 'month',
+ 'time',
+ 'week',
+ 'number',
+ 'email',
+ 'url',
+ 'search',
+ 'tel',
+ 'color',
+ ]),
+ /**
+ * The input is a controlled component, and will always display this value.
+ */
+ value: PropTypes.string,
+ },
+
+ getDefaultProps () {
+ return {
+ type: 'text',
+ };
+ },
+
+ componentWillMount () {
+ // `checkProps` issues warnings to developers about properties (similar to React's built in development tools)
+ checkProps(FORMS_INPUT, this.props);
+
+ this.generatedId = shortid.generate();
+ if (this.props.errorText) {
+ this.generatedErrorId = shortid.generate();
+ }
+ },
+
+ getId () {
+ return this.props.id || this.generatedId;
+ },
+
+ getErrorId () {
+ return this.props['aria-describedby'] || this.generatedErrorId;
+ },
+
+ // This is convuluted to maintain backwards compatibility. Please remove deprecatedProps on next breaking change.
+ getIconRender (position, iconPositionProp) {
+ let icon;
+
+ // Remove at next breaking change
+ /* eslint-disable react/prop-types */
+ const deprecatedProps = {
+ assistiveText:
+ (this.props[iconPositionProp] &&
+ this.props[iconPositionProp].props.assistiveText) ||
+ this.props.iconAssistiveText,
+ category:
+ (this.props[iconPositionProp] &&
+ this.props[iconPositionProp].props.category) ||
+ this.props.iconCategory,
+ name:
+ (this.props[iconPositionProp] &&
+ this.props[iconPositionProp].props.name) ||
+ this.props.iconName,
+ onClick:
+ (this.props[iconPositionProp] &&
+ this.props[iconPositionProp].props.onClick) ||
+ this.props.onIconClick,
+ };
+ /* eslint-enable react/prop-types */
+
+ if (
+ this.props[iconPositionProp] &&
+ position &&
+ this.props[iconPositionProp]
+ ) {
+ icon = React.cloneElement(this.props[iconPositionProp], {
+ iconPosition: `${position}`,
+ });
+ } else if (deprecatedProps.name) {
+ icon = ;
+ }
+
+ return icon;
+ },
+
+ render () {
+ // Remove at next breaking change
+ // this is a hack to make left the default prop unless overwritten by `iconPosition="right"`
+ const hasLeftIcon =
+ !!this.props.iconLeft ||
+ ((this.props.iconPosition === 'left' ||
+ this.props.iconPosition === undefined) &&
+ !!this.props.iconName);
+ const hasRightIcon =
+ !!this.props.iconRight ||
+ (this.props.iconPosition === 'right' && !!this.props.iconName);
+
+ return (
+
+
+
+ {this.props.errorText && (
+
+ {this.props.errorText}
+
+ )}
+ {this.props.children}
+
+ );
+ },
+});
+
+export default Input;
diff --git a/components/forms/input/private/inner-input.jsx b/components/input/private/inner-input.jsx
similarity index 99%
rename from components/forms/input/private/inner-input.jsx
rename to components/input/private/inner-input.jsx
index 7e321d3f2b..30abc11404 100644
--- a/components/forms/input/private/inner-input.jsx
+++ b/components/input/private/inner-input.jsx
@@ -8,7 +8,7 @@ import React from 'react';
import PropTypes from 'prop-types';
import classNames from 'classnames';
-import Spinner from '../../../../components/spinner';
+import Spinner from '../../../components/spinner';
const propTypes = {
'aria-activedescendant': PropTypes.string,
diff --git a/components/input/search.jsx b/components/input/search.jsx
new file mode 100644
index 0000000000..0a59e09021
--- /dev/null
+++ b/components/input/search.jsx
@@ -0,0 +1,94 @@
+/* Copyright (c) 2015-present, salesforce.com, inc. All rights reserved */
+/* Licensed under BSD 3-Clause - see LICENSE.txt or git.io/sfdc-license */
+
+// # Search Component
+
+// Wraps the input to default to a search style.
+
+// ## Dependencies
+
+// ### React
+import React from 'react';
+import PropTypes from 'prop-types';
+
+// ## Children
+import Input from './index';
+import InputIcon from '../icon/input-icon';
+
+// ### Event Helpers
+import KEYS from '../../utilities/key-code';
+import EventUtil from '../../utilities/event';
+
+// ## Constants
+import { FORMS_SEARCH } from '../../utilities/constants';
+
+const handleKeyDown = (event, onSearch) => {
+ if (event.keyCode === KEYS.ENTER) {
+ EventUtil.trapImmediate(event);
+ onSearch(event);
+ }
+};
+
+/**
+ * A `Search` is an `Input` which renders the search icon by default. It can be cleared, too. All `Input` props not specified as props already may be used with this component and will override defaults.
+ */
+const Search = ({
+ assistiveText,
+ clearable,
+ onClear,
+ onSearch,
+ placeholder,
+ ...props
+}) => (
+
+ }
+ iconRight={
+ clearable ? (
+
+ ) : null
+ }
+ onKeyDown={onSearch ? (event) => handleKeyDown(event, onSearch) : null}
+ placeholder={placeholder}
+ {...props}
+ />
+);
+
+Search.displayName = FORMS_SEARCH;
+
+Search.propTypes = {
+ /**
+ * Assistive text to search input
+ */
+ assistiveText: PropTypes.string,
+ /**
+ * Adds a clear button to right side of the input
+ */
+ clearable: PropTypes.bool,
+ /**
+ * Triggers when the clear button is clicked
+ */
+ onClear: PropTypes.func,
+ /**
+ * This event fires when enter is pressed in the `input` or the search button is clicked.
+ */
+ onSearch: PropTypes.func,
+ /**
+ * Placeholder for the input
+ */
+ placeholder: PropTypes.string,
+};
+
+export default Search;
diff --git a/components/lookup/lookup.jsx b/components/lookup/lookup.jsx
index 2bf0123122..2427ae0983 100644
--- a/components/lookup/lookup.jsx
+++ b/components/lookup/lookup.jsx
@@ -28,7 +28,7 @@ import Dialog from '../utilities/dialog';
import Button from '../button';
import Icon from '../icon';
import InputIcon from '../icon/input-icon';
-import Input from '../forms/input';
+import Input from '../input';
// ### Event Helpers
import EventUtil from '../../utilities/event';
diff --git a/components/forms/radio/__examples__/default.jsx b/components/radio/__examples__/default.jsx
similarity index 76%
rename from components/forms/radio/__examples__/default.jsx
rename to components/radio/__examples__/default.jsx
index af537badde..b6cc1f2f51 100644
--- a/components/forms/radio/__examples__/default.jsx
+++ b/components/radio/__examples__/default.jsx
@@ -1,6 +1,6 @@
import React from 'react';
import createReactClass from 'create-react-class';
-import Radio from '~/components/forms/radio'; // `~` is replaced with design-system-react at runtime
+import Radio from '~/components/radio'; // `~` is replaced with design-system-react at runtime
const Example = createReactClass({
displayName: 'RadioExample',
diff --git a/components/forms/radio/__examples__/disabled.jsx b/components/radio/__examples__/disabled.jsx
similarity index 76%
rename from components/forms/radio/__examples__/disabled.jsx
rename to components/radio/__examples__/disabled.jsx
index 5805edd3f4..68bca27f04 100644
--- a/components/forms/radio/__examples__/disabled.jsx
+++ b/components/radio/__examples__/disabled.jsx
@@ -1,6 +1,6 @@
import React from 'react';
import createReactClass from 'create-react-class';
-import Radio from '~/components/forms/radio'; // `~` is replaced with design-system-react at runtime
+import Radio from '~/components/radio'; // `~` is replaced with design-system-react at runtime
const Example = createReactClass({
displayName: 'RadioExample',
diff --git a/components/radio/index.jsx b/components/radio/index.jsx
new file mode 100644
index 0000000000..3fa7f6533f
--- /dev/null
+++ b/components/radio/index.jsx
@@ -0,0 +1,114 @@
+/* Copyright (c) 2015-present, salesforce.com, inc. All rights reserved */
+/* Licensed under BSD 3-Clause - see LICENSE.txt or git.io/sfdc-license */
+
+import React from 'react';
+import PropTypes from 'prop-types';
+import shortid from 'shortid';
+import classNames from 'classnames';
+
+import { RADIO } from '../../utilities/constants';
+
+const propTypes = {
+ /**
+ * The ID of an element that describes this radio input. Often used for error messages.
+ */
+ 'aria-describedby': PropTypes.string,
+ /**
+ * This is a controlled component. This radio is checked according to this value.
+ */
+ checked: PropTypes.bool,
+ /**
+ * This is the initial value of an uncontrolled form element and is present only to provide compatibility
+ * with hybrid framework applications that are not entirely React. It should only be used in an application
+ * without centralized state (Redux, Flux). "Controlled components" with centralized state is highly recommended.
+ * See [Code Overview](https://github.com/salesforce/design-system-react/blob/master/docs/codebase-overview.md#controlled-and-uncontrolled-components) for more information.
+ */
+ defaultChecked: PropTypes.bool,
+ /**
+ * Disable this radio input.
+ */
+ disabled: PropTypes.bool,
+ /**
+ * A unique ID that is used to associating a label to the `input` element. This ID is added to the `input` element.
+ */
+ id: PropTypes.string,
+ /**
+ * The string or element that is shown as both the title and the label for this radio input.
+ */
+ label: PropTypes.oneOfType([PropTypes.string, PropTypes.element]).isRequired,
+ /**
+ * The name of the radio input group.
+ */
+ name: PropTypes.string,
+ /**
+ * This event fires when the radio selection changes.
+ */
+ onChange: PropTypes.func,
+ /**
+ * The value of this radio input.
+ */
+ value: PropTypes.string,
+ /**
+ * Variant of the Radio button. Base is the default and button-group makes the radio button look like a normal button (should be a child of ).
+ */
+ variant: PropTypes.oneOf(['base', 'button-group']),
+};
+
+const defaultProps = {
+ variant: 'base',
+};
+
+/**
+ * A radio input that can have a single input checked at any one time. Radios should be wrapped with
+ * a [RadioGroup](/components/radio-group) or [RadioButtonGroup](/components/radio-button-group)
+ */
+class Radio extends React.Component {
+ constructor (props) {
+ super(props);
+ this.generatedId = shortid.generate();
+ }
+
+ getId () {
+ return this.props.id || this.generatedId;
+ }
+
+ render () {
+ return (
+
+
+ {this.props.variant === 'button-group' ? (
+
+ ) : (
+
+ )}
+
+ );
+ }
+}
+
+Radio.displayName = RADIO;
+Radio.propTypes = propTypes;
+Radio.defaultProps = defaultProps;
+
+export default Radio;
diff --git a/components/site-stories.js b/components/site-stories.js
index 471b640681..af56418b23 100644
--- a/components/site-stories.js
+++ b/components/site-stories.js
@@ -21,8 +21,7 @@ const documentationSiteLiveExamples = {
'data-table': require('@salesforce/design-system-react/components/data-table/__docs__/site-stories.js'),
'date-picker': require('@salesforce/design-system-react/components/date-picker/__docs__/site-stories.js'),
icon: require('@salesforce/design-system-react/components/icon/__docs__/site-stories.js'),
- 'forms-input-inline': require('@salesforce/design-system-react/components/forms/input/__docs__/inline/site-stories.js'),
- 'forms-input': require('@salesforce/design-system-react/components/forms/input/__docs__/site-stories.js'),
+ input: require('@salesforce/design-system-react/components/input/__docs__/site-stories.js'),
'forms-textarea': require('@salesforce/design-system-react/components/forms/textarea/__docs__/site-stories.js'),
'global-header': require('@salesforce/design-system-react/components/global-header/__docs__/site-stories.js'),
'global-navigation-bar': require('@salesforce/design-system-react/components/global-navigation-bar/__docs__/site-stories.js'),
diff --git a/components/slider/__tests__/slider.browser-test.jsx b/components/slider/__tests__/slider.browser-test.jsx
index 7b48c9ccc9..d363e72845 100644
--- a/components/slider/__tests__/slider.browser-test.jsx
+++ b/components/slider/__tests__/slider.browser-test.jsx
@@ -203,7 +203,6 @@ describe('SLDSSlider', () => {
/>,
{ attachTo: mountNode }
);
-
const trigger = wrapper.find('input');
trigger.simulate('change', { target: { value: '300' } });
});
@@ -222,7 +221,6 @@ describe('SLDSSlider', () => {
/>,
{ attachTo: mountNode }
);
-
const trigger = wrapper.find('input');
trigger.simulate('input', { target: { value: '300' } });
});
diff --git a/components/story-based-tests.js b/components/story-based-tests.js
index d803c882d0..659257a804 100644
--- a/components/story-based-tests.js
+++ b/components/story-based-tests.js
@@ -24,15 +24,14 @@ export Accordion from '../components/accordion/__docs__/storybook-stories';
// export ButtonGroup from '../components/button-group/__docs__/storybook-stories';
// export ButtonStateful from '../components/button-stateful/__docs__/storybook-stories';
// export Card from '../components/card/__docs__/storybook-stories';
-// export Checkbox from '../components/forms/checkbox/__docs__/storybook-stories';
+// export Checkbox from '../components/checkbox/__docs__/storybook-stories';
// export Combobox from '../components/combobox/__docs__/storybook-stories';
// export Filter from '../components/filter/__docs__/storybook-stories';
// export DataTable from '../components/data-table/__docs__/storybook-stories';
// export Dropdown from '../components/menu-dropdown/__docs__/storybook-stories';
-// export Input from '../components/forms/input/__docs__/storybook-stories';
-// export Teaxtarea from '../components/forms/textarea/__docs__/storybook-stories';
-// export InlineInput from '../components/forms/input/__docs__/inline/storybook-stories';
-// export Search from '../components/forms/input/__docs__/search/storybook-stories';
+// export Input from '../components/input/__docs__/storybook-stories';
+// export Textarea from '../components/textarea/__docs__/storybook-stories';
+// export Search from '../components/input/__docs__/search/storybook-stories';
// export Icon from '../components/icon/__docs__/storybook-stories';
// export Lookup from '../components/lookup/__docs__/storybook-stories';
// export MediaObject from '../components/media-object/__docs__/storybook-stories';
diff --git a/components/storybook-stories.js b/components/storybook-stories.js
index 6b8cf90d81..4131264e99 100644
--- a/components/storybook-stories.js
+++ b/components/storybook-stories.js
@@ -19,7 +19,7 @@ export Button from '../components/button/__docs__/storybook-stories';
export ButtonGroup from '../components/button-group/__docs__/storybook-stories';
export ButtonStateful from '../components/button-stateful/__docs__/storybook-stories';
export Card from '../components/card/__docs__/storybook-stories';
-export Checkbox from '../components/forms/checkbox/__docs__/storybook-stories';
+export Checkbox from '../components/checkbox/__docs__/storybook-stories';
export Combobox from '../components/combobox/__docs__/storybook-stories';
export Filter from '../components/filter/__docs__/storybook-stories';
export GlobalNavigationBar from '../components/global-navigation-bar/__docs__/storybook-stories';
@@ -27,10 +27,10 @@ export DataTable from '../components/data-table/__docs__/storybook-stories';
export DatePicker from '../components/date-picker/__docs__/storybook-stories';
export Dropdown from '../components/menu-dropdown/__docs__/storybook-stories';
export IconSettings from '../components/icon-settings/__docs__/storybook-stories';
-export Input from '../components/forms/input/__docs__/storybook-stories';
-export Teaxtarea from '../components/forms/textarea/__docs__/storybook-stories';
+export Input from '../components/input/__docs__/storybook-stories';
+export Teaxtarea from '../components/textarea/__docs__/storybook-stories';
export InlineInput from '../components/forms/input/__docs__/inline/storybook-stories';
-export Search from '../components/forms/input/__docs__/search/storybook-stories';
+export Search from '../components/input/__docs__/search/storybook-stories';
export GlobalHeader from '../components/global-header/__docs__/storybook-stories';
export Icon from '../components/icon/__docs__/storybook-stories';
export Lookup from '../components/lookup/__docs__/storybook-stories';
diff --git a/components/tabs/__docs__/storybook-stories.jsx b/components/tabs/__docs__/storybook-stories.jsx
index d43f11cf3c..4e50a547f9 100644
--- a/components/tabs/__docs__/storybook-stories.jsx
+++ b/components/tabs/__docs__/storybook-stories.jsx
@@ -13,11 +13,11 @@ import Tabs from '../../tabs';
import Panel from '../../tabs/panel';
// Used in the Nested story
-import Input from '../../forms/input';
+import Input from '../../input';
import InputIcon from '../../icon/input-icon';
// Used in the Conditinal story
-import Checkbox from '../../forms/checkbox';
+import Checkbox from '../../checkbox';
// Used in the outside control story
import Button from '../../button';
diff --git a/components/forms/textarea/__docs__/site-stories.js b/components/textarea/__docs__/site-stories.js
similarity index 100%
rename from components/forms/textarea/__docs__/site-stories.js
rename to components/textarea/__docs__/site-stories.js
diff --git a/components/forms/textarea/__docs__/storybook-stories.jsx b/components/textarea/__docs__/storybook-stories.jsx
similarity index 89%
rename from components/forms/textarea/__docs__/storybook-stories.jsx
rename to components/textarea/__docs__/storybook-stories.jsx
index 0607612a91..1272816212 100644
--- a/components/forms/textarea/__docs__/storybook-stories.jsx
+++ b/components/textarea/__docs__/storybook-stories.jsx
@@ -1,8 +1,8 @@
import React from 'react';
import { storiesOf } from '@storybook/react';
-import IconSettings from '../../../icon-settings';
+import IconSettings from '../../icon-settings';
-import { FORMS_TEXTAREA } from '../../../../utilities/constants';
+import { FORMS_TEXTAREA } from '../../../utilities/constants';
import Textarea from '../';
storiesOf(FORMS_TEXTAREA, module)
diff --git a/components/forms/textarea/__examples__/default.jsx b/components/textarea/__examples__/default.jsx
similarity index 81%
rename from components/forms/textarea/__examples__/default.jsx
rename to components/textarea/__examples__/default.jsx
index a88b5f3c1d..f6e4132ac8 100644
--- a/components/forms/textarea/__examples__/default.jsx
+++ b/components/textarea/__examples__/default.jsx
@@ -1,7 +1,7 @@
import React from 'react';
import createReactClass from 'create-react-class';
import IconSettings from '~/components/icon-settings';
-import Textarea from '~/components/forms/textarea'; // `~` is replaced with design-system-react at runtime
+import Textarea from '~/components/textarea'; // `~` is replaced with design-system-react at runtime
const Example = createReactClass({
displayName: 'TextareaExample',
diff --git a/components/forms/textarea/__examples__/disabled.jsx b/components/textarea/__examples__/disabled.jsx
similarity index 83%
rename from components/forms/textarea/__examples__/disabled.jsx
rename to components/textarea/__examples__/disabled.jsx
index 45381ac94f..395ed54648 100644
--- a/components/forms/textarea/__examples__/disabled.jsx
+++ b/components/textarea/__examples__/disabled.jsx
@@ -1,7 +1,7 @@
import React from 'react';
import createReactClass from 'create-react-class';
import IconSettings from '~/components/icon-settings';
-import Textarea from '~/components/forms/textarea'; // `~` is replaced with design-system-react at runtime
+import Textarea from '~/components/textarea'; // `~` is replaced with design-system-react at runtime
const Example = createReactClass({
displayName: 'TextareaExample',
diff --git a/components/forms/textarea/__examples__/error.jsx b/components/textarea/__examples__/error.jsx
similarity index 84%
rename from components/forms/textarea/__examples__/error.jsx
rename to components/textarea/__examples__/error.jsx
index 3f8f610d08..dc4457f903 100644
--- a/components/forms/textarea/__examples__/error.jsx
+++ b/components/textarea/__examples__/error.jsx
@@ -1,7 +1,7 @@
import React from 'react';
import createReactClass from 'create-react-class';
import IconSettings from '~/components/icon-settings';
-import Textarea from '~/components/forms/textarea'; // `~` is replaced with design-system-react at runtime
+import Textarea from '~/components/textarea'; // `~` is replaced with design-system-react at runtime
const Example = createReactClass({
displayName: 'TextareaExample',
diff --git a/components/forms/textarea/__tests__/textarea.browser-test.jsx b/components/textarea/__tests__/textarea.browser-test.jsx
similarity index 100%
rename from components/forms/textarea/__tests__/textarea.browser-test.jsx
rename to components/textarea/__tests__/textarea.browser-test.jsx
diff --git a/components/forms/textarea/check-props.js b/components/textarea/check-props.js
similarity index 85%
rename from components/forms/textarea/check-props.js
rename to components/textarea/check-props.js
index e3a2cc7c5a..38ebf311be 100644
--- a/components/forms/textarea/check-props.js
+++ b/components/textarea/check-props.js
@@ -3,7 +3,7 @@
/* eslint-disable import/no-mutable-exports */
/* eslint-disable max-len */
-import onlyOneOfProperties from '../../../utilities/warning/only-one-of-properties';
+import onlyOneOfProperties from '../../utilities/warning/only-one-of-properties';
let checkProps = function () {};
diff --git a/components/textarea/index.jsx b/components/textarea/index.jsx
new file mode 100644
index 0000000000..e980022c25
--- /dev/null
+++ b/components/textarea/index.jsx
@@ -0,0 +1,333 @@
+/* Copyright (c) 2015-present, salesforce.com, inc. All rights reserved */
+/* Licensed under BSD 3-Clause - see LICENSE.txt or git.io/sfdc-license */
+
+/* eslint-disable jsx-a11y/no-autofocus */
+
+// # Textarea Component
+
+// Implements the [Textarea design pattern](https://lightningdesignsystem.com/components/textarea).
+// Based on SLDS v2.4.0
+//
+
+// ### React
+import React from 'react';
+import createReactClass from 'create-react-class';
+import PropTypes from 'prop-types';
+
+// ### classNames
+// [github.com/JedWatson/classnames](https://github.com/JedWatson/classnames)
+// This project uses `classnames`, "a simple javascript utility for conditionally
+// joining classNames together."
+import classNames from 'classnames';
+
+// ### shortid
+// [npmjs.com/package/shortid](https://www.npmjs.com/package/shortid)
+// shortid is a short, non-sequential, url-friendly, unique id generator
+import shortid from 'shortid';
+
+// ## Children
+// This component's `checkProps` which issues warnings to developers about properties when in development mode (similar to React's built in development tools)
+import checkProps from './check-props';
+
+import { FORMS_TEXTAREA } from '../../utilities/constants';
+
+/**
+ * A multi-line plain-text editing control.
+ */
+const Textarea = createReactClass({
+ displayName: FORMS_TEXTAREA,
+
+ propTypes: {
+ /**
+ * The aria-activedescendant attribute contains the ID of the currently active child object that is part of a composite widget within the Document Object Model. It makes do with the overhead of having all or more than one child focusable. As the name specifies, it helps in managing the current active child of the composite widget.
+ */
+ 'aria-activedescendant': PropTypes.string,
+ /**
+ * Indicates if the suggestions in a composite widget are values that complete the current textbox input.
+ */
+ 'aria-autocomplete': PropTypes.string,
+ /**
+ * An HTML ID that is shared with ARIA-supported devices with the
+ * `aria-controls` attribute in order to relate the input with
+ * another region of the page. An example would be a select box
+ * that shows or hides a panel.
+ */
+ 'aria-controls': PropTypes.string,
+ /**
+ * The `aria-describedby` attribute is used to indicate the IDs of the elements that describe the object. It is used to establish a relationship between widgets or groups and text that described them. This is very similar to aria-labelledby: a label describes the essence of an object, while a description provides more information that the user might need.
+ */
+ 'aria-describedby': PropTypes.string,
+ /**
+ * Use the `aria-expanded` state to indicate whether regions of the content are collapsible, and to expose whether a region is currently expanded or collapsed.
+ */
+ 'aria-expanded': PropTypes.bool,
+ /**
+ * Indicates that the element has a popup context menu or sub-level menu.
+ */
+ 'aria-haspopup': PropTypes.bool,
+ /**
+ * The aria-labelledby attribute contains the element IDs of labels in objects such as input elements, widgets, and groups. The attribute establishes relationships between objects and their labels. Assistive technology, such as screen readers, use this attribute to catalog the objects in a document so that users can navigate between them. Without an element ID, the assistive technology cannot catalog the object.
+ */
+ 'aria-labelledby': PropTypes.string,
+ /**
+ * An HTML ID that is shared with ARIA-supported devices with the
+ * `aria-controls` attribute in order to relate the input with
+ * another region of the page. An example would be a search field
+ * that shows search results.
+ */
+ 'aria-owns': PropTypes.string,
+ /**
+ * The `aria-required` attribute is used to indicate that user input is required on an element before a form can be submitted.
+ */
+ 'aria-required': PropTypes.bool,
+ /**
+ * Specifies is the textarea should automatically get focus when the page loads. This is typically a poor user experience.
+ */
+ autoFocus: PropTypes.bool,
+ /**
+ * If present, the label associated with this `textarea` is overwritten
+ * by this text and is visually not shown.
+ */
+ assistiveText: PropTypes.string,
+ /**
+ * Elements are added after the `textarea`.
+ */
+ children: PropTypes.node,
+ /**
+ * Class names to be added to the textarea component.
+ */
+ className: PropTypes.oneOfType([
+ PropTypes.array,
+ PropTypes.object,
+ PropTypes.string,
+ ]),
+ /** Allows for ability to apply classNames to outer textarea div.
+ */
+ classNameContainer: PropTypes.oneOfType([
+ PropTypes.array,
+ PropTypes.object,
+ PropTypes.string,
+ ]),
+ /**
+ * Disables the textarea and prevents editing the contents.
+ */
+ disabled: PropTypes.bool,
+ /**
+ * Message to display when the textarea is in an error state. When this is present, also visually highlights the component as in error.
+ */
+ errorText: PropTypes.string,
+ /**
+ * Every textarea must have a unique ID in order to support keyboard navigation and ARIA support.
+ */
+ id: PropTypes.string,
+ /**
+ * This callback exposes the textarea reference / DOM node to parent components. ` this.textarea = textareaComponent} />
+ */
+ textareaRef: PropTypes.func,
+ /**
+ * This label appears above the textarea.
+ */
+ label: PropTypes.string,
+ /**
+ * Triggered when focus is removed.
+ */
+ onBlur: PropTypes.func,
+ /**
+ * This callback fires when the textarea changes. The synthetic React event will be the first parameter to the callback. You will probably want to reference `event.target.value` in your callback. No custom data object is provided.
+ */
+ onChange: PropTypes.func,
+ /**
+ * This event fires when the textarea is clicked.
+ */
+ onClick: PropTypes.func,
+ /**
+ * Triggered when component is focused.
+ */
+ onFocus: PropTypes.func,
+ /**
+ * Similar to `onchange`. Triggered when an element gets user input.
+ */
+ onInput: PropTypes.func,
+ /**
+ * Triggered when a submittable element is invalid.
+ */
+ onInvalid: PropTypes.func,
+ /**
+ * Triggered when a key is pressed down
+ */
+ onKeyDown: PropTypes.func,
+ /**
+ * Triggered when a key is pressed and released
+ */
+ onKeyPress: PropTypes.func,
+ /**
+ * Triggered when a key is released
+ */
+ onKeyUp: PropTypes.func,
+ /**
+ * Triggered after some text has been selected in an element.
+ */
+ onSelect: PropTypes.func,
+ /**
+ * Fires when a form is submitted.
+ */
+ onSubmit: PropTypes.func,
+ /**
+ * Maximum number of characters allowed.
+ */
+ maxLength: PropTypes.string,
+ /**
+ * Name of the submitted form parameter.
+ */
+ name: PropTypes.string,
+ /**
+ * Text that will appear in an empty textarea.
+ */
+ placeholder: PropTypes.string,
+ /**
+ * Highlights the textarea as a required field (does not perform any validation).
+ */
+ required: PropTypes.bool,
+ /**
+ * The textarea is a controlled component, and will always display this value.
+ */
+ value: PropTypes.string,
+ /**
+ * The textarea is a uncontrolled component, and this will be the initial value.
+ */
+ defaultValue: PropTypes.string,
+ /**
+ * Specifies how the text in a text area is to be wrapped when submitted in a form.
+ */
+ wrap: PropTypes.oneOf(['soft', 'hard']),
+ },
+
+ componentWillMount () {
+ // `checkProps` issues warnings to developers about properties (similar to React's built in development tools)
+ checkProps(FORMS_TEXTAREA, this.props);
+
+ this.generatedId = shortid.generate();
+ if (this.props.errorText) {
+ this.generatedErrorId = shortid.generate();
+ }
+ },
+
+ getId () {
+ return this.props.id || this.generatedId;
+ },
+
+ getErrorId () {
+ return this.props['aria-describedby'] || this.generatedErrorId;
+ },
+
+ // ### Render
+ render () {
+ const {
+ autoFocus,
+ assistiveText,
+ children,
+ className,
+ classNameContainer,
+ disabled,
+ errorText,
+ textareaRef, // eslint-disable-line react/prop-types
+ label,
+ onBlur,
+ onChange,
+ onClick,
+ onFocus,
+ onInput,
+ onInvalid,
+ onKeyDown,
+ onKeyPress,
+ onKeyUp,
+ onSelect,
+ onSubmit,
+ maxLength,
+ name,
+ placeholder,
+ required,
+ role,
+ value,
+ defaultValue,
+ wrap,
+
+ // ### Additional properties
+ // Using [object destructuring](https://facebook.github.io/react/docs/transferring-props.html#transferring-with-...-in-jsx) to pass on any properties which are not explicitly defined.
+ // ...props // Uncomment this if you actually need to send the rest of the props to other elements
+ } = this.props;
+
+ const labelText = label || assistiveText; // One of these is required to pass accessibility tests
+
+ return (
+
+ {labelText && (
+
+ )}
+
+
+
+ {errorText && (
+
+ {errorText}
+
+ )}
+ {children}
+
+ );
+ },
+});
+
+export default Textarea;
diff --git a/components/time-picker/private/dropdown-trigger.jsx b/components/time-picker/private/dropdown-trigger.jsx
index fb3f6def63..67d7c22d4d 100644
--- a/components/time-picker/private/dropdown-trigger.jsx
+++ b/components/time-picker/private/dropdown-trigger.jsx
@@ -11,7 +11,7 @@ import createReactClass from 'create-react-class';
import PropTypes from 'prop-types';
// ### Children
-import Input from '../../forms/input';
+import Input from '../../input';
// ### Event Helpers
import KEYS from '../../../utilities/key-code';
diff --git a/components/tree/__docs__/storybook-stories.jsx b/components/tree/__docs__/storybook-stories.jsx
index 395b334d36..09f164400b 100644
--- a/components/tree/__docs__/storybook-stories.jsx
+++ b/components/tree/__docs__/storybook-stories.jsx
@@ -9,7 +9,7 @@ import { TREE } from '../../../utilities/constants';
import sampleNodes from '../../../utilities/sample-data/tree';
import Tree from '../../tree';
-import Search from '../../forms/input/search';
+import Search from '../../input/search';
const branchExpandClicked = action;
const itemClicked = action;
diff --git a/components/tree/__tests__/tree.browser-test.jsx b/components/tree/__tests__/tree.browser-test.jsx
index 0ffd806517..dc3a339a35 100644
--- a/components/tree/__tests__/tree.browser-test.jsx
+++ b/components/tree/__tests__/tree.browser-test.jsx
@@ -23,7 +23,7 @@ import sampleNodes from '../../../utilities/sample-data/tree';
import IconSettings from '../../icon-settings';
import Tree from '../../tree';
-import Search from '../../forms/input/search';
+import Search from '../../input/search';
chai.use(chaiEnzyme());
diff --git a/components/utilities/label/index.jsx b/components/utilities/label/index.jsx
new file mode 100644
index 0000000000..ca973aadf7
--- /dev/null
+++ b/components/utilities/label/index.jsx
@@ -0,0 +1,68 @@
+/* Copyright (c) 2015-present, salesforce.com, inc. All rights reserved */
+/* Licensed under BSD 3-Clause - see LICENSE.txt or git.io/sfdc-license */
+
+import React from 'react';
+import PropTypes from 'prop-types';
+import classNames from 'classnames';
+
+const propTypes = {
+ /*
+ * Assistive Text to use instead of a visible label
+ */
+ assistiveText: PropTypes.object,
+ /*
+ * Id of the input associated with this label
+ */
+ htmlFor: PropTypes.string,
+ /*
+ * Input Label
+ */
+ label: PropTypes.string,
+ /*
+ * Applies label styling for a required form element
+ */
+ required: PropTypes.bool,
+ /**
+ * Changes markup of label.
+ */
+ variant: PropTypes.oneOf(['base', 'static']),
+};
+
+const defaultProps = {
+ variant: 'base',
+};
+
+/*
+ * Form label. This returns null if there is no label text (hidden or shown)
+ */
+const Label = (props) => {
+ const labelText =
+ props.label || (props.assistiveText && props.assistiveText.label); // One of these is required to pass accessibility tests
+
+ const subRenders = {
+ base: (
+
+ ),
+ static: {labelText},
+ };
+
+ return labelText ? subRenders[props.variant] : null;
+};
+
+Label.displayName = 'Label';
+Label.propTypes = propTypes;
+Label.defaultProps = defaultProps;
+
+export default Label;
diff --git a/package.json b/package.json
index ce528d0d31..9c7ac5d278 100644
--- a/package.json
+++ b/package.json
@@ -312,14 +312,14 @@
]
},
{
- "component": "forms/checkbox",
+ "component": "checkbox",
"status": "prod",
"display-name": "Checkboxes",
"last-accessibility-review": {
"date-iso-8601": "2018/01/18",
"commit-sha": "ad6b6c6523ee21cada11be5f7ea4d99abc530726"
},
- "SLDS-component-path": "/components/forms/#flavor-checkbox"
+ "SLDS-component-path": "/components/checkbox/"
},
{
"component": "combobox",
@@ -373,34 +373,14 @@
"SLDS-component-path": "/components/filter"
},
{
- "component": "forms/input",
- "status": "prod",
- "display-name": "Inline Edit Inputs",
- "last-accessibility-review": {
- "date-iso-8601": "2017/08/21",
- "commit-sha": "119f7033c17a8a0634a31c6eeef947ddd0ee876b"
- },
- "last-slds-markup-review": {
- "date-iso-8601": "2017/08/21",
- "commit-sha": "119f7033c17a8a0634a31c6eeef947ddd0ee876b"
- },
- "SLDS-component-path": "/components/forms#flavor-input"
- },
- {
- "component": "forms/input",
+ "component": "input",
"status": "prod",
"display-name": "Inputs",
"last-accessibility-review": {
"date-iso-8601": "2017/09/22",
"commit-sha": "ad6b6c6523ee21cada11be5f7ea4d99abc530726"
},
- "SLDS-component-path": "/components/forms#flavor-input"
- },
- {
- "component": "forms/textarea",
- "status": "prod",
- "display-name": "Textareas",
- "SLDS-component-path": "/components/forms#flavor-textarea"
+ "SLDS-component-path": "/components/input/"
},
{
"component": "global-header",
@@ -562,14 +542,14 @@
"SLDS-component-path": "/components/progress-ring"
},
{
- "component": "forms/radio",
+ "component": "radio",
"status": "prod",
"display-name": "Radios",
"last-accessibility-review": {
"date-iso-8601": "2018/01/18",
"commit-sha": "ad6b6c6523ee21cada11be5f7ea4d99abc530726"
},
- "SLDS-component-path": "/components/forms/#flavor-radio"
+ "SLDS-component-path": "/components/radio-group/"
},
{
"component": "split-view",
@@ -614,10 +594,10 @@
"SLDS-component-path": "/components/radio-button-group"
},
{
- "component": "tooltip",
+ "component": "slider",
"status": "prod",
- "display-name": "Tooltips",
- "SLDS-component-path": "/components/tooltips"
+ "display-name": "Slider",
+ "SLDS-component-path": "/components/slider"
},
{
"component": "tabs",
@@ -634,6 +614,18 @@
}
]
},
+ {
+ "component": "textarea",
+ "status": "prod",
+ "display-name": "Textareas",
+ "SLDS-component-path": "/components/forms#flavor-textarea"
+ },
+ {
+ "component": "time-picker",
+ "status": "prod",
+ "display-name": "Timepickers",
+ "SLDS-component-path": "/components/datepickers"
+ },
{
"component": "toast",
"status": "prod",
@@ -649,6 +641,12 @@
}
]
},
+ {
+ "component": "tooltip",
+ "status": "prod",
+ "display-name": "Tooltips",
+ "SLDS-component-path": "/components/tooltips"
+ },
{
"component": "tree",
"status": "prod",
@@ -662,18 +660,6 @@
"commit-sha": "5fdeb31982a42cbd37a70d96d6257142cd7eec72"
},
"SLDS-component-path": "/components/tree"
- },
- {
- "component": "time-picker",
- "status": "prod",
- "display-name": "Timepickers",
- "SLDS-component-path": "/components/datepickers"
- },
- {
- "component": "slider",
- "status": "prod",
- "display-name": "Slider",
- "SLDS-component-path": "/components/slider"
}
],
"documentation": {
diff --git a/utilities/warning/deprecated-event-parameter.js b/utilities/warning/deprecated-event-parameter.js
new file mode 100644
index 0000000000..8cbd5f50ae
--- /dev/null
+++ b/utilities/warning/deprecated-event-parameter.js
@@ -0,0 +1,45 @@
+/* Copyright (c) 2015-present, salesforce.com, inc. All rights reserved */
+/* Licensed under BSD 3-Clause - see LICENSE.txt or git.io/sfdc-license */
+
+/* eslint-disable import/no-mutable-exports */
+/* eslint-disable max-len */
+
+// This function will deliver a warning message to the browser console about an event parameter change.
+import lowPriorityWarning from './low-priority-warning';
+
+let deprecated = function () {};
+
+if (process.env.NODE_ENV !== 'production') {
+ const hasWarned = {};
+
+ deprecated = function (
+ control,
+ {
+ oldEventParameterOrder, // flag that tells which parameter order is in use
+ propAsString, // key name of prop being warned about
+ log, // log function that will disable console warning and pipe to another function log({ message })
+ },
+ comment
+ ) {
+ const additionalComment = comment ? ` ${comment}` : '';
+ const warnOnFirstOccurrenceKey = control + propAsString;
+ const triggerWarning = oldEventParameterOrder !== undefined;
+
+ if (!hasWarned[warnOnFirstOccurrenceKey]) {
+ const message = `[Design System React] ${additionalComment}`;
+
+ if (triggerWarning && log) {
+ log({ message });
+ } else {
+ lowPriorityWarning(
+ !triggerWarning, // false value triggers warning
+ message
+ );
+ }
+ // store global flag to limit warnings to first issue
+ hasWarned[warnOnFirstOccurrenceKey] = triggerWarning;
+ }
+ };
+}
+
+export default deprecated;
diff --git a/utilities/warning/low-priority-warning.js b/utilities/warning/low-priority-warning.js
index 81e77138e8..668e54d66c 100644
--- a/utilities/warning/low-priority-warning.js
+++ b/utilities/warning/low-priority-warning.js
@@ -23,7 +23,7 @@ if (process.env.NODE_ENV !== 'production') {
};
lowPriorityWarning = (condition, originalMessage, ...args) => {
- if (originalMessage) {
+ if (!condition && originalMessage) {
printWarning(originalMessage, ...args);
}
};
From 6de84ad3cb61a9e17b94e98ee8fc113927227cf0 Mon Sep 17 00:00:00 2001
From: Stephen James
Date: Fri, 8 Jun 2018 17:02:44 -0600
Subject: [PATCH 2/2] Checkbox: Checkprops warning typo
---
components/checkbox/check-props.js | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/components/checkbox/check-props.js b/components/checkbox/check-props.js
index 16a20db239..6c21d938b9 100644
--- a/components/checkbox/check-props.js
+++ b/components/checkbox/check-props.js
@@ -17,7 +17,7 @@ if (process.env.NODE_ENV !== 'production') {
propAsString: 'onChange',
propAsValue: props.onChange,
},
- '`components/forms/checkbox` is deprecated. `components/checkbox` should be used. When this path update is made `onChange` event parameters will change from `onChange(value, event, { value } to `onChange(event, { value }). Please update your event parameters when you change paths.` If you are using the CommonJS named import, `Checkbox` events will break at v1.0 and this warning will be present until then. Please review https://github.com/salesforce/design-system-react/releases when you upgrade.'
+ '`components/forms/checkbox` is deprecated. `components/checkbox` should be used. When this path update is made `onChange` event parameters will change from `onChange(value, event, { value }) to `onChange(event, { value }). Please update your event parameters when you change paths.` If you are using the CommonJS named import, `Checkbox` events will break at v1.0 and this warning will be present until then. Please review https://github.com/salesforce/design-system-react/releases when you upgrade.'
);
if (props.variant === 'toggle' && props.indeterminate === true) {