Skip to content
Merged
Show file tree
Hide file tree
Changes from 25 commits
Commits
Show all changes
30 commits
Select commit Hold shift + click to select a range
06d1725
Initial implementation of Field and InputField
behowell Aug 17, 2022
84ff5e9
Revert some dependencies in react-field for now
behowell Aug 17, 2022
edf391a
Merge branch 'master' of https://github.com/microsoft/fluentui into f…
behowell Aug 17, 2022
4189e9a
Rename fieldOrientation to orientation, and add UseFieldParams argume…
behowell Aug 18, 2022
4dba2ae
Rename helperText to hint
behowell Aug 18, 2022
7040897
Rename status to validationState, statusText to validationMessage, an…
behowell Aug 18, 2022
6ee6dcd
Add all Field components
behowell Aug 19, 2022
efbec05
Fix issue in SpinButtonField
behowell Aug 19, 2022
049a28f
Merge branch 'field/implement' of https://github.com/behowell/fluentu…
behowell Aug 30, 2022
3235bc2
Merge branch 'field/implement' of https://github.com/behowell/fluentu…
behowell Aug 30, 2022
d77c166
Add ComboboxField
behowell Aug 30, 2022
988ae99
Add ComboboxField tests
behowell Aug 30, 2022
0e4340f
Rename `fieldComponent` slot to `field`
behowell Aug 31, 2022
6d47406
Rename `field` slot to `control`
behowell Aug 31, 2022
11aa35b
Merge branch 'master' of https://github.com/microsoft/fluentui into f…
behowell Aug 31, 2022
5cba764
Merge branch 'field/implement' of https://github.com/behowell/fluentu…
behowell Aug 31, 2022
79ba601
Rename `field` slot to `control`
behowell Aug 31, 2022
364f387
Clean up how CheckboxField applies the fieldLabel
behowell Aug 31, 2022
94a9bba
Update CheckboxField conformance tests to use fieldLabel
behowell Aug 31, 2022
7fe46a7
Merge branch 'master' of https://github.com/microsoft/fluentui into f…
behowell Sep 2, 2022
c3df78f
Update api.md
behowell Sep 2, 2022
249713e
Remove comment about PRIMARY slot on Field control prop.
behowell Sep 2, 2022
4967264
CheckboxField: put required on the checkbox label, not fieldLabel
behowell Sep 2, 2022
9816cd4
Add stories for all components
behowell Sep 2, 2022
bcdfd1f
Merge branch 'master' of https://github.com/microsoft/fluentui into f…
behowell Sep 2, 2022
47c41fc
Refactor FieldConfig to not include props and ref
behowell Sep 6, 2022
5d77563
Merge branch 'master' of https://github.com/microsoft/fluentui into f…
behowell Sep 6, 2022
6d1fe7f
Implement PR feedback
behowell Sep 7, 2022
516c8b2
Add dependencies to vr-test package
behowell Sep 7, 2022
a5d5b04
Revert changes intended for another branch
behowell Sep 7, 2022
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
7 changes: 6 additions & 1 deletion packages/react-components/react-field/.storybook/main.js
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,12 @@ const rootMain = require('../../../../.storybook/main');

module.exports = /** @type {Omit<import('../../../../.storybook/main'), 'typescript'|'babel'>} */ ({
...rootMain,
stories: [...rootMain.stories, '../src/**/*.stories.mdx', '../src/**/index.stories.@(ts|tsx)'],
stories: [
...rootMain.stories,
'../src/**/*.stories.mdx',
'../src/stories/Field/index.stories.@(ts|tsx)',
'../src/**/index.stories.@(ts|tsx)',
],
addons: [...rootMain.addons],
webpackFinal: (config, options) => {
const localConfig = { ...rootMain.webpackFinal(config, options) };
Expand Down
86 changes: 85 additions & 1 deletion packages/react-components/react-field/etc/react-field.api.md
Original file line number Diff line number Diff line change
Expand Up @@ -6,16 +6,46 @@

/// <reference types="react" />

import { Checkbox } from '@fluentui/react-checkbox';
import type { CheckboxProps } from '@fluentui/react-checkbox';
import { Combobox } from '@fluentui/react-combobox';
import type { ComponentProps } from '@fluentui/react-utilities';
import type { ComponentState } from '@fluentui/react-utilities';
import type { ForwardRefComponent } from '@fluentui/react-utilities';
import { ForwardRefComponent } from '@fluentui/react-utilities';
import { Input } from '@fluentui/react-input';
import { Label } from '@fluentui/react-label';
import { RadioGroup } from '@fluentui/react-radio';
import * as React_2 from 'react';
import { Select } from '@fluentui/react-select';
import { Slider } from '@fluentui/react-slider';
import type { Slot } from '@fluentui/react-utilities';
import { SlotClassNames } from '@fluentui/react-utilities';
import type { SlotRenderFunction } from '@fluentui/react-utilities';
import type { SlotShorthandValue } from '@fluentui/react-utilities';
import { SpinButton } from '@fluentui/react-spinbutton';
import { Switch } from '@fluentui/react-switch';
import { Textarea } from '@fluentui/react-textarea';

// @public (undocumented)
export const CheckboxField: ForwardRefComponent<CheckboxFieldProps>;

// @public (undocumented)
export const checkboxFieldClassNames: SlotClassNames<FieldSlots<FieldComponent>>;

// @public (undocumented)
export type CheckboxFieldProps = Omit<FieldProps<typeof Checkbox>, 'label'> & {
label?: CheckboxProps['label'];
fieldLabel?: FieldProps<typeof Checkbox>['label'];
};

// @public (undocumented)
export const ComboboxField: ForwardRefComponent<ComboboxFieldProps>;

// @public (undocumented)
export const comboboxFieldClassNames: SlotClassNames<FieldSlots<FieldComponent>>;

// @public (undocumented)
export type ComboboxFieldProps = FieldProps<typeof Combobox>;

// @public
export type FieldProps<T extends FieldComponent> = ComponentProps<Partial<FieldSlots<T>>, 'control'> & {
Expand Down Expand Up @@ -50,9 +80,63 @@ export const inputFieldClassNames: SlotClassNames<FieldSlots<FieldComponent>>;
// @public (undocumented)
export type InputFieldProps = FieldProps<typeof Input>;

// @public (undocumented)
export const RadioGroupField: ForwardRefComponent<RadioGroupFieldProps>;

// @public (undocumented)
export const radioGroupFieldClassNames: SlotClassNames<FieldSlots<FieldComponent>>;

// @public (undocumented)
export type RadioGroupFieldProps = FieldProps<typeof RadioGroup>;

// @public
export const renderField_unstable: <T extends FieldComponent>(state: FieldState<T>) => JSX.Element;

// @public (undocumented)
export const SelectField: ForwardRefComponent<SelectFieldProps>;

// @public (undocumented)
export const selectFieldClassNames: SlotClassNames<FieldSlots<FieldComponent>>;

// @public (undocumented)
export type SelectFieldProps = FieldProps<typeof Select>;

// @public (undocumented)
export const SliderField: ForwardRefComponent<SliderFieldProps>;

// @public (undocumented)
export const sliderFieldClassNames: SlotClassNames<FieldSlots<FieldComponent>>;

// @public (undocumented)
export type SliderFieldProps = FieldProps<typeof Slider>;

// @public (undocumented)
export const SpinButtonField: ForwardRefComponent<SpinButtonFieldProps>;

// @public (undocumented)
export const spinButtonFieldClassNames: SlotClassNames<FieldSlots<FieldComponent>>;

// @public (undocumented)
export type SpinButtonFieldProps = FieldProps<typeof SpinButton>;

// @public (undocumented)
export const SwitchField: ForwardRefComponent<SwitchFieldProps>;

// @public (undocumented)
export const switchFieldClassNames: SlotClassNames<FieldSlots<FieldComponent>>;

// @public (undocumented)
export type SwitchFieldProps = FieldProps<typeof Switch>;

// @public (undocumented)
export const TextareaField: ForwardRefComponent<TextareaFieldProps>;

// @public (undocumented)
export const textareaFieldClassNames: SlotClassNames<FieldSlots<FieldComponent>>;

// @public (undocumented)
export type TextareaFieldProps = FieldProps<typeof Textarea>;

// @public
export const useField_unstable: <T extends FieldComponent>(params: UseFieldParams<T>) => FieldState<T>;

Expand Down
8 changes: 8 additions & 0 deletions packages/react-components/react-field/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -32,10 +32,18 @@
"@fluentui/scripts": "^1.0.0"
},
"dependencies": {
"@fluentui/react-checkbox": "^9.0.4",
"@fluentui/react-combobox": "^9.0.0-beta.8",
"@fluentui/react-context-selector": "^9.0.2",
"@fluentui/react-icons": "^2.0.175",
"@fluentui/react-input": "^9.0.4",
"@fluentui/react-label": "^9.0.4",
"@fluentui/react-radio": "^9.0.4",
"@fluentui/react-select": "9.0.0-beta.8",
"@fluentui/react-slider": "^9.0.3",
"@fluentui/react-spinbutton": "^9.0.0",
"@fluentui/react-switch": "^9.0.4",
"@fluentui/react-textarea": "^9.0.4",
"@fluentui/react-theme": "^9.0.0",
"@fluentui/react-utilities": "^9.0.2",
"@griffel/react": "^1.3.0",
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
export * from './components/CheckboxField/index';
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
export * from './components/ComboboxField/index';
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
export * from './components/RadioGroupField/index';
1 change: 1 addition & 0 deletions packages/react-components/react-field/src/SelectField.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
export * from './components/SelectField/index';
1 change: 1 addition & 0 deletions packages/react-components/react-field/src/SliderField.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
export * from './components/SliderField/index';
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
export * from './components/SpinButtonField/index';
1 change: 1 addition & 0 deletions packages/react-components/react-field/src/SwitchField.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
export * from './components/SwitchField/index';
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
export * from './components/TextareaField/index';
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
import * as React from 'react';
import { resetIdsForTests } from '@fluentui/react-utilities';
import { render } from '@testing-library/react';
import { isConformant } from '../../common/isConformant';
import { CheckboxField, checkboxFieldClassNames } from './CheckboxField';

describe('CheckboxField', () => {
isConformant({
Component: CheckboxField,
displayName: 'CheckboxField',
primarySlot: 'control',
testOptions: {
'has-static-classnames': [
{
props: {
label: 'label',
fieldLabel: 'fieldLabel',
validationState: 'error',
validationMessage: 'validationMessage',
hint: 'hint',
},
expectedClassNames: checkboxFieldClassNames,
},
],
},
});

beforeEach(resetIdsForTests);

it('renders a default state', () => {
const result = render(<CheckboxField label="Checkbox" />);
expect(result.container).toMatchSnapshot();
});
});
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
import * as React from 'react';
import type { CheckboxProps } from '@fluentui/react-checkbox';
import { Checkbox } from '@fluentui/react-checkbox';
import { ForwardRefComponent } from '@fluentui/react-utilities';
import type { FieldProps } from '../../Field';
import { getFieldClassNames, renderField_unstable, useFieldStyles_unstable, useField_unstable } from '../../Field';

export type CheckboxFieldProps = Omit<FieldProps<typeof Checkbox>, 'label'> & {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Does Switch also need to implement this behavior since it also already has a label prop?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'm talking to Design about how the label prop of Switch should work. I logged this issue to implement the final behavior once we decide how it should work:

/**
* The Checkbox's label.
*/
label?: CheckboxProps['label'];

/**
* The label for the CheckboxField, which appears above or before the Checkbox, depending on the `orientation` prop.
* It is recommended to only set the `label` prop, and not `fieldLabel`.
*/
fieldLabel?: FieldProps<typeof Checkbox>['label'];
};

export const checkboxFieldClassNames = getFieldClassNames('CheckboxField');

export const CheckboxField: ForwardRefComponent<CheckboxFieldProps> = React.forwardRef((props, ref) => {
const { fieldLabel, required, label, control, ...restOfProps } = props;

const state = useField_unstable({
props: {
// Use the fieldLabel prop as the Field's label
label: fieldLabel,
// Use the label prop as the Checkbox's label
control: { label, required, ...control },
...restOfProps,
},
ref,
component: Checkbox,
classNames: checkboxFieldClassNames,
});
useFieldStyles_unstable(state);
return renderField_unstable(state);
});

CheckboxField.displayName = 'CheckboxField';
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
// Jest Snapshot v1, https://goo.gl/fbAQLP

exports[`CheckboxField renders a default state 1`] = `
<div>
<div
class="fui-CheckboxField"
>
<span
class="fui-Checkbox fui-CheckboxField__control"
>
<input
class="fui-Checkbox__input"
type="checkbox"
/>
<div
aria-hidden="true"
class="fui-Checkbox__indicator"
>
<svg
aria-hidden="true"
class=""
fill="currentColor"
height="12"
viewBox="0 0 12 12"
width="12"
xmlns="http://www.w3.org/2000/svg"
>
<path
d="M9.76 3.2c.3.29.32.76.04 1.06l-4.25 4.5a.75.75 0 01-1.08.02L2.22 6.53a.75.75 0 011.06-1.06l1.7 1.7L8.7 3.24a.75.75 0 011.06-.04z"
fill="currentColor"
/>
</svg>
</div>
<label
class="fui-Label fui-Checkbox__label"
for="checkbox-2"
>
Checkbox
</label>
</span>
</div>
</div>
`;
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
export * from './CheckboxField';
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
import * as React from 'react';
import { resetIdsForTests } from '@fluentui/react-utilities';
import { render } from '@testing-library/react';
import { isConformant } from '../../common/isConformant';
import { ComboboxField, comboboxFieldClassNames } from './ComboboxField';

describe('ComboboxField', () => {
isConformant({
Component: ComboboxField,
displayName: 'ComboboxField',
primarySlot: 'control',
testOptions: {
'has-static-classnames': [
{
props: {
label: 'label',
validationState: 'error',
validationMessage: 'validationMessage',
hint: 'hint',
},
expectedClassNames: comboboxFieldClassNames,
},
],
},
});

beforeEach(resetIdsForTests);

it('renders a default state', () => {
const result = render(<ComboboxField />);
expect(result.container).toMatchSnapshot();
});
});
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
import * as React from 'react';
import { Combobox } from '@fluentui/react-combobox';
import type { ForwardRefComponent } from '@fluentui/react-utilities';
import type { FieldProps } from '../../Field';
import { getFieldClassNames, renderField_unstable, useFieldStyles_unstable, useField_unstable } from '../../Field';

export type ComboboxFieldProps = FieldProps<typeof Combobox>;

export const comboboxFieldClassNames = getFieldClassNames('ComboboxField');

export const ComboboxField: ForwardRefComponent<ComboboxFieldProps> = React.forwardRef((props, ref) => {
const state = useField_unstable({ props, ref, component: Combobox, classNames: comboboxFieldClassNames });
useFieldStyles_unstable(state);
return renderField_unstable(state);
});

ComboboxField.displayName = 'ComboboxField';
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
// Jest Snapshot v1, https://goo.gl/fbAQLP

exports[`ComboboxField renders a default state 1`] = `
<div>
<div
class="fui-ComboboxField"
>
<div
class="fui-Combobox fui-ComboboxField__control"
>
<input
aria-expanded="false"
class="fui-Combobox__input"
role="combobox"
type="text"
value=""
/>
<span
class="fui-Combobox__expandIcon"
>
<svg
aria-hidden="true"
class=""
fill="currentColor"
height="1em"
viewBox="0 0 20 20"
width="1em"
xmlns="http://www.w3.org/2000/svg"
>
<path
d="M15.85 7.65c.2.2.2.5 0 .7l-5.46 5.49a.55.55 0 01-.78 0L4.15 8.35a.5.5 0 11.7-.7L10 12.8l5.15-5.16c.2-.2.5-.2.7 0z"
fill="currentColor"
/>
</svg>
</span>
</div>
</div>
</div>
`;
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
export * from './ComboboxField';
Original file line number Diff line number Diff line change
Expand Up @@ -24,9 +24,6 @@ export type FieldSlots<T extends FieldComponent> = {

/**
* The underlying component wrapped by this field.
*
* This is the PRIMARY slot: all intrinsic HTML properties will be applied to this slot,
* except `className` and `style`, which remain on the root slot.
*/
control: SlotComponent<T>;

Expand Down
Loading