Skip to content

Commit

Permalink
Primitive fields cleanup - split primitive props (aws-amplify#572)
Browse files Browse the repository at this point in the history
  • Loading branch information
reesscot authored Oct 26, 2021
1 parent cceb017 commit ad490a7
Show file tree
Hide file tree
Showing 10 changed files with 191 additions and 64 deletions.
32 changes: 8 additions & 24 deletions packages/react/src/primitives/Checkbox/Checkbox.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -8,34 +8,26 @@ import { Text } from '../Text';
import { VisuallyHidden } from '../VisuallyHidden';
import { CheckboxProps } from '../types/checkbox';
import { Primitive } from '../types/view';
import { splitPrimitiveProps } from '../shared/styleUtils';
import { ComponentClassNames } from '../shared/constants';
import { useTestId } from '../utils/testUtils';

export const Checkbox: Primitive<CheckboxProps, 'input'> = ({
alignContent,
alignItems,
backgroundColor,
checked,
children,
className,
color,
defaultChecked,
direction,
hasError,
id,
isDisabled,
isReadOnly,
isRequired,
justifyContent,
gap,
name,
onChange: onChangeProp,
size,
testId,
value,
wrap,
...rest
..._rest
}) => {
const { baseStyleProps, flexContainerStyleProps, rest } =
splitPrimitiveProps(_rest);

// controlled way should always override uncontrolled way
const initialChecked = checked !== undefined ? checked : defaultChecked;

Expand All @@ -50,17 +42,12 @@ export const Checkbox: Primitive<CheckboxProps, 'input'> = ({

return (
<Flex
alignContent={alignContent}
alignItems={alignItems}
as="label"
className={classNames(ComponentClassNames.Checkbox, className)}
data-disabled={isDisabled}
direction={direction}
gap={gap}
justifyContent={justifyContent}
wrap={wrap}
testId={testId}
{...rest}
{...baseStyleProps}
{...flexContainerStyleProps}
>
<VisuallyHidden>
<Input
Expand All @@ -69,14 +56,11 @@ export const Checkbox: Primitive<CheckboxProps, 'input'> = ({
defaultChecked={defaultChecked}
id={id}
isDisabled={isDisabled}
isReadOnly={isReadOnly}
isRequired={isRequired}
name={name}
onBlur={onBlur}
onChange={onChange}
onFocus={onFocus}
type="checkbox"
value={value}
{...rest}
/>
</VisuallyHidden>
<Flex
Expand Down
16 changes: 3 additions & 13 deletions packages/react/src/primitives/RadioGroupField/RadioGroupField.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -9,29 +9,25 @@ import { RadioGroupFieldProps, Primitive } from '../types';
import { ComponentClassNames } from '../shared/constants';
import { useStableId } from '../shared/utils';

export const RadioGroupField: Primitive<RadioGroupFieldProps, 'input'> = ({
alignContent,
alignItems,
// Note: RadioGroupField doesn't extend the JSX.IntrinsicElements<'input'> types (instead extending 'typeof Flex')
// because all rest props are passed to Flex container
export const RadioGroupField: Primitive<RadioGroupFieldProps, typeof Flex> = ({
children,
className,
defaultValue,
descriptiveText,
direction = 'column',
errorMessage,
gap,
hasError = false,
id,
isDisabled,
isRequired,
isReadOnly,
justifyContent,
label,
labelHidden = false,
onChange,
name,
size,
value,
wrap,
...rest
}) => {
const fieldId = useStableId(id);
Expand Down Expand Up @@ -62,18 +58,12 @@ export const RadioGroupField: Primitive<RadioGroupFieldProps, 'input'> = ({

return (
<Flex
alignContent={alignContent}
alignItems={alignItems}
className={classNames(
ComponentClassNames.Field,
ComponentClassNames.RadioGroupField,
className
)}
data-size={size}
direction={direction}
gap={gap}
justifyContent={justifyContent}
wrap={wrap}
{...rest}
>
<Label id={fieldId} visuallyHidden={labelHidden}>
Expand Down
20 changes: 7 additions & 13 deletions packages/react/src/primitives/StepperField/StepperField.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -15,40 +15,38 @@ import { ComponentClassNames } from '../shared/constants';
import { SharedText } from '../shared/i18n';
import { useStableId } from '../shared/utils';
import { Primitive } from '../types/view';
import { splitPrimitiveProps } from '../shared/styleUtils';

export const DECREASE_ICON = 'decrease-icon';
export const INCREASE_ICON = 'increase-icon';

export const StepperField: Primitive<StepperFieldProps, 'input'> = (props) => {
const {
alignContent,
alignItems,
className,
descriptiveText,
// this is only required in useStepper hook but deconstruct here to remove its existence in rest
defaultValue,
direction,
errorMessage,
gap,
hasError = false,
id,
isDisabled,
isReadOnly,
isRequired,
justifyContent,
label,
labelHidden = false,
onStepChange,
size,
testId,
// this is only required in useStepper hook but deconstruct here to remove its existence in rest
value: controlledValue,
wrap,
...rest
..._rest
} = props;

const fieldId = useStableId(id);

const { baseStyleProps, flexContainerStyleProps, rest } =
splitPrimitiveProps(_rest);

const {
step,
value,
Expand All @@ -64,19 +62,14 @@ export const StepperField: Primitive<StepperFieldProps, 'input'> = (props) => {

return (
<Flex
alignContent={alignContent}
alignItems={alignItems}
className={classNames(
ComponentClassNames.Field,
ComponentClassNames.StepperField,
className
)}
data-size={size}
direction={direction}
gap={gap}
justifyContent={justifyContent}
testId={testId}
wrap={wrap}
{...flexContainerStyleProps}
>
<Label htmlFor={fieldId} visuallyHidden={labelHidden}>
{label}
Expand Down Expand Up @@ -130,6 +123,7 @@ export const StepperField: Primitive<StepperFieldProps, 'input'> = (props) => {
size={size}
type="number"
value={inputValue}
{...baseStyleProps}
{...rest}
/>
</FieldGroup>
Expand Down
21 changes: 8 additions & 13 deletions packages/react/src/primitives/TextField/TextField.tsx
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
import classNames from 'classnames';

import { ComponentClassNames } from '../shared/constants';
import { splitPrimitiveProps } from '../shared/styleUtils';
import { FieldDescription, FieldErrorMessage } from '../Field';
import { FieldGroup } from '../FieldGroup';
import { Flex } from '../Flex';
Expand Down Expand Up @@ -28,16 +29,11 @@ export const TextField = <Multiline extends boolean>(
props: PrimitiveProps<TextFieldProps<Multiline>, 'input' | 'textarea'>
) => {
const {
alignContent,
alignItems,
className,
descriptiveText,
direction = 'column',
errorMessage,
gap,
hasError = false,
id,
justifyContent,
label,
labelHidden = false,
outerEndComponent,
Expand All @@ -48,12 +44,14 @@ export const TextField = <Multiline extends boolean>(
type, // remove from rest to prevent passing as DOM attribute to textarea
size,
testId,
wrap,
...rest
..._rest
} = props;

const fieldId = useStableId(id);

const { flexContainerStyleProps, baseStyleProps, rest } =
splitPrimitiveProps(_rest);

let control: JSX.Element = null;
if (isTextAreaField(props)) {
const { rows } = props;
Expand All @@ -63,6 +61,7 @@ export const TextField = <Multiline extends boolean>(
id={fieldId}
rows={rows ?? DEFAULT_ROW_COUNT}
size={size}
{...baseStyleProps}
{...rest}
/>
);
Expand All @@ -74,26 +73,22 @@ export const TextField = <Multiline extends boolean>(
id={fieldId}
size={size}
type={type}
{...baseStyleProps}
{...rest}
/>
);
}

return (
<Flex
alignContent={alignContent}
alignItems={alignItems}
className={classNames(
ComponentClassNames.Field,
ComponentClassNames.TextField,
className
)}
data-size={size}
direction={direction}
gap={gap}
justifyContent={justifyContent}
testId={testId}
wrap={wrap}
{...flexContainerStyleProps}
>
<Label htmlFor={fieldId} visuallyHidden={labelHidden}>
{label}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,10 +6,16 @@ import {
convertGridSpan,
convertStylePropsToStyleObj,
getGridSpan,
splitPrimitiveProps,
useNonStyleProps,
useTransformStyleProps,
} from '../styleUtils';
import { ComponentPropsToStylePropsMap, ViewProps } from '../../types';
import {
BaseStyleProps,
ComponentPropsToStylePropsMap,
FlexContainerStyleProps,
ViewProps,
} from '../../types';
import { Breakpoint } from '../../types/responsive';

const props: ViewProps = {
Expand Down Expand Up @@ -262,3 +268,47 @@ describe('useTransformStyleProps', () => {
);
});
});

describe('splitPrimitiveProps', () => {
it('should split props into base, flex and rest', () => {
const baseStyleProps: BaseStyleProps = {
backgroundColor: 'yellow',
alignSelf: 'baseline',
area: 'auto',
basis: 'content',
border: '1px solid black',
borderRadius: '2px',
};
const flexContainerStyleProps: FlexContainerStyleProps = {
alignContent: 'space-around',
alignItems: 'baseline',
columnGap: '2rem',
direction: 'column-reverse',
gap: '2rem',
justifyContent: 'space-around',
rowGap: '4rem',
wrap: 'nowrap',
};
const restProps = {
type: 'textarea',
rows: '4',
autoComplete: 'current-password',
name: 'password',
placeholder: 'Password',
};

const {
baseStyleProps: resultBaseStyleProps,
flexContainerStyleProps: resultFlexContainerStyleProps,
rest: resultRest,
} = splitPrimitiveProps({
...baseStyleProps,
...flexContainerStyleProps,
...restProps,
});

expect(resultRest).toEqual(restProps);
expect(resultFlexContainerStyleProps).toEqual(flexContainerStyleProps);
expect(resultBaseStyleProps).toEqual(baseStyleProps);
});
});
Loading

0 comments on commit ad490a7

Please sign in to comment.