Skip to content
Merged
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
296 changes: 162 additions & 134 deletions apps/vr-tests-react-components/src/stories/Field.stories.tsx
Original file line number Diff line number Diff line change
@@ -1,137 +1,165 @@
import * as React from 'react';
Comment thread
behowell marked this conversation as resolved.
import { Steps, StoryWright } from 'storywright';
import { storiesOf } from '@storybook/react';
import { CheckboxField_unstable as CheckboxField } from '@fluentui/react-checkbox';
import { ComboboxField_unstable as ComboboxField } from '@fluentui/react-combobox';
import { SparkleFilled } from '@fluentui/react-icons';
import type { InputFieldProps_unstable as InputFieldProps } from '@fluentui/react-input';
import { InputField_unstable as InputField } from '@fluentui/react-input';
import { ProgressField_unstable as ProgressField } from '@fluentui/react-progress';
import { Radio, RadioGroupField_unstable as RadioGroupField } from '@fluentui/react-radio';
import { SelectField_unstable as SelectField } from '@fluentui/react-select';
import { SliderField_unstable as SliderField } from '@fluentui/react-slider';
import { SpinButtonField_unstable as SpinButtonField } from '@fluentui/react-spinbutton';
import { SwitchField_unstable as SwitchField } from '@fluentui/react-switch';
import { TextareaField_unstable as TextareaField } from '@fluentui/react-textarea';

type FieldControlProps = Pick<
InputFieldProps,
'orientation' | 'required' | 'label' | 'validationState' | 'validationMessage' | 'validationMessageIcon' | 'hint'
>;

/**
* Common VR tests for all field components. Pass the given Field component (or a wrapper around it).
*/
const storiesOfField = (name: string, Field: React.VoidFunctionComponent<FieldControlProps>) =>
storiesOf(name, module)
.addDecorator(story => <StoryWright steps={new Steps().snapshot('default').end()}>{story()}</StoryWright>)
.addDecorator(story => (
<div style={{ display: 'flex' }}>
<div className="testWrapper" style={{ padding: '10px', width: '480px' }}>
<StoryWright steps={new Steps().snapshot('default', { cropTo: '.testWrapper' }).end()}>{story()}</StoryWright>
</div>
</div>
))
.addStory('base', () => <Field label="Example field" />)
.addStory('required', () => <Field label="Example field" required />)
.addStory('validation', () => (
<div style={{ display: 'grid', rowGap: '10px' }}>
<Field label="Validation error" validationState="error" validationMessage="Error message" />
<Field label="Validation warning" validationState="warning" validationMessage="Warning message" />
<Field label="Validation success" validationState="success" validationMessage="Success message" />
<Field
label="Custom validation state"
validationMessageIcon={<SparkleFilled />}
validationMessage="Custom message"
/>
</div>
))
.addStory('hint', () => <Field label="Example field" hint="Hint message" />)
.addStory('horizontal', () => (
<Field
label="This is a very long label that should wrap around to be multiple lines in height"
orientation="horizontal"
validationState="error"
validationMessage="Error message"
hint="Hint text"
/>
));

/**
* Same as storiesOfField, but with extra stories for Field components that support the size prop.
*/
const storiesOfFieldWithSize = (
name: string,
Field: React.VoidFunctionComponent<FieldControlProps & { size?: 'small' | 'medium' | 'large' }>,
) =>
storiesOfField(name, Field)
.addStory('size:small', () => <Field label="Example field" size="small" />)
.addStory('size:large', () => <Field label="Example field" size="large" />);

//
// CheckboxField
//
storiesOfField('CheckboxField converged', CheckboxField)
.addStory('size:large', () => <CheckboxField label="Example field" size="large" />)
.addStory('fieldLabel', () => <CheckboxField label="Label for the checkbox" fieldLabel="Field label" required />);

//
// ComboboxField
//
storiesOfFieldWithSize('ComboboxField converged', ComboboxField);

//
// InputField
//
storiesOfFieldWithSize('InputField converged', InputField);

//
// ProgressField
//
storiesOfField('ProgressField converged', props => (
<ProgressField
value={0.5}
{...props}
validationState={props.validationState === 'none' ? undefined : props.validationState}
/>
));

//
// RadioGroupField
//
storiesOfField('RadioGroupField converged', props => (
<RadioGroupField {...props}>
<Radio label="Option one" />
<Radio label="Option two" />
<Radio label="Option three" />
</RadioGroupField>
));

//
// SelectField
//
storiesOfFieldWithSize('SelectField converged', props => (
<SelectField {...props}>
<option>Option one</option>
</SelectField>
));

//
// SliderField
//
storiesOfField('SliderField converged', SliderField);

//
// SpinButtonField
//
storiesOfField('SpinButtonField converged', SpinButtonField);

//
// SwitchField
//
storiesOfField('SwitchField converged', SwitchField);
import { Checkbox } from '@fluentui/react-checkbox';
import { Combobox, Dropdown } from '@fluentui/react-combobox';
import { Field } from '@fluentui/react-field';
import { Dismiss12Filled } from '@fluentui/react-icons';
import { Input } from '@fluentui/react-input';
import { ProgressBar } from '@fluentui/react-progress';
import { Radio, RadioGroup } from '@fluentui/react-radio';
import { Select } from '@fluentui/react-select';
import { Slider } from '@fluentui/react-slider';
import { SpinButton } from '@fluentui/react-spinbutton';
import { Switch } from '@fluentui/react-switch';
import { Textarea } from '@fluentui/react-textarea';
import { storiesOf } from '@storybook/react';
import { Steps, StoryWright } from 'storywright';

//
// TextareaField
//
storiesOfFieldWithSize('TextareaField converged', TextareaField);
storiesOf('Field', module)
.addDecorator(story => (
<div className="testWrapper" style={{ padding: '10px', width: '400px' }}>
<StoryWright steps={new Steps().snapshot('default', { cropTo: '.testWrapper' }).end()}>{story()}</StoryWright>
</div>
))
.addStory('base', () => (
<Field label="Example field">
<Input />
</Field>
))
.addStory('required', () => (
<Field label="Required field" required>
<Input />
</Field>
))
.addStory('size:small', () => (
<Field label="Small field" size="small">
<Input size="small" />
</Field>
))
.addStory('size:large', () => (
<Field label="Large field" size="large">
<Input size="large" />
</Field>
))
.addStory('validation:error', () => (
<Field label="Validation error" validationMessage="Error message">
<Input />
</Field>
))
.addStory('validation:warning', () => (
<Field label="Validation warning" validationState="warning" validationMessage="Warning message">
<Input />
</Field>
))
.addStory('validation:success', () => (
<Field
label="Validation success"
validationState="success"
validationMessage={`This success message wraps to multiple lines. All lines of this message should be left aligned
with each other, and the icon should be in its own column to the left of the message. None of the text of the
message should be directly below the icon.`}
>
<Input />
</Field>
))
.addStory('validation:none', () => (
<Field label="Validation none" validationState="none" validationMessage="Custom validation message">
<Input />
</Field>
))
.addStory('validationMessageIcon', () => (
<Field
label="Custom validation icon"
validationMessage="Error message with custom icon"
validationMessageIcon={<Dismiss12Filled />}
>
<Input />
</Field>
))
.addStory('hint', () => (
<Field
label="Field with Hint"
hint={'This hint message wraps to multiple lines. It should all be left-aligned without an extra indentation.'}
>
<Input />
</Field>
))
.addStory('horizontal', () => (
<Field orientation="horizontal" label="Horizontal field">
<Input />
</Field>
))
.addStory('horizontal+longLabel', () => (
<Field
orientation="horizontal"
label="A long label should wrap around to multiple lines without affecting the layout of the control"
validationState="warning"
validationMessage="Warning message"
hint="Hint text"
>
<Input />
</Field>
))
.addStory('horizontal+noLabel', () => (
<Field
orientation="horizontal"
hint={`The gap to the left is expected. With no Field label, the control is indented to vertically align with
other horizontal fields.`}
>
<Checkbox label="Checkbox in a horizontal field" />
</Field>
))
.addStory('Checkbox:error', () => (
<Field validationMessage="Error message">
<Checkbox label="Checkbox in a Field with an error" />
</Field>
))
.addStory('Combobox:error', () => (
<Field label="Combobox in a Field with an error" validationMessage="Error message">
<Combobox />
</Field>
))
.addStory('Dropdown:error', () => (
<Field label="Dropdown in a Field with an error" validationMessage="Error message">
<Dropdown />
</Field>
))
.addStory('ProgressBar:error', () => (
<Field label="ProgressBar in a Field with an error" validationMessage="Error message">
<ProgressBar value={0.5} validationState="error" />
</Field>
))
.addStory('RadioGroup:error', () => (
<Field label="RadioGroup in a Field with an error" validationMessage="Error message">
<RadioGroup>
<Radio label="Option one" />
<Radio label="Option two" />
<Radio label="Option three" />
</RadioGroup>
</Field>
))
.addStory('Select:error', () => (
<Field label="Select in a Field with an error" validationMessage="Error message">
<Select />
</Field>
))
.addStory('Slider:error', () => (
<Field label="Slider in a Field with an error" validationMessage="Error message">
<Slider />
</Field>
))
.addStory('SpinButton:error', () => (
<Field label="SpinButton in a Field with an error" validationMessage="Error message">
<SpinButton />
</Field>
))
.addStory('Switch:error', () => (
<Field label="Switch in a Field with an error" validationMessage="Error message">
<Switch />
</Field>
))
.addStory('Textarea:error', () => (
<Field label="Textarea in a Field with an error" validationMessage="Error message">
<Textarea />
</Field>
));