;
+
+export const Default: Story = {
+ render: DefaultExample,
+};
+
+export const DefaultWithSimpleOptions: Story = {
+ render: DefaultWithSimpleOptionsExample,
+};
+
+export const DefaultWithCustomOptions: Story = {
+ render: DefaultWithCustomOptionsExample,
+};
+
+export const Scrollable: Story = {
+ render: ScrollableExample,
+};
+
+export const Disabled: Story = {
+ render: DisabledExample,
+};
+
+export const Alert: Story = {
+ render: AlertExample,
+};
+
+export const Error: Story = {
+ render: ErrorExample,
+};
+
+export const Grow: Story = {
+ render: GrowExample,
+};
+
+export const DefaultLeft: Story = {
+ render: DefaultLeftExample,
+};
+
+export const DefaultWithSimpleOptionsLeft: Story = {
+ render: DefaultWithSimpleOptionsExampleLeft,
+};
+
+export const DefaultWithCustomOptionsLeft: Story = {
+ render: DefaultWithCustomOptionsExampleLeft,
+};
+
+export const ScrollableLeft: Story = {
+ render: ScrollableExampleLeft,
+};
+
+export const DisabledLeft: Story = {
+ render: DisabledExampleLeft,
+};
+
+export const AlertLeft: Story = {
+ render: AlertExampleLeft,
+};
+
+export const ErrorLeft: Story = {
+ render: ErrorExampleLeft,
+};
+
+export const GrowLeft: Story = {
+ render: GrowExampleLeft,
+};
diff --git a/modules/preview-react/select/stories/examples/Left Label/AlertLeft.tsx b/modules/preview-react/select/stories/examples/Left Label/AlertLeft.tsx
new file mode 100644
index 0000000000..aa92ff5656
--- /dev/null
+++ b/modules/preview-react/select/stories/examples/Left Label/AlertLeft.tsx
@@ -0,0 +1,21 @@
+import React from 'react';
+
+import {FormField} from '@workday/canvas-kit-react/form-field';
+import {Select} from '@workday/canvas-kit-preview-react/select';
+import {hintId, hintText, options} from '../storiesData';
+import {controlComponent} from '../../../../../../utils/storybook';
+
+export const AlertLeft = () => {
+ return (
+
+ {controlComponent()}
+
+ );
+};
diff --git a/modules/preview-react/select/stories/examples/Left Label/DefaultLeft.tsx b/modules/preview-react/select/stories/examples/Left Label/DefaultLeft.tsx
new file mode 100644
index 0000000000..42adaf6f4d
--- /dev/null
+++ b/modules/preview-react/select/stories/examples/Left Label/DefaultLeft.tsx
@@ -0,0 +1,14 @@
+import React from 'react';
+
+import {FormField} from '@workday/canvas-kit-react/form-field';
+import {Select} from '@workday/canvas-kit-preview-react/select';
+import {options} from '../storiesData';
+import {controlComponent} from '../../../../../../utils/storybook';
+
+export const DefaultLeft = () => {
+ return (
+
+ {controlComponent()}
+
+ );
+};
diff --git a/modules/preview-react/select/stories/examples/Left Label/DefaultWithCustomOptionsLeft.tsx b/modules/preview-react/select/stories/examples/Left Label/DefaultWithCustomOptionsLeft.tsx
new file mode 100644
index 0000000000..582e9e36ed
--- /dev/null
+++ b/modules/preview-react/select/stories/examples/Left Label/DefaultWithCustomOptionsLeft.tsx
@@ -0,0 +1,25 @@
+import React from 'react';
+
+import {FormField} from '@workday/canvas-kit-react/form-field';
+import {Select} from '@workday/canvas-kit-preview-react/select';
+import {customOptions, customRenderOption, customRenderSelected} from '../storiesData';
+import {controlComponent} from '../../../../../../utils/storybook';
+
+export const DefaultWithCustomOptionsLeft = () => {
+ return (
+
+ {controlComponent(
+
+ )}
+
+ );
+};
diff --git a/modules/preview-react/select/stories/examples/Left Label/DefaultWithSimpleOptionsLeft.tsx b/modules/preview-react/select/stories/examples/Left Label/DefaultWithSimpleOptionsLeft.tsx
new file mode 100644
index 0000000000..c64c9a410d
--- /dev/null
+++ b/modules/preview-react/select/stories/examples/Left Label/DefaultWithSimpleOptionsLeft.tsx
@@ -0,0 +1,18 @@
+import React from 'react';
+
+import {FormField} from '@workday/canvas-kit-react/form-field';
+import {Select} from '@workday/canvas-kit-preview-react/select';
+import {simpleOptions} from '../storiesData';
+import {controlComponent} from '../../../../../../utils/storybook';
+
+export const DefaultWithSimpleOptionsLeft = () => {
+ return (
+
+ {controlComponent()}
+
+ );
+};
diff --git a/modules/preview-react/select/stories/examples/Left Label/DisabledLeft.tsx b/modules/preview-react/select/stories/examples/Left Label/DisabledLeft.tsx
new file mode 100644
index 0000000000..d63fec11f4
--- /dev/null
+++ b/modules/preview-react/select/stories/examples/Left Label/DisabledLeft.tsx
@@ -0,0 +1,14 @@
+import React from 'react';
+
+import {FormField} from '@workday/canvas-kit-react/form-field';
+import {Select} from '@workday/canvas-kit-preview-react/select';
+import {options} from '../storiesData';
+import {controlComponent} from '../../../../../../utils/storybook';
+
+export const DisabledLeft = () => {
+ return (
+
+ {controlComponent()}
+
+ );
+};
diff --git a/modules/preview-react/select/stories/examples/Left Label/ErrorLeft.tsx b/modules/preview-react/select/stories/examples/Left Label/ErrorLeft.tsx
new file mode 100644
index 0000000000..6a4d1bd2e9
--- /dev/null
+++ b/modules/preview-react/select/stories/examples/Left Label/ErrorLeft.tsx
@@ -0,0 +1,21 @@
+import React from 'react';
+
+import {FormField} from '@workday/canvas-kit-react/form-field';
+import {Select} from '@workday/canvas-kit-preview-react/select';
+import {hintId, hintText, options} from '../storiesData';
+import {controlComponent} from '../../../../../../utils/storybook';
+
+export const ErrorLeft = () => {
+ return (
+
+ {controlComponent()}
+
+ );
+};
diff --git a/modules/preview-react/select/stories/examples/Left Label/GrowLeft.tsx b/modules/preview-react/select/stories/examples/Left Label/GrowLeft.tsx
new file mode 100644
index 0000000000..24ca4376d3
--- /dev/null
+++ b/modules/preview-react/select/stories/examples/Left Label/GrowLeft.tsx
@@ -0,0 +1,19 @@
+import React from 'react';
+
+import {FormField} from '@workday/canvas-kit-react/form-field';
+import {Select} from '@workday/canvas-kit-preview-react/select';
+import {options} from '../storiesData';
+import {controlComponent} from '../../../../../../utils/storybook';
+
+export const GrowLeft = () => {
+ return (
+
+ {controlComponent()}
+
+ );
+};
diff --git a/modules/preview-react/select/stories/examples/Left Label/ScrollableLeft.tsx b/modules/preview-react/select/stories/examples/Left Label/ScrollableLeft.tsx
new file mode 100644
index 0000000000..5837ab50d3
--- /dev/null
+++ b/modules/preview-react/select/stories/examples/Left Label/ScrollableLeft.tsx
@@ -0,0 +1,14 @@
+import React from 'react';
+
+import {FormField} from '@workday/canvas-kit-react/form-field';
+import {Select} from '@workday/canvas-kit-preview-react/select';
+import {manyOptions} from '../storiesData';
+import {controlComponent} from '../../../../../../utils/storybook';
+
+export const ScrollableLeft = () => {
+ return (
+
+ {controlComponent()}
+
+ );
+};
diff --git a/modules/preview-react/select/stories/examples/Left Label/index.ts b/modules/preview-react/select/stories/examples/Left Label/index.ts
new file mode 100644
index 0000000000..108704197a
--- /dev/null
+++ b/modules/preview-react/select/stories/examples/Left Label/index.ts
@@ -0,0 +1,8 @@
+export {DefaultLeft} from './DefaultLeft';
+export {DefaultWithCustomOptionsLeft} from './DefaultWithCustomOptionsLeft';
+export {DefaultWithSimpleOptionsLeft} from './DefaultWithSimpleOptionsLeft';
+export {ScrollableLeft} from './ScrollableLeft';
+export {DisabledLeft} from './DisabledLeft';
+export {AlertLeft} from './AlertLeft';
+export {ErrorLeft} from './ErrorLeft';
+export {GrowLeft} from './GrowLeft';
diff --git a/modules/preview-react/select/stories/examples/Top Label/Alert.tsx b/modules/preview-react/select/stories/examples/Top Label/Alert.tsx
new file mode 100644
index 0000000000..fcfe8dd510
--- /dev/null
+++ b/modules/preview-react/select/stories/examples/Top Label/Alert.tsx
@@ -0,0 +1,20 @@
+import React from 'react';
+
+import {FormField} from '@workday/canvas-kit-react/form-field';
+import {Select} from '@workday/canvas-kit-preview-react/select';
+import {hintId, hintText, options} from '../storiesData';
+import {controlComponent} from '../../../../../../utils/storybook';
+
+export const Alert = () => {
+ return (
+
+ {controlComponent()}
+
+ );
+};
diff --git a/modules/preview-react/select/stories/examples/Top Label/Default.tsx b/modules/preview-react/select/stories/examples/Top Label/Default.tsx
new file mode 100644
index 0000000000..6997bb8c79
--- /dev/null
+++ b/modules/preview-react/select/stories/examples/Top Label/Default.tsx
@@ -0,0 +1,14 @@
+import React from 'react';
+
+import {FormField} from '@workday/canvas-kit-react/form-field';
+import {Select} from '@workday/canvas-kit-preview-react/select';
+import {options} from '../storiesData';
+import {controlComponent} from '../../../../../../utils/storybook';
+
+export const Default = () => {
+ return (
+
+ {controlComponent()}
+
+ );
+};
diff --git a/modules/preview-react/select/stories/examples/Top Label/DefaultWithCustomOptions.tsx b/modules/preview-react/select/stories/examples/Top Label/DefaultWithCustomOptions.tsx
new file mode 100644
index 0000000000..be7563091b
--- /dev/null
+++ b/modules/preview-react/select/stories/examples/Top Label/DefaultWithCustomOptions.tsx
@@ -0,0 +1,21 @@
+import React from 'react';
+
+import {FormField} from '@workday/canvas-kit-react/form-field';
+import {Select} from '@workday/canvas-kit-preview-react/select';
+import {customOptions, customRenderOption, customRenderSelected} from '../storiesData';
+import {controlComponent} from '../../../../../../utils/storybook';
+
+export const DefaultWithCustomOptions = () => {
+ return (
+
+ {controlComponent(
+
+ )}
+
+ );
+};
diff --git a/modules/preview-react/select/stories/examples/Top Label/DefaultWithSimpleOptions.tsx b/modules/preview-react/select/stories/examples/Top Label/DefaultWithSimpleOptions.tsx
new file mode 100644
index 0000000000..a96e4143fa
--- /dev/null
+++ b/modules/preview-react/select/stories/examples/Top Label/DefaultWithSimpleOptions.tsx
@@ -0,0 +1,14 @@
+import React from 'react';
+
+import {FormField} from '@workday/canvas-kit-react/form-field';
+import {Select} from '@workday/canvas-kit-preview-react/select';
+import {simpleOptions} from '../storiesData';
+import {controlComponent} from '../../../../../../utils/storybook';
+
+export const DefaultWithSimpleOptions = () => {
+ return (
+
+ {controlComponent()}
+
+ );
+};
diff --git a/modules/preview-react/select/stories/examples/Top Label/Disabled.tsx b/modules/preview-react/select/stories/examples/Top Label/Disabled.tsx
new file mode 100644
index 0000000000..a5246b5c6f
--- /dev/null
+++ b/modules/preview-react/select/stories/examples/Top Label/Disabled.tsx
@@ -0,0 +1,14 @@
+import React from 'react';
+
+import {FormField} from '@workday/canvas-kit-react/form-field';
+import {Select} from '@workday/canvas-kit-preview-react/select';
+import {options} from '../storiesData';
+import {controlComponent} from '../../../../../../utils/storybook';
+
+export const Disabled = () => {
+ return (
+
+ {controlComponent()}
+
+ );
+};
diff --git a/modules/preview-react/select/stories/examples/Top Label/Error.tsx b/modules/preview-react/select/stories/examples/Top Label/Error.tsx
new file mode 100644
index 0000000000..79cb31b51b
--- /dev/null
+++ b/modules/preview-react/select/stories/examples/Top Label/Error.tsx
@@ -0,0 +1,20 @@
+import React from 'react';
+
+import {FormField} from '@workday/canvas-kit-react/form-field';
+import {Select} from '@workday/canvas-kit-preview-react/select';
+import {hintId, hintText, options} from '../storiesData';
+import {controlComponent} from '../../../../../../utils/storybook';
+
+export const Error = () => {
+ return (
+
+ {controlComponent()}
+
+ );
+};
diff --git a/modules/preview-react/select/stories/examples/Top Label/Grow.tsx b/modules/preview-react/select/stories/examples/Top Label/Grow.tsx
new file mode 100644
index 0000000000..c8a5a61a70
--- /dev/null
+++ b/modules/preview-react/select/stories/examples/Top Label/Grow.tsx
@@ -0,0 +1,14 @@
+import React from 'react';
+
+import {FormField} from '@workday/canvas-kit-react/form-field';
+import {Select} from '@workday/canvas-kit-preview-react/select';
+import {options} from '../storiesData';
+import {controlComponent} from '../../../../../../utils/storybook';
+
+export const Grow = () => {
+ return (
+
+ {controlComponent()}
+
+ );
+};
diff --git a/modules/preview-react/select/stories/examples/Top Label/Scrollable.tsx b/modules/preview-react/select/stories/examples/Top Label/Scrollable.tsx
new file mode 100644
index 0000000000..a4c2f7bb2a
--- /dev/null
+++ b/modules/preview-react/select/stories/examples/Top Label/Scrollable.tsx
@@ -0,0 +1,14 @@
+import React from 'react';
+
+import {FormField} from '@workday/canvas-kit-react/form-field';
+import {Select} from '@workday/canvas-kit-preview-react/select';
+import {manyOptions} from '../storiesData';
+import {controlComponent} from '../../../../../../utils/storybook';
+
+export const Scrollable = () => {
+ return (
+
+ {controlComponent()}
+
+ );
+};
diff --git a/modules/preview-react/select/stories/examples/Top Label/index.ts b/modules/preview-react/select/stories/examples/Top Label/index.ts
new file mode 100644
index 0000000000..7f3e48442d
--- /dev/null
+++ b/modules/preview-react/select/stories/examples/Top Label/index.ts
@@ -0,0 +1,8 @@
+export {Default} from './Default';
+export {DefaultWithCustomOptions} from './DefaultWithCustomOptions';
+export {DefaultWithSimpleOptions} from './DefaultWithSimpleOptions';
+export {Scrollable} from './Scrollable';
+export {Disabled} from './Disabled';
+export {Alert} from './Alert';
+export {Error} from './Error';
+export {Grow} from './Grow';
diff --git a/modules/preview-react/select/stories/examples/storiesData.tsx b/modules/preview-react/select/stories/examples/storiesData.tsx
new file mode 100644
index 0000000000..86ee41c5dc
--- /dev/null
+++ b/modules/preview-react/select/stories/examples/storiesData.tsx
@@ -0,0 +1,97 @@
+import * as React from 'react';
+import {storiesOf} from '@storybook/react';
+import {controlComponent} from '../../../../../utils/storybook';
+import {SystemIcon} from '@workday/canvas-kit-react/icon';
+import {
+ activityStreamIcon,
+ avatarIcon,
+ uploadCloudIcon,
+ userIcon,
+} from '@workday/canvas-system-icons-web';
+import {colors, typeColors} from '@workday/canvas-kit-react/tokens';
+import {FormField} from '@workday/canvas-kit-react/form-field';
+import {
+ Select,
+ RenderOptionFunction,
+ RenderSelectedFunction,
+} from '@workday/canvas-kit-preview-react/select';
+
+export const hintText = 'Helpful text goes here.';
+export const hintId = 'error-desc-id';
+
+export const options = [
+ {label: 'E-mail', value: 'email-1234'},
+ {label: 'Phone', value: 'phone'},
+ {label: 'Fax (disabled)', value: 'fax', disabled: true},
+ {label: 'Mail', value: 'mail'},
+ {label: 'Mobile Phone', value: 'mobile_phone'},
+ {
+ label: 'The Ontologically Anthropocentric Sensory Immersive Simulation',
+ value: 'oasis',
+ },
+];
+
+export const simpleOptions = ['California', 'Florida', 'New York', 'Pennsylvania', 'Texas'];
+
+export const manyOptions = [
+ {label: 'Atlanta (United States)', value: 'atlanta'},
+ {label: 'Amsterdam (Europe)', value: 'amsterdam'},
+ {label: 'Austin (United States)', value: 'austin'},
+ {label: 'Beaverton (United States)', value: 'beaverton'},
+ {label: 'Belfast (Europe)', value: 'belfast'},
+ {label: 'Berlin (Europe)', value: 'berlin'},
+ {label: 'Boston (United States)', value: 'boston'},
+ {label: 'Boulder (United States)', value: 'boulder'},
+ {label: 'Chicago (United States)', value: 'chicago'},
+ {label: 'Dallas (United States)', value: 'dallas'},
+ {label: 'Denver (United States)', value: 'denver'},
+ {label: 'Dublin (Europe)', value: 'dublin'},
+ {label: 'Irvine (United States)', value: 'irvine'},
+ {label: 'Minneapolis (United States)', value: 'minneapolis'},
+ {label: 'New York (United States)', value: 'new-york'},
+ {label: 'Orlando (United States)', value: 'orlando'},
+ {label: 'Palo Alto (United States)', value: 'palo-alto'},
+ {label: 'Philadelphia (United States)', value: 'philadelphia'},
+ {label: 'Pleasanton (United States)', value: 'pleasanton'},
+ {label: 'Raleigh (United States)', value: 'raleigh'},
+ {label: 'San Francisco (United States)', value: 'san-francisco'},
+ {label: 'San Mateo (United States)', value: 'san-mateo'},
+ {label: 'Stockholm (Europe)', value: 'stockholm'},
+ {
+ label: 'The Ontologically Anthropocentric Sensory Immersive Simulation (Virtual Reality)',
+ value: 'oasis',
+ },
+ {label: 'Toronto (Canada)', value: 'toronto'},
+ {label: 'Victoria (Canada)', value: 'victoria'},
+ {label: 'Vienna (Europe)', value: 'vienna'},
+ {label: 'Warsaw (Europe)', value: 'warsaw'},
+ {label: 'Washington, DC (United States)', value: 'washington-dc'},
+ {label: 'Zurich (Europe)', value: 'zurich'},
+];
+
+export const customOptions = [
+ {value: 'Activity Stream', data: {icon: activityStreamIcon}},
+ {value: 'Avatar', data: {icon: avatarIcon}},
+ {value: 'Upload Cloud', data: {icon: uploadCloudIcon}},
+ {value: 'User', data: {icon: userIcon}},
+];
+
+export const customRenderOption: RenderOptionFunction = option => {
+ const iconColor = option.focused ? typeColors.inverse : colors.blackPepper100;
+ return (
+
+ );
+};
+
+export const customRenderSelected: RenderSelectedFunction = option => {
+ const iconColor = colors.blackPepper100;
+ return (
+
+ );
+};
diff --git a/modules/preview-react/select/stories/stories_CypressTesting.tsx b/modules/preview-react/select/stories/stories_CypressTesting.tsx
new file mode 100644
index 0000000000..527314b06c
--- /dev/null
+++ b/modules/preview-react/select/stories/stories_CypressTesting.tsx
@@ -0,0 +1,248 @@
+import * as React from 'react';
+import {controlComponent} from '../../../../utils/storybook';
+
+import {colors} from '@workday/canvas-kit-react/tokens';
+import {PrimaryButton} from '@workday/canvas-kit-react/button';
+import {FormField} from '@workday/canvas-kit-react/form-field';
+
+import {Select} from '../lib/Select';
+
+import {manyOptions, options} from './examples/storiesData';
+import {Modal} from '@workday/canvas-kit-react/modal';
+import {Flex} from '@workday/canvas-kit-react/layout';
+
+export default {
+ title: 'Testing/Preview/Select/Cypress',
+ component: Select,
+};
+
+const disabledOptions = [
+ {label: 'Carrier Pigeon', value: 'pigeon', disabled: true},
+ {label: 'E-mail', value: 'email'},
+ {label: 'Phone', value: 'phone'},
+ {label: 'Fax', value: 'fax', disabled: true},
+ {label: 'Mail', value: 'mail'},
+ {label: 'Mobile Phone', value: 'mobile_phone'},
+ {label: 'Telegram', value: 'telegram', disabled: true},
+];
+
+const Container = ({children, style = {}, ...elemProps}) => {
+ return (
+
+ {children}
+
+ );
+};
+
+const SelectModal = () => {
+ return (
+
+ Show Modal
+
+
+
+ Modal with Select
+
+ The menu for this Select should break out of the Modal.
+
+ {controlComponent()}
+
+
+ Submit
+ Cancel
+
+
+
+
+
+ );
+};
+
+const BlurTest = () => {
+ const [clicked, setClicked] = React.useState(false);
+
+ const handleButtonBlur = () => {
+ // Setting clicked updates the state of BlurTest which in turn causes
+ // the contained Select to re-render
+ setClicked(false);
+ };
+
+ const handleButtonClick = () => {
+ setClicked(true);
+ };
+
+ return (
+ <>
+ Empty filler (scroll down)
+ Blur Test
+
+ The following test checks against a timing issue where focus could be applied to the Select
+ Menu before it's been properly positioned, causing the browser to scroll to the top of the
+ page when clicking the Select Button to activate its Menu.
+
+ Context
+
+ The Select component consists of a Button (the collapsed form of the Select) and a Menu (the
+ dropdown menu displayed when you click on the Button or activate it using assistive
+ technology). The Menu has two important characteristics:
+
+
+ - DOM focus is applied to the Menu when it's visible.
+ -
+ The Menu is portalled to another location in the DOM outside the DOM hierarchy of the
+ Select component (to enable it to break outside of Modals, for example). Because the Menu
+ is located some distance (DOM-wise) away from it's corresponding Button, it needs to be
+ positioned so that it's visually attached to its Button.
+
+
+
+ Focusing the Menu before it's been properly positioned next to the Button will cause the
+ browser to scroll to the wrong location (where the Menu was before it was
+ positioned next to the button -- this is generally the top of the page).
+
+ Test
+
+ The following test creates a scenario where such a timing issue could potentially occur:
+
+
+ - The page is long (requires scrolling).
+ -
+ There's a button and a Select near the bottom of the page. The button has a blur handler
+ which triggers a re-render of the Select.
+
+ - You click on the button to give it focus.
+ -
+ You then click on the Select. This activates the Menu and immediately triggers the blur
+ handler for the button (which re-renders the Select).
+
+
+
+ This creates a tricky situation where we could potentially assign focus to the Menu before
+ it's been positioned since we're re-rendering the Menu immediately after it's been
+ activated. If we assign focus too soon, the page will scroll to the top and you'll need to
+ scroll back down to access the Menu you just activated.
+
+
+ To run the test, click on the "Click me first!" button, and then click directly on the
+ Select below it (directly on the Select itself, not the label).{' '}
+ No scrolling should occur when the Select is clicked.
+
+
+
+ {controlComponent()}
+
+ >
+ );
+};
+
+export const AccessibilityTest = () => (
+
+
+
+ This Select has its aria-required prop set to true. When its listbox menu
+ is opened, we expect aria-required to be set to "true" for the listbox.
+
+
+ {controlComponent(
+
+ )}
+
+
+ This Select has its required prop set to true. Again, when its listbox menu
+ is opened, we expect aria-required to be set to "true" for the listbox.
+
+
+ {controlComponent()}
+
+
+
+);
+
+export const DisabledOptionsTest = () => (
+
+
+ Disabled options may not be assistively focused using the keyboard.
+
+ {controlComponent()}
+
+
+
+);
+
+export const PortalTest = () => (
+
+
+
+ All gray-bordered containers on this page have their overflow set to hidden. Menus are
+ rendered using portals and should break out of their containers.
+
+
+ {controlComponent()}
+
+
+ Menus for Select with grow set to true should resize automatically as the Select grows.
+ Activate this menu and resize the window to see the menu grow to match the width of the
+ Select.
+
+
+ {controlComponent()}
+
+
+
+
+ Menus should flip upwards automatically if there isn't enough space in the viewport for them
+ to extend downwards. As you scroll down and space becomes available, the Menu will flip back
+ downwards.
+
+
+ {controlComponent()}
+
+
+ {controlComponent()}
+
+
+
+ Menus should behave the same with left-labeled FormFields.
+
+ {controlComponent()}
+
+
+ {controlComponent()}
+
+
+
+ Menus should break out of Modals.
+
+
+
+
+
+
+);
diff --git a/modules/preview-react/select/stories/stories_VisualTesting.tsx b/modules/preview-react/select/stories/stories_VisualTesting.tsx
new file mode 100644
index 0000000000..7c93343b5f
--- /dev/null
+++ b/modules/preview-react/select/stories/stories_VisualTesting.tsx
@@ -0,0 +1,172 @@
+import * as React from 'react';
+import {
+ ComponentStatesTable,
+ permutateProps,
+ StaticStates,
+} from '@workday/canvas-kit-react/testing';
+import {withSnapshotsEnabled, customColorTheme} from '../../../../utils/storybook';
+
+import {Select} from '../lib/Select';
+import {SelectBase} from '../lib/SelectBase';
+import {SelectOption} from '../lib/SelectOption';
+
+import {options} from './examples/storiesData';
+
+const normalizedOptions = options.map(option => {
+ return {
+ data: {},
+ disabled: option.disabled || false,
+ id: option.value,
+ label: option.label || option.value,
+ value: option.value,
+ };
+});
+
+export default withSnapshotsEnabled({
+ title: 'Testing/Preview/Select',
+ component: Select,
+});
+
+export const SelectStates = () => (
+
+ {
+ if (props.disabled && !['', 'hover'].includes(props.className)) {
+ return false;
+ }
+ return true;
+ }
+ )}
+ >
+ {props => (
+
+
+);
+
+export const SelectStatesMenuOn = () => (
+
+
+ {props => {
+ const buttonRef = React.createRef();
+ return (
+
+ {}} // eslint-disable-line no-empty-function
+ options={normalizedOptions}
+ focusedOptionIndex={1}
+ menuVisibility="opened"
+ shouldMenuAutoFlip={false}
+ shouldMenuAutoFocus={false}
+ />
+
+ );
+ }}
+
+
+);
+
+export const SelectStatesOption = () => (
+
+ {[
+ {
+ label: 'Disabled States',
+ columnProps: [
+ {label: 'Default', props: {}},
+ {label: 'Hover', props: {className: 'hover'}},
+ ],
+ rowProps: [{label: 'Disabled', props: {'aria-disabled': true}}],
+ },
+ {
+ label: 'Interaction States',
+ columnProps: [
+ {label: 'Default', props: {}},
+ {label: 'Hover', props: {className: 'hover'}},
+ {label: 'Active', props: {className: 'active'}},
+ {label: 'Active Hover', props: {className: 'active hover'}},
+ ],
+ rowProps: [
+ {label: 'Default', props: {}},
+ {label: 'Assistive-Focus', props: {focused: true}},
+ {label: 'Selected', props: {'aria-selected': true}},
+ {label: 'Assistive-Focus Selected', props: {'aria-selected': true, focused: true}},
+ ],
+ },
+ ].map(statesTable => (
+
+
{statesTable.label}
+
+
+ {props => (
+
+ )}
+
+
+
+ ))}
+
+);
+
+const themedParameters = {
+ canvasProviderDecorator: {
+ theme: customColorTheme,
+ },
+};
+
+export const SelectThemedStates = () => ;
+export const SelectThemedStatesMenuOn = () => ;
+export const SelectThemedStatesOption = () => ;
+
+SelectThemedStates.parameters = themedParameters;
+SelectThemedStatesMenuOn.parameters = themedParameters;
+SelectThemedStatesOption.parameters = themedParameters;
diff --git a/modules/preview-react/select/stories/tsconfig.json b/modules/preview-react/select/stories/tsconfig.json
new file mode 100644
index 0000000000..4fb6aa9472
--- /dev/null
+++ b/modules/preview-react/select/stories/tsconfig.json
@@ -0,0 +1,3 @@
+{
+ "extends": "../../../../tsconfig.stories.json"
+}