diff --git a/components/combobox/__docs__/__snapshots__/storybook-stories.storyshot b/components/combobox/__docs__/__snapshots__/storybook-stories.storyshot index b9928ce753..36c8395cb6 100644 --- a/components/combobox/__docs__/__snapshots__/storybook-stories.storyshot +++ b/components/combobox/__docs__/__snapshots__/storybook-stories.storyshot @@ -4089,6 +4089,87 @@ exports[`DOM snapshots SLDSCombobox Inline Single Selection 1`] = ` `; +exports[`DOM snapshots SLDSCombobox Inline Single Selection Invalid 1`] = ` +
+
+ +
+
+
+
+ + + + +
+
+
+
+
+ This field is invalid +
+
+
+
+
+`; + exports[`DOM snapshots SLDSCombobox Inline Single Selection Predefined Options Only 1`] = `
`; +exports[`DOM snapshots SLDSCombobox Snapshot Inline Single Selection Invalid 1`] = ` +
+
+ +
+
+
+
+ + + + +
+
+
+
+
+ This field is invalid +
+
+
+
+
+`; + exports[`DOM snapshots SLDSCombobox Snapshot Inline Single Selection Selected 1`] = `
( )) + .add('Inline Single Selection Invalid', () => ( + + )) .add('Inline Single Selection With Custom Open State', () => ( )) @@ -161,6 +166,9 @@ storiesOf(COMBOBOX, module) )) .add('Snapshot Dialog Open', () => ) + .add('Snapshot Inline Single Selection Invalid', () => ( + + )) .add('Snapshot Inline Single Selection', () => ( )) diff --git a/components/combobox/__examples__/inline-single-invalid.jsx b/components/combobox/__examples__/inline-single-invalid.jsx new file mode 100644 index 0000000000..83facef9ee --- /dev/null +++ b/components/combobox/__examples__/inline-single-invalid.jsx @@ -0,0 +1,161 @@ +/* eslint-disable no-console, react/prop-types */ +import React from 'react'; +import Combobox from '~/components/combobox'; +import Icon from '~/components/icon'; +import comboboxFilterAndLimit from '~/components/combobox/filter'; +import IconSettings from '~/components/icon-settings'; + +const accounts = [ + { + id: '1', + label: 'Acme', + subTitle: 'Account • San Francisco', + type: 'account', + }, + { + id: '2', + label: 'Salesforce.com, Inc.', + subTitle: 'Account • San Francisco', + type: 'account', + }, + { + id: '3', + label: "Paddy's Pub", + subTitle: 'Account • Boston, MA', + type: 'account', + }, + { + id: '4', + label: 'Tyrell Corp', + subTitle: 'Account • San Francisco, CA', + type: 'account', + }, + { + id: '5', + label: 'Paper St. Soap Company', + subTitle: 'Account • Beloit, WI', + type: 'account', + }, + { + id: '6', + label: 'Nakatomi Investments', + subTitle: 'Account • Chicago, IL', + type: 'account', + }, + { id: '7', label: 'Acme Landscaping', type: 'account' }, + { + id: '8', + label: 'Acme Construction', + subTitle: 'Account • Grand Marais, MN', + type: 'account', + }, +]; + +const accountsWithIcon = accounts.map((elem) => ({ + ...elem, + ...{ + icon: ( + + ), + }, +})); + +class Example extends React.Component { + constructor(props) { + super(props); + + this.state = { + inputValue: '', + selection: [], + }; + } + + render() { + return ( + + { + if (this.props.action) { + this.props.action('onChange')(event, value); + } else if (console) { + console.log('onChange', event, value); + } + this.setState({ inputValue: value }); + }, + onRequestRemoveSelectedOption: (event, data) => { + this.setState({ + inputValue: '', + selection: data.selection, + }); + }, + onSubmit: (event, { value }) => { + if (this.props.action) { + this.props.action('onChange')(event, value); + } else if (console) { + console.log('onChange', event, value); + } + this.setState({ + inputValue: '', + selection: [ + ...this.state.selection, + { + label: value, + icon: ( + + ), + }, + ], + }); + }, + onSelect: (event, data) => { + if (this.props.action) { + this.props.action('onSelect')( + event, + ...Object.keys(data).map((key) => data[key]) + ); + } else if (console) { + console.log('onSelect', event, data); + } + this.setState({ + inputValue: '', + selection: data.selection, + }); + }, + }} + labels={{ + label: 'Search', + placeholder: 'Search Salesforce', + }} + options={comboboxFilterAndLimit({ + inputValue: this.state.inputValue, + options: accountsWithIcon, + selection: this.state.selection, + })} + selection={this.state.selection} + value={ + this.state.selectedOption + ? this.state.selectedOption.label + : this.state.inputValue + } + required + errorText="This field is invalid" + variant="inline-listbox" + /> + + ); + } +} + +Example.displayName = 'ComboboxExample'; +export default Example; // export is replaced with `ReactDOM.render(, mountNode);` at runtime diff --git a/components/combobox/__examples__/snapshot/inline-single-invalid.jsx b/components/combobox/__examples__/snapshot/inline-single-invalid.jsx new file mode 100644 index 0000000000..83facef9ee --- /dev/null +++ b/components/combobox/__examples__/snapshot/inline-single-invalid.jsx @@ -0,0 +1,161 @@ +/* eslint-disable no-console, react/prop-types */ +import React from 'react'; +import Combobox from '~/components/combobox'; +import Icon from '~/components/icon'; +import comboboxFilterAndLimit from '~/components/combobox/filter'; +import IconSettings from '~/components/icon-settings'; + +const accounts = [ + { + id: '1', + label: 'Acme', + subTitle: 'Account • San Francisco', + type: 'account', + }, + { + id: '2', + label: 'Salesforce.com, Inc.', + subTitle: 'Account • San Francisco', + type: 'account', + }, + { + id: '3', + label: "Paddy's Pub", + subTitle: 'Account • Boston, MA', + type: 'account', + }, + { + id: '4', + label: 'Tyrell Corp', + subTitle: 'Account • San Francisco, CA', + type: 'account', + }, + { + id: '5', + label: 'Paper St. Soap Company', + subTitle: 'Account • Beloit, WI', + type: 'account', + }, + { + id: '6', + label: 'Nakatomi Investments', + subTitle: 'Account • Chicago, IL', + type: 'account', + }, + { id: '7', label: 'Acme Landscaping', type: 'account' }, + { + id: '8', + label: 'Acme Construction', + subTitle: 'Account • Grand Marais, MN', + type: 'account', + }, +]; + +const accountsWithIcon = accounts.map((elem) => ({ + ...elem, + ...{ + icon: ( + + ), + }, +})); + +class Example extends React.Component { + constructor(props) { + super(props); + + this.state = { + inputValue: '', + selection: [], + }; + } + + render() { + return ( + + { + if (this.props.action) { + this.props.action('onChange')(event, value); + } else if (console) { + console.log('onChange', event, value); + } + this.setState({ inputValue: value }); + }, + onRequestRemoveSelectedOption: (event, data) => { + this.setState({ + inputValue: '', + selection: data.selection, + }); + }, + onSubmit: (event, { value }) => { + if (this.props.action) { + this.props.action('onChange')(event, value); + } else if (console) { + console.log('onChange', event, value); + } + this.setState({ + inputValue: '', + selection: [ + ...this.state.selection, + { + label: value, + icon: ( + + ), + }, + ], + }); + }, + onSelect: (event, data) => { + if (this.props.action) { + this.props.action('onSelect')( + event, + ...Object.keys(data).map((key) => data[key]) + ); + } else if (console) { + console.log('onSelect', event, data); + } + this.setState({ + inputValue: '', + selection: data.selection, + }); + }, + }} + labels={{ + label: 'Search', + placeholder: 'Search Salesforce', + }} + options={comboboxFilterAndLimit({ + inputValue: this.state.inputValue, + options: accountsWithIcon, + selection: this.state.selection, + })} + selection={this.state.selection} + value={ + this.state.selectedOption + ? this.state.selectedOption.label + : this.state.inputValue + } + required + errorText="This field is invalid" + variant="inline-listbox" + /> + + ); + } +} + +Example.displayName = 'ComboboxExample'; +export default Example; // export is replaced with `ReactDOM.render(, mountNode);` at runtime diff --git a/components/combobox/combobox.jsx b/components/combobox/combobox.jsx index 41cffc80a2..0cf2e699b3 100644 --- a/components/combobox/combobox.jsx +++ b/components/combobox/combobox.jsx @@ -1439,13 +1439,15 @@ class Combobox extends React.Component { {this.getDialog({ menuRenderer: this.renderMenu({ assistiveText, labels }), })} - {props.errorText && ( -
- {props.errorText} -
- )}
+ {props.errorText && ( +
+
+ {props.errorText} +
+
+ )} ); }; diff --git a/components/combobox/component.json b/components/combobox/component.json index 06fe7d5647..7ef8e1014c 100644 --- a/components/combobox/component.json +++ b/components/combobox/component.json @@ -37,6 +37,10 @@ "heading": "Inline single selection", "path": "/__examples__/inline-single.jsx" }, + { + "heading": "Inline single selection invalid", + "path": "/__examples__/inline-single-invalid.jsx" + }, { "heading": "Inline: Single Selection with Entity Selection", "path": "/__examples__/inline-single-entity-combobox.jsx" diff --git a/components/site-stories.js b/components/site-stories.js index a847f34b69..0fc4825dd4 100644 --- a/components/site-stories.js +++ b/components/site-stories.js @@ -253,6 +253,10 @@ const documentationSiteLiveExamples = { heading: 'Inline single selection', path: require('raw-loader!@salesforce/design-system-react/components/combobox/__examples__/inline-single.jsx'), }, + { + heading: 'Inline single selection invalid', + path: require('raw-loader!@salesforce/design-system-react/components/combobox/__examples__/inline-single-invalid.jsx'), + }, { heading: 'Inline: Single Selection with Entity Selection', path: require('raw-loader!@salesforce/design-system-react/components/combobox/__examples__/inline-single-entity-combobox.jsx'), diff --git a/package.json b/package.json index 0ae11244db..4b45b37993 100644 --- a/package.json +++ b/package.json @@ -696,6 +696,10 @@ "heading": "Inline single selection", "path": "/__examples__/inline-single.jsx" }, + { + "heading": "Inline single selection invalid", + "path": "/__examples__/inline-single-invalid.jsx" + }, { "heading": "Inline: Single Selection with Entity Selection", "path": "/__examples__/inline-single-entity-combobox.jsx" @@ -822,6 +826,24 @@ ], "url-slug": "date-pickers" }, + { + "component": "docked-composer", + "status": "prod", + "display-name": "Docked Composers", + "classKey": "DockedComposer", + "SLDS-component-path": "/components/docked-composer", + "site-stories": [ + { + "heading": "Default", + "path": "/__examples__/base.jsx" + }, + { + "heading": "Minimized", + "path": "/__examples__/minimized.jsx" + } + ], + "url-slug": "docked-composers" + }, { "component": "dynamic-icon", "status": "prod",