Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

chore: Add FormFieldGroup component and density example #2865

Merged
merged 80 commits into from
Sep 20, 2024
Merged
Show file tree
Hide file tree
Changes from 23 commits
Commits
Show all changes
80 commits
Select commit Hold shift + click to select a range
5705d9d
fix: Add density example
Aug 1, 2024
adb7ef3
fix: Add formfield group
Aug 6, 2024
392774a
fix: Clean formfield group
Aug 6, 2024
a7a59af
fix: Add horixontal support
Aug 9, 2024
028a60a
fix: Clean up example
Aug 9, 2024
909fb81
fix: Refactor select styles
Aug 9, 2024
421a1d9
fix: Add docs
Aug 9, 2024
911a3da
fix: Update radio usage
Aug 9, 2024
c909633
fix: Remove onchange
Aug 9, 2024
f9826e8
Merge branch 'prerelease/major' into mc-ff-example
mannycarrera4 Aug 9, 2024
22ff4b4
fix: Remove id from input
Aug 12, 2024
30056ef
Merge branch 'mc-ff-example' of https://github.com/mannycarrera4/canv…
Aug 12, 2024
d1744dc
fix: Handle errors better
Aug 12, 2024
5c4978c
fix: Update form validation
Aug 12, 2024
8ddb470
fix: Add timeout
Aug 13, 2024
d34641f
fix: Clean up jsdocs
Aug 13, 2024
f39b3b8
fix: Update jsdocs
Aug 13, 2024
0e7cb0e
fix: Remove unused stencil
Aug 13, 2024
2b35b03
fix: Update density example
Aug 15, 2024
0af112e
fix: Clean up examples
Aug 15, 2024
a8b1813
fix: Update upgrade guide
Aug 15, 2024
e6af5ad
docs: Add info to upgrade guide
Aug 19, 2024
6060aed
fix: Update cc example
Aug 19, 2024
652ee9f
Update modules/preview-react/form-field/stories/examples/AllFields.tsx
mannycarrera4 Aug 22, 2024
1408c84
Update modules/preview-react/form-field/lib/FormFieldGroup.tsx
mannycarrera4 Aug 22, 2024
f7fad11
Update modules/preview-react/form-field/stories/examples/GroupedInput…
mannycarrera4 Aug 22, 2024
f62eee0
fix: Update merge conflicts
Aug 23, 2024
5f3d829
Merge branch 'mc-ff-example' of https://github.com/mannycarrera4/canv…
Aug 23, 2024
caed8f0
Merge branch 'prerelease/major' into mc-ff-example
mannycarrera4 Aug 27, 2024
27c1186
fix: Update example to new storybook format
Aug 29, 2024
f410b29
Merge branch 'mc-ff-example' of https://github.com/mannycarrera4/canv…
Aug 29, 2024
065a2ff
fix: Add back in grouped inputs story
Aug 29, 2024
428a6f2
fix: Remove duplicate import
Aug 29, 2024
4a71a77
fix: Update typecheck
Aug 29, 2024
808b584
fix: Try to remove flakiness
Aug 29, 2024
cb53c47
Update modules/preview-react/form-field/stories/examples/GroupedInput…
mannycarrera4 Aug 30, 2024
e01f067
Update modules/preview-react/form-field/stories/examples/GroupedInput…
mannycarrera4 Aug 30, 2024
d173780
fix: Clean up data attributes and styling
Sep 4, 2024
0375748
fix: Update density selector
Sep 5, 2024
3e0ca10
fix: Clean up selectors
Sep 6, 2024
0c1f437
fix: Add info around selectors
Sep 6, 2024
dd32dcc
fix: Add formfield field
Sep 6, 2024
fcc318e
fix: Update all examples to use formfield field
Sep 9, 2024
052d9db
fix: Remove themable and update upgrade guide
Sep 9, 2024
f559a7e
fix: Update upgrade guide
Sep 10, 2024
fcc63b2
fix: Add info to upgrade guide
Sep 10, 2024
a9903d6
Merge branch 'prerelease/major' into mc-ff-example
mannycarrera4 Sep 10, 2024
c82a3b5
fix: Update merge conflcits
Sep 12, 2024
844c95e
Merge branch 'mc-ff-example' of https://github.com/mannycarrera4/canv…
Sep 12, 2024
b03ec3f
fix: Update accessibility
Sep 16, 2024
d03b1ec
fix: Update to be formfield label
Sep 16, 2024
9378ba3
fix: Update accessbility
Sep 16, 2024
916625a
Update cypress.config.ts
mannycarrera4 Sep 16, 2024
2665034
Update cypress/component/ActionBar.spec.tsx
mannycarrera4 Sep 17, 2024
e8d3194
fix: Clean up upgrade guide
Sep 17, 2024
242e798
Merge branch 'mc-ff-example' of https://github.com/mannycarrera4/canv…
Sep 17, 2024
9104d57
Merge branch 'prerelease/major' into mc-ff-example
mannycarrera4 Sep 17, 2024
0faf886
fix: Update accessibility and density example
Sep 17, 2024
74c0b42
Merge branch 'mc-ff-example' of https://github.com/mannycarrera4/canv…
Sep 17, 2024
1f3a1f8
fix: Update error text in density example
Sep 17, 2024
361175c
fix: Clean up group
Sep 17, 2024
825aa0b
Update modules/docs/mdx/12.0-UPGRADE-GUIDE.mdx
mannycarrera4 Sep 18, 2024
de5ca8d
Update modules/docs/mdx/12.0-UPGRADE-GUIDE.mdx
mannycarrera4 Sep 18, 2024
febd236
Update modules/preview-react/form-field/lib/FormFieldContainer.tsx
mannycarrera4 Sep 18, 2024
8a0aa0d
Update modules/preview-react/form-field/lib/FormFieldContainer.tsx
mannycarrera4 Sep 18, 2024
e7995a9
Update modules/react/action-bar/stories/examples/Basic.tsx
mannycarrera4 Sep 18, 2024
a38b3b1
Update modules/preview-react/form-field/lib/FormField.tsx
mannycarrera4 Sep 18, 2024
78c672e
fix: Clean up examples
Sep 18, 2024
a73eaf0
Merge branch 'mc-ff-example' of https://github.com/mannycarrera4/canv…
Sep 18, 2024
23e2f63
fix: Clean up styles
Sep 18, 2024
521f102
fix: Clean up styles
Sep 18, 2024
435c858
fix: Remove use of parentModifier
Sep 19, 2024
63fc6c5
fix: Clean up radios
Sep 19, 2024
a0c55e3
fix: Deprecate parentModifier
Sep 19, 2024
255829a
fix: Clean up docs
Sep 19, 2024
9b3ac40
Update modules/docs/mdx/12.0-UPGRADE-GUIDE.mdx
mannycarrera4 Sep 19, 2024
67d90e5
Merge branch 'prerelease/major' into mc-ff-example
mannycarrera4 Sep 19, 2024
f3ba40d
fix: Export the things from index
Sep 19, 2024
af922d1
Merge branch 'mc-ff-example' of https://github.com/mannycarrera4/canv…
Sep 19, 2024
a11e36d
Apply suggestions from code review
mannycarrera4 Sep 20, 2024
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
28 changes: 25 additions & 3 deletions modules/docs/mdx/12.0-UPGRADE-GUIDE.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -46,6 +46,8 @@ A note to the reader:
- [Component Updates](#component-updates)
- [Styling API and CSS Tokens](#styling-api-and-css-tokens)
- [Avatar](#avatar)
- [FormFieldGroup](#form-field-group)
- [Select](#select)
- [Text Area](#text-area)
- [Troubleshooting](#troubleshooting)
- [Glossary](#glossary)
Expand Down Expand Up @@ -120,12 +122,32 @@ The following components are affected:
### Avatar

- Avatar no longer uses `SystemIconCircle` for sizing.
- `Avatar.Size` is no longer supported. The `size` prop type has change to accept the following:
- `Avatar.Size` is no longer supported.
- The `size` prop type has change to accept the following:
`"extraExtraLarge" | "extraLarge" | "large" | "medium" | "small" | "extraSmall" | (string{})`
- `Avatar.Variant` is no longer supported. Enum `AvatarVariant` has been removed. The `variant` type
prop now accepts `"dark" | "light"`
- `Avatar.Variant` is no longer supported.
- Enum `AvatarVariant` has been removed.
- The `variant` prop now accepts `"dark" | "light"`
- The `as` prop now accepts any element, not just `div`.

### Form Field Group

We've added a new component to the Preview package under FromField to allow users to group inputs
without worrying about setting the `as` prop on the `FormField` component.

Use `FormFieldGroup` when you have a group of inputs that need to be associated to one another, like
`RadioGroup` or a group of `Checkbox`'s. `FormFieldGroup` renders a `fieldset` element and
`FormFieldGroup.Legend` renders a `legend` element. These elements will allow for correct
accessibility of grouped inputs.

`FormFieldGroup` supports the same props of `FormField`:

- `error`: `"alert" | "error"` Defines the error around the whole group of inputs.
- `orientation`: `"horizontal" | "vertical"` Defines the legend placement.
- `isRequired`: `true` Defines if a group like RadioGroup is required.

### Select

### Text Area

**PR:** [#2825](https://github.com/Workday/canvas-kit/pull/2825)
Expand Down
1 change: 1 addition & 0 deletions modules/preview-react/form-field/index.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
export * from './lib/FormField';
export * from './lib/FormFieldGroup';
export * from './lib/hooks/';
export {formFieldStencil} from './lib/formFieldStencil';
export {formFieldContainerStencil} from './lib/FormFieldContainer';
Expand Down
128 changes: 128 additions & 0 deletions modules/preview-react/form-field/lib/FormFieldGroup.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,128 @@
import React from 'react';

import {createContainer, GrowthBehavior} from '@workday/canvas-kit-react/common';
import {FlexProps, mergeStyles} from '@workday/canvas-kit-react/layout';

import {FormFieldGroupList} from './FormFieldGroupList';
import {FormFieldGroupInput} from './FormFieldGroupInput';
import {FormField} from './FormField';

import {useFormFieldModel} from './hooks';
import {formFieldStencil} from './formFieldStencil';

export interface FormFieldGroupProps extends FlexProps, GrowthBehavior {
/**
* The direction the child elements should stack
* @default vertical
*/
orientation?: 'vertical' | 'horizontal';
children: React.ReactNode;
}

/**
* Use `FormFieldGroup` to wrap a group of inputs to make them accessible. `FormFieldGroup` will render a `fieldset` element with the purpose of grouping input controls.
*
* ```tsx
* <FormFieldGroup>
* <FormField.Legend>Choose a Pet</FormField.Label>
* <FormFieldGroup.List as={RadioGroup} />
* <FromFieldGroup.Input as={RadioGroup.RadioButton} value='dog'>Dog</FormFieldGroup.Input>
* <FromFieldGroup.Input as={RadioGroup.RadioButton} value='cat'>Cat</FormFieldGroup.Input>
* </FormFieldGroup.List>
* </FormFieldGroup>
* ```
*
* @stencil formFieldStencil
*/
export const FormFieldGroup = createContainer('fieldset')({
displayName: 'FormFieldGroup',
modelHook: useFormFieldModel,
subComponents: {
/**
* `FormFieldGroup.Input` will render any `inputs` passed to it via the `as` prop, including `TextInput`, `Select`, `Switch`, `TextArea`, `RadioGroup.RadioButton` or any custom input.
* `FormFieldGroup.Input` will apply `aria-invalid` when there is an error on `FromFieldGroup` or `aria-describedby` when an `id` is added on the `FormFieldGroup`.
*
* **Note: If you pass in a custom input that is *not* as Canvas Kit input, you will have to handle the `error` prop, validation and styling. For a custom approach, reference our Custom storybook example.**
*
* ```tsx
* <FormFieldGroup>
* <FormField.Legend>Choose a Pet</FormField.Label>
* <FormFieldGroup.List as={RadioGroup} />
* <FromFieldGroup.Input as={RadioGroup.RadioButton} value='dog'>Dog</FormFieldGroup.Input>
* <FromFieldGroup.Input as={RadioGroup.RadioButton} value='cat'>Cat</FormFieldGroup.Input>
* </FormFieldGroup.List>
* </FormFieldGroup>
* ```
*/
Input: FormFieldGroupInput,
/**
* `FormFieldGroup.Legend` will render a `legend` element. This element labels the contents of a `fieldset`.
*
* ```tsx
* <FormFieldGroup>
* <FormFieldGroup.Legend>Choose a pet</FormFieldGroup.Legend>
* //...
* </FormFieldGroup>
* ```
*
* @stencil formFieldLabelStencil
*/
Legend: FormField.Label.as('legend'),
/**
* `FormFieldGroup.List` will render a `div`. This element is used to apply the visual error states around the group of inputs. It's contents will be your inputs.
*/
List: FormFieldGroupList,
/**
* `FormFieldGroup.Hint` will render any additional information you want to provide to the `FormFieldGroup`. If you
* set the `orientation` prop to `horizontal` you should use `FormFieldGroup.Container` to properly align the hint with your `FormField.List`.
*
* ```tsx
* <FormFieldGroup>
* <FormFieldGroup.Legend>Choose a pet</FormFieldGroup.Legend>
* <FormFieldGroup.List>
* //...
* <FormFieldGroup.List>
* <FormField.Hint>This is your hint text</FormField.Hint>
* </FormFieldGroup>
* ```
*
* @stencil formFieldHintStencil
*/
Hint: FormField.Hint,
/**
* `FormFieldGroup.Container` allows you to properly center `FormField.Legend` when the `orientation` is set to `horizontal` and there is hint text..
mannycarrera4 marked this conversation as resolved.
Show resolved Hide resolved
*
* ```tsx
* <FormFieldGroup orientation="horizontal">
* <FormFieldGroup.Legend>Choose a pet</FormFieldGroup.Legend>
* <FormFieldGroup.Container>
* <FormFieldGroup.List>
* <FromFieldGroup.Input as={RadioGroup.RadioButton} value='dog'>Dog</FormFieldGroup.Input>
* <FromFieldGroup.Input as={RadioGroup.RadioButton} value='cat'>Cat</FormFieldGroup.Input>
* </FormFieldGroup.List>
* <FormFieldGroup.Hint>This is your hint text</FormField.Hint>
* </FormFieldGroup.Container>
* </FormFieldGroup>
* ```
*
* @stencil formFieldContainerStencil
*/
Container: FormField.Container,
},
})<FormFieldGroupProps>(({children, grow, orientation, ...elemProps}, Element, model) => {
return (
<Element
{...mergeStyles(
elemProps,
formFieldStencil({
grow,
orientation,
error: model.state.error,
required: model.state.isRequired,
})
)}
>
{children}
</Element>
);
});
24 changes: 24 additions & 0 deletions modules/preview-react/form-field/lib/FormFieldGroupInput.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
import {createElemPropsHook, createSubcomponent} from '@workday/canvas-kit-react/common';
import {CSProps, handleCsProp} from '@workday/canvas-kit-styling';
import React from 'react';
import {useFormFieldModel} from './hooks';

export interface FormFieldGroupInputProps extends CSProps {}
/**
* Adds the necessary props to an `Input` component.
* Used by the FormField.Input subcomponent and other input type components
*/
export const useFormFieldGroupInput = createElemPropsHook(useFormFieldModel)(({state}) => {
return {
'aria-invalid': state.error === 'error' ? true : undefined,
'aria-describedby': state.id ? `hint-${state.id}` : undefined,
};
});

export const FormFieldGroupInput = createSubcomponent('input')({
displayName: 'FormField.Input',
modelHook: useFormFieldModel,
elemPropsHook: useFormFieldGroupInput,
})((elemProps: FormFieldGroupInputProps, Element) => {
return <Element {...handleCsProp(elemProps)} />;
});
50 changes: 50 additions & 0 deletions modules/preview-react/form-field/lib/FormFieldGroupList.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,50 @@
import React from 'react';
import {createSubcomponent} from '@workday/canvas-kit-react/common';

import {FlexProps} from '@workday/canvas-kit-react/layout';

import {createStencil, CSProps, calc, px2rem, handleCsProp} from '@workday/canvas-kit-styling';
import {brand, system} from '@workday/canvas-tokens-web';

import {useFormFieldModel} from './hooks';

export interface FormFieldGroupListProps extends CSProps, FlexProps {}

const formFieldGroupListStencil = createStencil({
base: {
display: 'flex',
flexDirection: 'column',
borderRadius: system.shape.x1,
gap: system.space.x2,
padding: `${px2rem(10)} ${system.space.x3} ${system.space.x2}`,
margin: `${calc.negate(system.space.x1)} ${calc.negate(system.space.x3)}`,
transition: '100ms box-shadow',
width: 'fit-content',
},
modifiers: {
error: {
error: {
boxShadow: `inset 0 0 0 ${px2rem(2)} ${brand.error.base}`,
},
alert: {
boxShadow: `inset 0 0 0 ${px2rem(1)} ${brand.alert.darkest}, inset 0 0 0 ${px2rem(3)} ${
brand.alert.base
}`,
},
},
},
});

export const FormFieldGroupList = createSubcomponent('div')({
displayName: 'FormFieldGroup.List',
modelHook: useFormFieldModel,
})<FormFieldGroupListProps>(({children, ...elemProps}, Element, model) => {
return (
<Element
data-width="ck-formfield-width"
{...handleCsProp(elemProps, formFieldGroupListStencil({error: model.state.error}))}
>
{children}
</Element>
);
});
2 changes: 1 addition & 1 deletion modules/preview-react/form-field/lib/FormFieldLabel.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -60,7 +60,7 @@ export const FormFieldLabel = createSubcomponent('label')({
displayName: 'FormField.Label',
modelHook: useFormFieldModel,
elemPropsHook: useFormFieldLabel,
})<FormFieldLabelProps>(({children, typeLevel, variant, ...elemProps}, Element) => {
})<FormFieldLabelProps>(({children, typeLevel, variant, ...elemProps}, Element, model) => {
return (
<Element {...mergeStyles(elemProps, formFieldLabelStencil({typeLevel, variant}))}>
{children}
Expand Down
17 changes: 13 additions & 4 deletions modules/preview-react/form-field/stories/FormField.stories.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@ import {Hint} from './examples/Hint';
import {FieldSet} from './examples/FieldSet';
import {Grow} from './examples/Grow';
import {ThemedError} from './examples/ThemedErrors';
import {GroupedInputs} from './examples/GroupedInputs';

<Meta title="Preview/Inputs/Form Field" component={FormField} />

Expand Down Expand Up @@ -102,12 +103,20 @@ for required fields are suffixed by a red asterisk.

<ExampleCodeBlock code={Required} />

### Field Set
### Grouped Inputs

Set the `as` prop of the `FormField` to `fieldset` and the `as` prop of the `FormField.Label` to
`legend` when using `RadioGroup` to ensure proper accessbility.
Use `FormFieldGroup` when you have a group of inputs that need to be associated to one another, like
`RadioGroup` or a group of `Checkbox`'s. `FormFieldGroup` renders a `fieldset` element and
`FormFieldGroup.Legend` renders a `legend` element. These elements will allow for correct
accessibility of grouped inputs.

<ExampleCodeBlock code={FieldSet} />
`FormFieldGroup` supports the same props of `FormField`:

- `error`: `"alert" | "error"` Defines the error around the whole group of inputs.
- `orientation`: `"horizontal" | "vertical"` Defines the legend placement.
- `isRequired`: `true` Defines if a group like RadioGroup is required.

<ExampleCodeBlock code={GroupedInputs} />

### Custom

Expand Down
47 changes: 26 additions & 21 deletions modules/preview-react/form-field/stories/examples/AllFields.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ import {TextArea} from '@workday/canvas-kit-react/text-area';
import {Switch} from '@workday/canvas-kit-react/switch';
import {calc, createStyles} from '@workday/canvas-kit-styling';
import {system} from '@workday/canvas-tokens-web';
import {FormFieldGroup} from '../../lib/FormFieldGroup';
mannycarrera4 marked this conversation as resolved.
Show resolved Hide resolved

const parentContainerStyles = createStyles({
flexDirection: 'column',
Expand Down Expand Up @@ -47,27 +48,31 @@ export const AllFields = () => {
</Select.Popper>
</Select>
</FormField>
<FormField as="fieldset" isRequired={true} error={'error'} orientation="horizontal" grow>
<FormField.Label as="legend">Radio Group Legend</FormField.Label>
<FormField.Container>
<FormField.Input as={RadioGroup}>
<RadioGroup.RadioButton value="deep-dish">Deep dish</RadioGroup.RadioButton>
<RadioGroup.RadioButton value="thin">Thin</RadioGroup.RadioButton>
<RadioGroup.RadioButton value="gluten-free">Gluten free</RadioGroup.RadioButton>
<RadioGroup.RadioButton value="cauliflower">Cauliflower</RadioGroup.RadioButton>
<RadioGroup.RadioButton value="butter">
Butter - the best thing to put on bread
</RadioGroup.RadioButton>
</FormField.Input>
<FormField.Hint>Error Message</FormField.Hint>
</FormField.Container>
</FormField>
<FormField as="fieldset" grow>
<FormField.Label as="legend">Checkbox Legend</FormField.Label>
<FormField.Input checked={true} as={Checkbox} label="Checkbox Label" />
<FormField.Input checked={false} as={Checkbox} label="Thin Crust" />
<FormField.Input checked={false} as={Checkbox} label="Extra Cheese" />
</FormField>
<FormFieldGroup error="error" orientation="horizontal" grow>
<FormFieldGroup.Legend>Choose Your Crust</FormFieldGroup.Legend>
<FormFieldGroup.Container>
<FormFieldGroup.List as={RadioGroup}>
<FormFieldGroup.Input as={RadioGroup.RadioButton} value="thin-crust">
Thin Crust
</FormFieldGroup.Input>
<FormFieldGroup.Input as={RadioGroup.RadioButton} value="hand-tossed">
Hand Tossed
</FormFieldGroup.Input>
<FormFieldGroup.Input as={RadioGroup.RadioButton} value="deep-dish">
Deep Dish
</FormFieldGroup.Input>
<FormFieldGroup.Input as={RadioGroup.RadioButton} value="cauliflower">
Cauliflower
</FormFieldGroup.Input>
</FormFieldGroup.List>
</FormFieldGroup.Container>
</FormFieldGroup>
<FormFieldGroup grow>
<FormFieldGroup.Legend>Checkbox Legend</FormFieldGroup.Legend>
<FormFieldGroup.Input checked={true} as={Checkbox} label="Checkbox Label" />
<FormFieldGroup.Input checked={false} as={Checkbox} label="Thin Crust" />
<FormFieldGroup.Input checked={false} as={Checkbox} label="Extra Cheese" />
</FormFieldGroup>

<FormField orientation="horizontal" grow>
<FormField.Label>Switch Label</FormField.Label>
Expand Down
Loading
Loading