Skip to content

Commit

Permalink
feat: refactor away from size to variant
Browse files Browse the repository at this point in the history
BREAKING CHANGE: changes NDSProvider `size` prop to `variant`.

The `size` prop was originally used sparingly in some components like the
Button and the Icon to resize those components.

It was later extended to make all interactive components large enough to
be used on a touch screen, through changing the `size` prop directly or
by passing a `size` prop to the NDSProvider globally.

With this change, we retain the use of the `size` prop for select
components, and introduce a `variant` prop that can be passed either to
individual components or the NDSProvider globally with the value of
either `desktop` or `touch`.
  • Loading branch information
haideralsh committed Nov 7, 2024
1 parent 8332de0 commit 7fb639a
Show file tree
Hide file tree
Showing 54 changed files with 328 additions and 292 deletions.
11 changes: 5 additions & 6 deletions src/AsyncSelect/AsyncSelect.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ import { MaybeFieldLabel } from "../FieldLabel";
import { InlineValidation } from "../Validation";
import customStyles from "../Select/customReactSelectStyles";
import { getSubset } from "../utils/subset";
import { ComponentSize, useComponentSize } from "../NDSProvider/ComponentSizeContext";
import { ComponentVariant, useComponentVariant } from "../NDSProvider/ComponentVariantContext";
import {
SelectControl,
SelectMultiValue,
Expand All @@ -22,12 +22,11 @@ import {
SelectMenu,
SelectOption,
} from "./AsyncSelectComponents";
import { DefaultNDSThemeType } from "../theme.type";

type AsyncCustomProps<Option, IsMulti extends boolean, Group extends GroupBase<Option>> = {
autocomplete?: AsyncProps<Option, IsMulti, Group>["isSearchable"];
labelText?: string;
size?: ComponentSize;
variant?: ComponentVariant;
requirementText?: string;
helpText?: ReactNode;
disabled?: AsyncProps<Option, IsMulti, Group>["isDisabled"];
Expand Down Expand Up @@ -80,7 +79,7 @@ const AsyncSelect = forwardRef(
defaultOptions,
loadOptions,
isClearable,
size,
variant,
...props
}: AsyncSelectProps<Option, IsMulti, Group>,
ref:
Expand All @@ -93,7 +92,7 @@ const AsyncSelect = forwardRef(
const spaceProps = getSubset(props, propTypes.space);
const error = !!(errorMessage || errorList);

const componentSize = useComponentSize(size);
const componentVariant = useComponentVariant(variant);

return (
<Field {...spaceProps}>
Expand Down Expand Up @@ -132,7 +131,7 @@ const AsyncSelect = forwardRef(
theme={theme as any}
components={{
Option: (props) => (
<SelectOption size={componentSize} {...props}>
<SelectOption variant={componentVariant} {...props}>
{props.children}
</SelectOption>
),
Expand Down
17 changes: 11 additions & 6 deletions src/AsyncSelect/AsyncSelectComponents.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -9,9 +9,9 @@ import {
MenuProps,
MultiValueProps,
} from "react-select";
import { components, GroupBase } from "react-select";
import { OptionProps } from "react-windowed-select";
import { ComponentSize, useComponentSize } from "../NDSProvider/ComponentSizeContext";
import { components, type GroupBase } from "react-select";
import type { OptionProps } from "react-windowed-select";
import { type ComponentVariant, useComponentVariant } from "../NDSProvider/ComponentVariantContext";
import { StyledOption } from "../Select/SelectOption";

export const SelectControl = <Option, IsMulti extends boolean, Group extends GroupBase<Option>>(
Expand Down Expand Up @@ -97,12 +97,17 @@ export const SelectMenu = <Option, IsMulti extends boolean, Group extends GroupB
};

export function SelectOption<Option, IsMulti extends boolean, Group extends GroupBase<Option>>(
props: OptionProps<Option, IsMulti, Group> & { size?: ComponentSize }
props: OptionProps<Option, IsMulti, Group> & { variant?: ComponentVariant }
) {
const size = useComponentSize(props.size);
const variant = useComponentVariant(props.variant);

return (
<StyledOption isSelected={props.isSelected} isFocused={props.isFocused} size={size} data-testid="select-option">
<StyledOption
isSelected={props.isSelected}
isFocused={props.isFocused}
variant={variant}
data-testid="select-option"
>
<components.Option {...props}>{props.children}</components.Option>
</StyledOption>
);
Expand Down
2 changes: 1 addition & 1 deletion src/BrandedNavBar/BrandLogoContainer.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,7 @@ const BrandLogoContainer = ({
to={brandingLinkTo}
as={brandingLinkComponent}
underline={false}
size="medium"
variant="desktop"
style={{ display: "block" }}
>
{logoSrc && <img src={logoSrc} style={{ maxWidth: MAX_LOGO_WIDTH, maxHeight: MAX_LOGO_HEIGHT }} alt="" />}
Expand Down
2 changes: 1 addition & 1 deletion src/Breadcrumbs/Breadcrumbs.story.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,7 @@ export const _Breadcrumbs = () => (

const DashedBreadcrumbs = dashed(Breadcrumbs);

export const WithDifferentSizes = () => (
export const WithDifferentVariants = () => (
<Flex gap="x2" alignItems="flex-start">
<DashedBreadcrumbs>
<Link href="/">Default</Link>
Expand Down
10 changes: 5 additions & 5 deletions src/Breadcrumbs/Breadcrumbs.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ import React, { isValidElement } from "react";
import { Flex } from "../Flex";
import { Icon } from "../Icon";
import { FlexProps } from "../Flex/Flex";
import { ComponentSize, useComponentSize } from "../NDSProvider/ComponentSizeContext";
import { ComponentVariant, useComponentVariant } from "../NDSProvider/ComponentVariantContext";
import BreadcrumbsList from "./BreadcrumbsList";
import { BreadcrumbsListItem, BreadcrumbsListSeparator } from "./BreadcrumbsListItem";

Expand All @@ -17,16 +17,16 @@ const insertSeparators = (items: JSX.Element[]) => {
}, []);
};

type BreadcrumbsProps = Omit<FlexProps, "size"> & { size?: ComponentSize };
type BreadcrumbsProps = FlexProps & { variant?: ComponentVariant };

const Breadcrumbs = ({ size, as = "nav", children, ...props }: BreadcrumbsProps) => {
const componentSize = useComponentSize(size);
const Breadcrumbs = ({ variant, as = "nav", children, ...props }: BreadcrumbsProps) => {
const componentVariant = useComponentVariant(variant);

const allItems = React.Children.map(children, (child, index) => {
if (!isValidElement(child)) return null;

return (
<BreadcrumbsListItem size={componentSize} key={`child-${index}`}>
<BreadcrumbsListItem variant={componentVariant} key={`child-${index}`}>
{child}
</BreadcrumbsListItem>
);
Expand Down
9 changes: 4 additions & 5 deletions src/Breadcrumbs/BreadcrumbsListItem.tsx
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import styled from "styled-components";
import { space, color, flexbox, layout, variant } from "styled-system";
import { ComponentSize } from "../NDSProvider/ComponentSizeContext";
import { ComponentVariant } from "../NDSProvider/ComponentVariantContext";

export const BreadcrumbsListSeparator = styled.li(
({ theme }) => ({
Expand All @@ -22,7 +22,7 @@ export const BreadcrumbsListSeparator = styled.li(
flexbox
);

export const BreadcrumbsListItem = styled.li<{ size: ComponentSize }>(
export const BreadcrumbsListItem = styled.li<{ variant: ComponentVariant }>(
({ theme }) => ({
margin: 0,
listStyle: "none",
Expand All @@ -42,16 +42,15 @@ export const BreadcrumbsListItem = styled.li<{ size: ComponentSize }>(
},
}),
variant({
prop: "size",
variants: {
large: {
touch: {
"a, p": {
py: "x2",
px: "x0",
fontSize: "medium",
},
},
medium: {
desktop: {
"a, p": {
py: "0",
px: "0",
Expand Down
5 changes: 1 addition & 4 deletions src/Button/Button.story.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -25,24 +25,21 @@ _QuietButton.story = {
name: "QuietButton",
};

export const WithDifferentSizes = () => (
export const WithDifferentVariants = () => (
<Flex flexDirection="column" gap="x1">
<Flex alignItems="center" gap="x1">
<Button size="small">Create project</Button>
<Button size="medium">Create project</Button>
<Button size="large">Create project</Button>
</Flex>

<Flex alignItems="center" gap="x1">
<PrimaryButton size="small">Create project</PrimaryButton>
<PrimaryButton size="medium">Create project</PrimaryButton>
<PrimaryButton size="large">Create project</PrimaryButton>
</Flex>

<Flex alignItems="center" gap="x1">
<QuietButton size="small">Create project</QuietButton>
<QuietButton size="medium">Create project</QuietButton>
<QuietButton size="large">Create project</QuietButton>
</Flex>
</Flex>
);
Expand Down
42 changes: 30 additions & 12 deletions src/Button/Button.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -3,17 +3,20 @@ import styled, { useTheme } from "styled-components";
import { space, SpaceProps, variant } from "styled-system";
import { Icon } from "../Icon";
import { DefaultNDSThemeType } from "../theme.type";
import { useComponentSize, ComponentSize as ContextComponentSize } from "../NDSProvider/ComponentSizeContext";
import {
useComponentVariant,
ComponentVariant as ContextComponentSize,
ComponentVariant,
} from "../NDSProvider/ComponentVariantContext";
import { subPx } from "../utils";

type ComponentSize = "small" | "medium" | "large";

export type ButtonProps = SpaceProps &
React.ComponentPropsWithRef<"button"> & {
className?: string;
icon?: any;
iconSide?: "left" | "right";
size?: ComponentSize;
size?: "small" | "medium";
variant?: ComponentVariant;
fullWidth?: boolean;
asLink?: boolean;
children?: React.ReactNode;
Expand Down Expand Up @@ -71,30 +74,45 @@ const WrapperButton = styled.button<ButtonProps>(
padding: `${subPx(theme.space.half)} ${theme.space.x1}`,
},

large: {
medium: {
fontSize: "medium",
padding: `${subPx(theme.space.x2)} ${theme.space.x3}`,
padding: `${subPx(theme.space.x1)} ${theme.space.x2}`,
},

medium: {
},
}),
({ theme }) =>
variant({
variants: {
desktop: {
fontSize: "medium",
padding: `${subPx(theme.space.x1)} ${theme.space.x2}`,
},
touch: {
fontSize: "medium",
padding: `${subPx(theme.space.x2)} ${theme.space.x3}`,
},
},
}),
space
);

const Button: React.FC<React.PropsWithChildren<ButtonProps>> = React.forwardRef(
({ children, iconSide = "right", icon, className, asLink, size, ...props }: ButtonProps, ref) => {
const Button = React.forwardRef<HTMLButtonElement, ButtonProps>(
({ children, iconSide = "right", icon, className, asLink, variant, size, ...props }: ButtonProps, ref) => {
const {
lineHeights: { smallTextCompressed },
} = useTheme();

const componentSize = useComponentSize(size as ContextComponentSize);
const componentVariant = useComponentVariant(variant as ContextComponentSize);

return (
<WrapperButton as={asLink ? "a" : "button"} ref={ref} className={className} size={componentSize} {...props}>
<WrapperButton
as={asLink ? "a" : "button"}
ref={ref}
className={className}
variant={componentVariant}
size={size}
{...props}
>
{icon && iconSide === "left" && <Icon size={`${smallTextCompressed}em`} mr="half" icon={icon} />}
{children}
{icon && iconSide === "right" && <Icon size={`${smallTextCompressed}em`} ml="half" icon={icon} />}
Expand Down
2 changes: 1 addition & 1 deletion src/Button/IconicButton.story.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -127,7 +127,7 @@ export const WithACustomFontSize = () => (

const DashedIconicButton = dashed(IconicButton);

export const WithDifferentSizes = () => (
export const WithDifferentVariants = () => (
<Flex gap="x2" alignItems="flex-start">
<DashedIconicButton tooltip="Stop job" icon="close">
Default size
Expand Down
15 changes: 7 additions & 8 deletions src/Button/IconicButton.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -7,10 +7,10 @@ import icons from "@nulogy/icons";
import { Icon } from "../Icon";
import { Text } from "../Type";
import { DefaultNDSThemeType } from "../theme.type";
import { ComponentSize, useComponentSize } from "../NDSProvider/ComponentSizeContext";
import { ComponentVariant, useComponentVariant } from "../NDSProvider/ComponentVariantContext";

interface BaseProps {
size?: ComponentSize;
variant?: ComponentVariant;
color?: string;
labelHidden?: boolean;
icon?: string;
Expand Down Expand Up @@ -103,13 +103,12 @@ const WrapperButton = styled.button<IconicButtonProps>(
paddingRight: theme.space.none,
}),
variant({
prop: "size",
variants: {
large: {
touch: {
py: "x1",
px: "none",
},
medium: {
desktop: {
py: "half",
px: "none",
},
Expand All @@ -130,20 +129,20 @@ const IconicButton = React.forwardRef<HTMLButtonElement, IconicButtonProps>(
iconSize = "x3",
fontSize,
tooltip,
size,
variant,
...props
},
forwardedRef
) => {
const componentSize = useComponentSize(size);
const componentVariant = useComponentVariant(variant);

return (
<WrapperButton
ref={forwardedRef}
aria-label={props["aria-label"] ? props["aria-label"] : typeof children === "string" ? children : undefined}
className={className}
hoverBackgroundColor={hoverBackgroundColor}
size={componentSize}
variant={componentVariant}
{...props}
>
<Manager>
Expand Down
2 changes: 1 addition & 1 deletion src/Checkbox/Checkbox.story.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -100,7 +100,7 @@ SetToRequired.story = {

const DashedCheckbox = dashed(Checkbox);

export const WithDifferentSizes = () => (
export const WithDifferentVariants = () => (
<Flex gap="x2" alignItems="flex-start">
<DashedCheckbox id="checkbox-1" labelText="I am a default sized Checkbox" />
<DashedCheckbox id="checkbox-1" size="medium" labelText="I am a medium sized Checkbox" />
Expand Down
10 changes: 5 additions & 5 deletions src/Checkbox/Checkbox.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -8,15 +8,15 @@ import { ClickInputLabel } from "../utils";
import { getSubset, omitSubset } from "../utils/subset";
import { DefaultNDSThemeType } from "../theme.type";
import { addStyledProps } from "../StyledProps";
import { ComponentSize, useComponentSize } from "../NDSProvider/ComponentSizeContext";
import { ComponentVariant, useComponentVariant } from "../NDSProvider/ComponentVariantContext";

type NativeInputProps = Omit<React.ComponentPropsWithRef<"input">, "size">;

type CheckboxProps = NativeInputProps &
SpaceProps & {
children?: React.ReactNode;
htmlSize?: number;
size?: ComponentSize;
variant?: ComponentVariant;
labelText?: string;
checked?: boolean;
defaultChecked?: boolean;
Expand Down Expand Up @@ -131,15 +131,15 @@ const CheckboxInput = styled.input<CheckboxProps>((props) => ({
type Ref = HTMLInputElement;

const Checkbox = forwardRef<Ref, CheckboxProps>((props, ref) => {
const { size, className, labelText, disabled, checked, required, error, indeterminate } = props;
const { variant, className, labelText, disabled, checked, required, error, indeterminate } = props;

const componentSize = useComponentSize(size);
const componentVariant = useComponentVariant(variant);
const spaceProps = getSubset(props, propTypes.space);
const restProps = omitSubset(props, propTypes.space);

return (
<Box className={className} px="0" {...spaceProps}>
<ClickInputLabel size={componentSize} disabled={disabled}>
<ClickInputLabel variant={componentVariant} disabled={disabled}>
<CheckboxInput
type="checkbox"
required={required}
Expand Down
2 changes: 1 addition & 1 deletion src/DatePicker/DatePicker.story.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -47,7 +47,7 @@ WithCustomDateFormat.story = {
name: "with custom date format",
};

export const WithDifferentSizes = () => (
export const WithDifferentVariants = () => (
<Flex gap="x2" alignItems="flex-start">
<DatePicker
selected={select("selected", selectedDateExamples, selectedDateExamples[0], "selected")}
Expand Down
Loading

0 comments on commit 7fb639a

Please sign in to comment.