feat: add common sets of props for inputs

main
Juan Olvera 9 months ago
parent ccfdecb318
commit 8449c8dd84

@ -0,0 +1,8 @@
type InputProps = {
label: string;
hideLabel?: boolean;
helpText?: string;
hasError?: boolean;
};
export type { InputProps };

@ -0,0 +1,3 @@
import * as T from "./Common.types";
export type { T };

@ -1,7 +1,7 @@
import * as React from "react"; import * as React from "react";
import { match, P } from "ts-pattern"; import { match, P } from "ts-pattern";
import * as T from "./Divider.types"; import * as T from "./Divider.types";
import { Modal } from "../Box"; import { Box } from "../Box";
import { cx } from "../../utils"; import { cx } from "../../utils";
import { dividerStyles } from "./Divider.styles"; import { dividerStyles } from "./Divider.styles";
@ -16,7 +16,7 @@ const Divider = React.forwardRef<
return match({ border }) return match({ border })
.with({ border: true }, () => ( .with({ border: true }, () => (
<div {...props} className={classes}> <div {...props} className={classes}>
<Modal className={cx(["bg-mono-border", "h-[2px]"])} /> <Box className={cx(["bg-mono-border", "h-[2px]"])} />
</div> </div>
)) ))
.otherwise(() => <div {...props} className={classes} ref={forwardedRef} />); .otherwise(() => <div {...props} className={classes} ref={forwardedRef} />);

@ -0,0 +1,35 @@
import * as React from "react";
import { Primitive } from "@radix-ui/react-primitive";
import { cva, VariantProps } from "class-variance-authority";
import { cx } from "../utils";
import * as Common from "./Common";
type HelpTextElement = React.ElementRef<typeof Primitive.p>;
type HelpTextProps = React.ComponentPropsWithoutRef<typeof Primitive.p> &
VariantProps<typeof styles> &
Pick<Common.T.InputProps, "hasError"> & {};
const styles = cva(["mt-2", "text-sm", "text-mono-text"], {
variants: {
hasError: {
true: ["text-mono-error"],
},
},
defaultVariants: {
hasError: false,
},
});
const HelpText = React.forwardRef<HelpTextElement, HelpTextProps>(
({ hasError, children, ...props }, forwardedRef) => {
const classes = cx(styles({ hasError }));
return (
<p {...props} className={classes} ref={forwardedRef}>
{children}
</p>
);
}
);
export { HelpText };

@ -4,6 +4,7 @@ import { NumericFormat } from "react-number-format";
import type * as T from "./Input.types"; import type * as T from "./Input.types";
import { Box } from "../Box"; import { Box } from "../Box";
import { Label } from "../Label"; import { Label } from "../Label";
import { HelpText } from "../HelpText";
import { cx } from "../../utils"; import { cx } from "../../utils";
import { inputStyles } from "./Input.styles"; import { inputStyles } from "./Input.styles";
import { match, P } from "ts-pattern"; import { match, P } from "ts-pattern";
@ -93,13 +94,7 @@ const Input = React.forwardRef<HTMLInputElement, T.InputProps>(
</Box> </Box>
{match(helpText) {match(helpText)
.with(P.not(P.nullish), () => ( .with(P.not(P.nullish), () => (
<p <HelpText hasError={hasError}>{helpText}</HelpText>
className={cx(["mt-2", "text-sm", "text-mono-text"], {
"text-mono-error": hasError,
})}
>
{helpText}
</p>
)) ))
.otherwise(() => null)} .otherwise(() => null)}
</Box> </Box>

@ -18,7 +18,42 @@ const options = [
export const Default: Story = { export const Default: Story = {
render: () => ( render: () => (
<Select placeholder="Select a fruit" tabIndex={0}> <Select label="Fruits" placeholder="Select a fruit" tabIndex={0}>
{options.map((option) => (
<SelectItem key={option.value} value={option.value}>
{option.label}
</SelectItem>
))}
</Select>
),
};
export const HelpText: Story = {
render: () => (
<Select
label="Fruits"
placeholder="Select a fruit"
tabIndex={0}
helpText="Select from an approved list of fruits."
>
{options.map((option) => (
<SelectItem key={option.value} value={option.value}>
{option.label}
</SelectItem>
))}
</Select>
),
};
export const WithError: Story = {
render: () => (
<Select
label="Fruits"
placeholder="Select a fruit"
tabIndex={0}
hasError
helpText="You must select one fruit."
>
{options.map((option) => ( {options.map((option) => (
<SelectItem key={option.value} value={option.value}> <SelectItem key={option.value} value={option.value}>
{option.label} {option.label}

@ -63,6 +63,9 @@ const selectStyles = cva(base, {
fullWidth: { fullWidth: {
true: "w-full", true: "w-full",
}, },
hasError: {
true: "border-mono-error",
},
}, },
defaultVariants: { defaultVariants: {
fullWidth: false, fullWidth: false,

@ -1,15 +1,32 @@
import * as React from "react"; import * as React from "react";
import * as $ from "@radix-ui/react-select"; import * as $ from "@radix-ui/react-select";
import { match, P } from "ts-pattern";
import { FaCheck, FaChevronDown, FaChevronUp } from "react-icons/fa"; import { FaCheck, FaChevronDown, FaChevronUp } from "react-icons/fa";
import * as T from "./Select.types"; import * as T from "./Select.types";
import * as styles from "./Select.styles"; import * as styles from "./Select.styles";
import { cx } from "../../utils"; import { cx } from "../../utils";
import { Box } from "../Box"; import { Box } from "../Box";
import { Label } from "../Label"; import { Label } from "../Label";
import { HelpText } from "../HelpText";
const Select = React.forwardRef<T.SelectElement, T.SelectProps>( const Select = React.forwardRef<T.SelectElement, T.SelectProps>(
({ hideLabel = false, fullWidth, children, className, ...props }, ref) => { (
const classes = cx([styles.selectStyles({ fullWidth })], className); {
label,
hideLabel = false,
helpText,
fullWidth,
hasError,
children,
className,
...props
},
ref
) => {
const classes = cx(
[styles.selectStyles({ fullWidth, hasError })],
className
);
return ( return (
<Box className={cx(["relative"])}> <Box className={cx(["relative"])}>
<Label <Label
@ -18,7 +35,7 @@ const Select = React.forwardRef<T.SelectElement, T.SelectProps>(
"sr-only": hideLabel, "sr-only": hideLabel,
})} })}
> >
Select {label}
</Label> </Label>
<Box className={cx(["mt-1"])}> <Box className={cx(["mt-1"])}>
<$.Root> <$.Root>
@ -46,6 +63,11 @@ const Select = React.forwardRef<T.SelectElement, T.SelectProps>(
</$.Portal> </$.Portal>
</$.Root> </$.Root>
</Box> </Box>
{match(helpText)
.with(P.not(P.nullish), (helpText) => (
<HelpText hasError={hasError}>{helpText}</HelpText>
))
.otherwise(() => null)}
</Box> </Box>
); );
} }

@ -1,5 +1,6 @@
import * as React from "react"; import * as React from "react";
import * as $ from "@radix-ui/react-select"; import * as $ from "@radix-ui/react-select";
import * as Common from "../Common";
import { VariantProps } from "class-variance-authority"; import { VariantProps } from "class-variance-authority";
import { selectStyles } from "./Select.styles"; import { selectStyles } from "./Select.styles";
@ -16,9 +17,8 @@ type SelectSection = {
type SelectElement = React.ElementRef<typeof $.Trigger>; type SelectElement = React.ElementRef<typeof $.Trigger>;
type SelectProps = React.ComponentPropsWithoutRef<typeof $.Trigger> & type SelectProps = React.ComponentPropsWithoutRef<typeof $.Trigger> &
VariantProps<typeof selectStyles> & { VariantProps<typeof selectStyles> &
hideLabel?: boolean; Common.T.InputProps & {};
};
type SelectItemElement = React.ElementRef<typeof $.Item>; type SelectItemElement = React.ElementRef<typeof $.Item>;

Loading…
Cancel
Save