feat: add card, divider and input
							parent
							
								
									d16d06da3b
								
							
						
					
					
						commit
						fa840257d3
					
				@ -0,0 +1,59 @@
 | 
				
			|||||||
 | 
					import React from "react";
 | 
				
			||||||
 | 
					import type { Meta, StoryObj } from "@storybook/react";
 | 
				
			||||||
 | 
					import * as Card from "./Card";
 | 
				
			||||||
 | 
					import { Box } from "../Box";
 | 
				
			||||||
 | 
					import { Input } from "../Input";
 | 
				
			||||||
 | 
					import { Button } from "../Button";
 | 
				
			||||||
 | 
					import { cx } from "../../utils";
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					const meta: Meta<typeof Card.$> = {
 | 
				
			||||||
 | 
					  title: "UI/Card",
 | 
				
			||||||
 | 
					  component: Card.$,
 | 
				
			||||||
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					export default meta;
 | 
				
			||||||
 | 
					type Story = StoryObj<typeof Card>;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					export const Default: Story = {
 | 
				
			||||||
 | 
					  render: () => (
 | 
				
			||||||
 | 
					    <Box className={cx(["w-96"])}>
 | 
				
			||||||
 | 
					      <Card.$ paddless>
 | 
				
			||||||
 | 
					        <Card.Header>
 | 
				
			||||||
 | 
					          <Card.Title>Create account</Card.Title>
 | 
				
			||||||
 | 
					          <Card.Description>
 | 
				
			||||||
 | 
					            Manage all your transactions in one place.
 | 
				
			||||||
 | 
					          </Card.Description>
 | 
				
			||||||
 | 
					        </Card.Header>
 | 
				
			||||||
 | 
					        <Card.Body>
 | 
				
			||||||
 | 
					          <form onSubmit={(event) => event.preventDefault()}>
 | 
				
			||||||
 | 
					            <Input label="Name" fullWidth />
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            <Box className={cx(["py-2"])} />
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            <Input label="Type" fullWidth />
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            <Box className={cx(["py-2"])} />
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            <Input label="Balance" money fullWidth />
 | 
				
			||||||
 | 
					          </form>
 | 
				
			||||||
 | 
					        </Card.Body>
 | 
				
			||||||
 | 
					        <Card.Footer className={cx(["flex", "justify-between"])}>
 | 
				
			||||||
 | 
					          <Button>Cancel</Button>
 | 
				
			||||||
 | 
					          <Button intent="primary">Save</Button>
 | 
				
			||||||
 | 
					        </Card.Footer>
 | 
				
			||||||
 | 
					      </Card.$>
 | 
				
			||||||
 | 
					    </Box>
 | 
				
			||||||
 | 
					  ),
 | 
				
			||||||
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					// Another way to use this component alone is to import the named export
 | 
				
			||||||
 | 
					// import { Card } from './Card';
 | 
				
			||||||
 | 
					export const Paddless: Story = {
 | 
				
			||||||
 | 
					  render: () => (
 | 
				
			||||||
 | 
					    <Box className={cx(["w-96"])}>
 | 
				
			||||||
 | 
					      <Card.$>
 | 
				
			||||||
 | 
					        <p>Dummy content while we create the input components.</p>
 | 
				
			||||||
 | 
					      </Card.$>
 | 
				
			||||||
 | 
					    </Box>
 | 
				
			||||||
 | 
					  ),
 | 
				
			||||||
 | 
					};
 | 
				
			||||||
@ -0,0 +1,25 @@
 | 
				
			|||||||
 | 
					import { cva } from "class-variance-authority";
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					const base = [
 | 
				
			||||||
 | 
					  "overflow-hidden",
 | 
				
			||||||
 | 
					  "rounded-lg",
 | 
				
			||||||
 | 
					  "bg-white",
 | 
				
			||||||
 | 
					  "border-2",
 | 
				
			||||||
 | 
					  "divide-y",
 | 
				
			||||||
 | 
					  "divide-y-2",
 | 
				
			||||||
 | 
					  "text-mono-text",
 | 
				
			||||||
 | 
					];
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					const cardStyles = cva(base, {
 | 
				
			||||||
 | 
					  variants: {
 | 
				
			||||||
 | 
					    paddless: {
 | 
				
			||||||
 | 
					      true: ["p-0"],
 | 
				
			||||||
 | 
					      false: ["px-4", "py-4", "sm:px-6", "divide-y-0"],
 | 
				
			||||||
 | 
					    },
 | 
				
			||||||
 | 
					  },
 | 
				
			||||||
 | 
					  defaultVariants: {
 | 
				
			||||||
 | 
					    paddless: false,
 | 
				
			||||||
 | 
					  },
 | 
				
			||||||
 | 
					});
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					export { cardStyles };
 | 
				
			||||||
@ -0,0 +1,24 @@
 | 
				
			|||||||
 | 
					import * as React from "react";
 | 
				
			||||||
 | 
					import { Primitive } from "@radix-ui/react-primitive";
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					import * as T from "./Card.types";
 | 
				
			||||||
 | 
					import { cardStyles } from "./Card.styles";
 | 
				
			||||||
 | 
					import { Header, Title, Description, Body, Footer } from "./components";
 | 
				
			||||||
 | 
					import { cx } from "../../utils";
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					const Card = React.forwardRef<T.CardElement, T.CardProps>(
 | 
				
			||||||
 | 
					  ({ children, paddless, ...props }, forwardedRef) => {
 | 
				
			||||||
 | 
					    const classes = cx(cardStyles({ paddless }), props.className);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    return (
 | 
				
			||||||
 | 
					      <Primitive.div {...props} className={classes} ref={forwardedRef}>
 | 
				
			||||||
 | 
					        {children}
 | 
				
			||||||
 | 
					      </Primitive.div>
 | 
				
			||||||
 | 
					    );
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					// Root element
 | 
				
			||||||
 | 
					const $ = Card;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					export { $, Card, Header, Title, Body, Description, Footer };
 | 
				
			||||||
@ -0,0 +1,13 @@
 | 
				
			|||||||
 | 
					import { ComponentPropsWithRef, ElementRef } from "react";
 | 
				
			||||||
 | 
					import { Primitive } from "@radix-ui/react-primitive";
 | 
				
			||||||
 | 
					import { VariantProps } from "class-variance-authority";
 | 
				
			||||||
 | 
					import { cardStyles } from "./Card.styles";
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					type CardElement = ElementRef<typeof Primitive.div>;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					type CardProps = Omit<ComponentPropsWithRef<typeof Primitive.div>, "asChild"> &
 | 
				
			||||||
 | 
					  VariantProps<typeof cardStyles> & {
 | 
				
			||||||
 | 
					    paddless?: boolean;
 | 
				
			||||||
 | 
					  };
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					export type { CardElement, CardProps };
 | 
				
			||||||
@ -0,0 +1,20 @@
 | 
				
			|||||||
 | 
					import * as React from "react";
 | 
				
			||||||
 | 
					import { Box } from "../../Box";
 | 
				
			||||||
 | 
					import { cx } from "../../../utils";
 | 
				
			||||||
 | 
					import { styles } from "./styles";
 | 
				
			||||||
 | 
					import { HTMLAttributes } from "react";
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					type BodyProps = HTMLAttributes<HTMLDivElement> & React.PropsWithChildren<{}>;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					type Body = (props: BodyProps) => React.ReactElement | null;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					const Body: Body = ({ children, ...props }) => {
 | 
				
			||||||
 | 
					  const classes = cx(styles, props.className);
 | 
				
			||||||
 | 
					  return (
 | 
				
			||||||
 | 
					    <Box {...props} className={classes}>
 | 
				
			||||||
 | 
					      {children}
 | 
				
			||||||
 | 
					    </Box>
 | 
				
			||||||
 | 
					  );
 | 
				
			||||||
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					export { Body };
 | 
				
			||||||
@ -0,0 +1,13 @@
 | 
				
			|||||||
 | 
					import * as React from "react";
 | 
				
			||||||
 | 
					import { Box } from "../../Box";
 | 
				
			||||||
 | 
					import { cx } from "../../../utils";
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					type Description = (
 | 
				
			||||||
 | 
					  props: React.PropsWithChildren<{}>
 | 
				
			||||||
 | 
					) => React.ReactElement | null;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					const Description: Description = ({ children }) => {
 | 
				
			||||||
 | 
					  return <Box className={cx(["mt-1"])}>{children}</Box>;
 | 
				
			||||||
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					export { Description };
 | 
				
			||||||
@ -0,0 +1,21 @@
 | 
				
			|||||||
 | 
					import * as React from "react";
 | 
				
			||||||
 | 
					import { Box } from "../../Box";
 | 
				
			||||||
 | 
					import { cx } from "../../../utils";
 | 
				
			||||||
 | 
					import { styles } from "./styles";
 | 
				
			||||||
 | 
					import { HTMLAttributes } from "react";
 | 
				
			||||||
 | 
					import { cva } from "class-variance-authority";
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					type FooterProps = HTMLAttributes<HTMLDivElement> & React.PropsWithChildren<{}>;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					type Footer = (props: FooterProps) => React.ReactElement | null;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					const Footer: Footer = ({ children, ...props }) => {
 | 
				
			||||||
 | 
					  const classes = cx(styles, props.className);
 | 
				
			||||||
 | 
					  return (
 | 
				
			||||||
 | 
					    <Box {...props} className={classes}>
 | 
				
			||||||
 | 
					      {children}
 | 
				
			||||||
 | 
					    </Box>
 | 
				
			||||||
 | 
					  );
 | 
				
			||||||
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					export { Footer };
 | 
				
			||||||
@ -0,0 +1,21 @@
 | 
				
			|||||||
 | 
					import * as React from "react";
 | 
				
			||||||
 | 
					import { Primitive } from "@radix-ui/react-primitive";
 | 
				
			||||||
 | 
					import { styles } from "./styles";
 | 
				
			||||||
 | 
					import { cx } from "../../../utils";
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					type HTMLTableHeader = React.ElementRef<typeof Primitive.div>;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					type HeaderProps = React.ComponentPropsWithoutRef<typeof Primitive.div> & {};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					const Header = React.forwardRef<HTMLTableHeader, HeaderProps>(
 | 
				
			||||||
 | 
					  ({ children, ...props }, forwardRef) => {
 | 
				
			||||||
 | 
					    const classes = cx(styles, props.className);
 | 
				
			||||||
 | 
					    return (
 | 
				
			||||||
 | 
					      <Primitive.div {...props} className={classes} ref={forwardRef}>
 | 
				
			||||||
 | 
					        {children}
 | 
				
			||||||
 | 
					      </Primitive.div>
 | 
				
			||||||
 | 
					    );
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					export { Header };
 | 
				
			||||||
@ -0,0 +1,26 @@
 | 
				
			|||||||
 | 
					import { Primitive } from "@radix-ui/react-primitive";
 | 
				
			||||||
 | 
					import * as React from "react";
 | 
				
			||||||
 | 
					import { cva, VariantProps } from "class-variance-authority";
 | 
				
			||||||
 | 
					import { cx } from "../../../utils";
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					const base = ["text-lg", "font-semibold", "leading-6", "text-mono-primary"];
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					const titleStyles = cva(base);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					type TitleElement = React.ElementRef<typeof Primitive.h3>;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					type TitleProps = React.ComponentPropsWithoutRef<typeof Primitive.h3> &
 | 
				
			||||||
 | 
					  VariantProps<typeof titleStyles> & {};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					const Title = React.forwardRef<TitleElement, TitleProps>(
 | 
				
			||||||
 | 
					  ({ children, ...props }, forwardRef) => {
 | 
				
			||||||
 | 
					    const classes = cx(titleStyles(), props.className);
 | 
				
			||||||
 | 
					    return (
 | 
				
			||||||
 | 
					      <Primitive.h3 {...props} className={classes} ref={forwardRef}>
 | 
				
			||||||
 | 
					        {children}
 | 
				
			||||||
 | 
					      </Primitive.h3>
 | 
				
			||||||
 | 
					    );
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					export { Title };
 | 
				
			||||||
@ -0,0 +1,5 @@
 | 
				
			|||||||
 | 
					export * from "./Header";
 | 
				
			||||||
 | 
					export * from "./Title";
 | 
				
			||||||
 | 
					export * from "./Body";
 | 
				
			||||||
 | 
					export * from "./Description";
 | 
				
			||||||
 | 
					export * from "./Footer";
 | 
				
			||||||
@ -0,0 +1,3 @@
 | 
				
			|||||||
 | 
					const styles = ["px-4", "py-4", "sm:px-6"];
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					export { styles };
 | 
				
			||||||
@ -0,0 +1 @@
 | 
				
			|||||||
 | 
					export * from "./Card";
 | 
				
			||||||
@ -0,0 +1,48 @@
 | 
				
			|||||||
 | 
					import React from "react";
 | 
				
			||||||
 | 
					import type { Meta, StoryObj } from "@storybook/react";
 | 
				
			||||||
 | 
					import { Box } from "../Box";
 | 
				
			||||||
 | 
					import { Divider } from "./Divider";
 | 
				
			||||||
 | 
					import * as Card from "../Card";
 | 
				
			||||||
 | 
					import { cx } from "../../utils";
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					const meta: Meta<typeof Divider> = {
 | 
				
			||||||
 | 
					  title: "UI/Divider",
 | 
				
			||||||
 | 
					  component: Divider,
 | 
				
			||||||
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					export default meta;
 | 
				
			||||||
 | 
					type Story = StoryObj<typeof Divider>;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					export const Default: Story = {
 | 
				
			||||||
 | 
					  render: () => (
 | 
				
			||||||
 | 
					    <Box>
 | 
				
			||||||
 | 
					      Hello world
 | 
				
			||||||
 | 
					      <Divider />
 | 
				
			||||||
 | 
					      Hello world
 | 
				
			||||||
 | 
					    </Box>
 | 
				
			||||||
 | 
					  ),
 | 
				
			||||||
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					export const WithBorder: Story = {
 | 
				
			||||||
 | 
					  render: () => (
 | 
				
			||||||
 | 
					    <Box>
 | 
				
			||||||
 | 
					      Hello world
 | 
				
			||||||
 | 
					      <Divider border />
 | 
				
			||||||
 | 
					      Hello world
 | 
				
			||||||
 | 
					    </Box>
 | 
				
			||||||
 | 
					  ),
 | 
				
			||||||
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					export const OnCard: Story = {
 | 
				
			||||||
 | 
					  render: () => (
 | 
				
			||||||
 | 
					    <Box className={cx(["lead"])}>
 | 
				
			||||||
 | 
					      <Card.$>
 | 
				
			||||||
 | 
					        <p>
 | 
				
			||||||
 | 
					          The first rule of Fight Club is: You do not talk about Fight Club.
 | 
				
			||||||
 | 
					        </p>
 | 
				
			||||||
 | 
					        <Divider border />
 | 
				
			||||||
 | 
					        <p>The second rule of Fight Club is: Always bring cupcakes.</p>
 | 
				
			||||||
 | 
					      </Card.$>
 | 
				
			||||||
 | 
					    </Box>
 | 
				
			||||||
 | 
					  ),
 | 
				
			||||||
 | 
					};
 | 
				
			||||||
@ -0,0 +1,30 @@
 | 
				
			|||||||
 | 
					import { cva } from "class-variance-authority";
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					const base = [""];
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					const horizontal = ["px-0", "w-full"];
 | 
				
			||||||
 | 
					const vertical = ["py-0", "h-full"];
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					const dividerStyles = cva(base, {
 | 
				
			||||||
 | 
					  variants: {
 | 
				
			||||||
 | 
					    size: {
 | 
				
			||||||
 | 
					      sm: ["p-1"],
 | 
				
			||||||
 | 
					      md: ["p-2"],
 | 
				
			||||||
 | 
					      lg: ["p-4"],
 | 
				
			||||||
 | 
					      xl: ["p-6"],
 | 
				
			||||||
 | 
					    },
 | 
				
			||||||
 | 
					    border: {
 | 
				
			||||||
 | 
					      true: [],
 | 
				
			||||||
 | 
					    },
 | 
				
			||||||
 | 
					    orientation: {
 | 
				
			||||||
 | 
					      horizontal,
 | 
				
			||||||
 | 
					      vertical,
 | 
				
			||||||
 | 
					    },
 | 
				
			||||||
 | 
					  },
 | 
				
			||||||
 | 
					  defaultVariants: {
 | 
				
			||||||
 | 
					    size: "md",
 | 
				
			||||||
 | 
					    orientation: "horizontal",
 | 
				
			||||||
 | 
					  },
 | 
				
			||||||
 | 
					});
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					export { dividerStyles };
 | 
				
			||||||
@ -0,0 +1,25 @@
 | 
				
			|||||||
 | 
					import * as React from "react";
 | 
				
			||||||
 | 
					import { match, P } from "ts-pattern";
 | 
				
			||||||
 | 
					import * as T from "./Divider.types";
 | 
				
			||||||
 | 
					import { Box } from "../Box";
 | 
				
			||||||
 | 
					import { cx } from "../../utils";
 | 
				
			||||||
 | 
					import { dividerStyles } from "./Divider.styles";
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					const Divider = React.forwardRef<
 | 
				
			||||||
 | 
					  HTMLDivElement | HTMLHRElement,
 | 
				
			||||||
 | 
					  T.DividerProps
 | 
				
			||||||
 | 
					>(({ children, border = false, orientation, size, ...props }, forwardedRef) => {
 | 
				
			||||||
 | 
					  const classes = cx(
 | 
				
			||||||
 | 
					    dividerStyles({ orientation, size, border }),
 | 
				
			||||||
 | 
					    props.className
 | 
				
			||||||
 | 
					  );
 | 
				
			||||||
 | 
					  return match({ border })
 | 
				
			||||||
 | 
					    .with({ border: true }, () => (
 | 
				
			||||||
 | 
					      <div {...props} className={classes}>
 | 
				
			||||||
 | 
					        <Box className={cx(["bg-mono-border", "h-[2px]"])} />
 | 
				
			||||||
 | 
					      </div>
 | 
				
			||||||
 | 
					    ))
 | 
				
			||||||
 | 
					    .otherwise(() => <div {...props} className={classes} ref={forwardedRef} />);
 | 
				
			||||||
 | 
					});
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					export { Divider };
 | 
				
			||||||
@ -0,0 +1,10 @@
 | 
				
			|||||||
 | 
					import { VariantProps } from "class-variance-authority";
 | 
				
			||||||
 | 
					import { dividerStyles } from "./Divider.styles";
 | 
				
			||||||
 | 
					import { HTMLAttributes } from "react";
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					type DividerProps = VariantProps<typeof dividerStyles> &
 | 
				
			||||||
 | 
					  HTMLAttributes<HTMLDivElement> & {
 | 
				
			||||||
 | 
					    border?: boolean;
 | 
				
			||||||
 | 
					  };
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					export { DividerProps };
 | 
				
			||||||
@ -0,0 +1,21 @@
 | 
				
			|||||||
 | 
					import React from "react";
 | 
				
			||||||
 | 
					import type { Meta, StoryObj } from "@storybook/react";
 | 
				
			||||||
 | 
					import { Box } from "../Box";
 | 
				
			||||||
 | 
					import { Input } from "./Input";
 | 
				
			||||||
 | 
					import { cx } from "../../utils";
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					const meta: Meta<typeof Input> = {
 | 
				
			||||||
 | 
					  title: "UI/Input",
 | 
				
			||||||
 | 
					  component: Input,
 | 
				
			||||||
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					export default meta;
 | 
				
			||||||
 | 
					type Story = StoryObj<typeof Input>;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					export const Default: Story = {
 | 
				
			||||||
 | 
					  render: () => (
 | 
				
			||||||
 | 
					    <Box className={cx(["w-96"])}>
 | 
				
			||||||
 | 
					      <Input label="name" />
 | 
				
			||||||
 | 
					    </Box>
 | 
				
			||||||
 | 
					  ),
 | 
				
			||||||
 | 
					};
 | 
				
			||||||
@ -0,0 +1,29 @@
 | 
				
			|||||||
 | 
					import { cva } from "class-variance-authority";
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					const base = [
 | 
				
			||||||
 | 
					  "block",
 | 
				
			||||||
 | 
					  "rounded-lg",
 | 
				
			||||||
 | 
					  "border-2",
 | 
				
			||||||
 | 
					  "border-mono-border",
 | 
				
			||||||
 | 
					  "py-1.5",
 | 
				
			||||||
 | 
					  "px-2",
 | 
				
			||||||
 | 
					  "text-mono-text",
 | 
				
			||||||
 | 
					  "text-ellipsis",
 | 
				
			||||||
 | 
					  "placeholder:text-mono-border",
 | 
				
			||||||
 | 
					  "outline-none",
 | 
				
			||||||
 | 
					  "focus:ring-0",
 | 
				
			||||||
 | 
					  "focus:border-mono-primary",
 | 
				
			||||||
 | 
					];
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					const inputStyles = cva(base, {
 | 
				
			||||||
 | 
					  variants: {
 | 
				
			||||||
 | 
					    fullWidth: {
 | 
				
			||||||
 | 
					      true: ["w-full"],
 | 
				
			||||||
 | 
					    },
 | 
				
			||||||
 | 
					  },
 | 
				
			||||||
 | 
					  defaultVariants: {
 | 
				
			||||||
 | 
					    fullWidth: false,
 | 
				
			||||||
 | 
					  },
 | 
				
			||||||
 | 
					});
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					export { inputStyles };
 | 
				
			||||||
@ -0,0 +1,106 @@
 | 
				
			|||||||
 | 
					import * as React from "react";
 | 
				
			||||||
 | 
					import dashify from "dashify";
 | 
				
			||||||
 | 
					import { Primitive } from "@radix-ui/react-primitive";
 | 
				
			||||||
 | 
					import { NumericFormat } from "react-number-format";
 | 
				
			||||||
 | 
					import type * as T from "./Input.types";
 | 
				
			||||||
 | 
					import { Box } from "../Box";
 | 
				
			||||||
 | 
					import { cx } from "../../utils";
 | 
				
			||||||
 | 
					import { inputStyles } from "./Input.styles";
 | 
				
			||||||
 | 
					import { match } from "ts-pattern";
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					const Input = React.forwardRef<HTMLInputElement, T.InputProps>(
 | 
				
			||||||
 | 
					  (
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					      label,
 | 
				
			||||||
 | 
					      fullWidth,
 | 
				
			||||||
 | 
					      money,
 | 
				
			||||||
 | 
					      numericFormatOptions,
 | 
				
			||||||
 | 
					      hideLabel = false,
 | 
				
			||||||
 | 
					      symbol = "$",
 | 
				
			||||||
 | 
					      currency = "USD",
 | 
				
			||||||
 | 
					      ...props
 | 
				
			||||||
 | 
					    },
 | 
				
			||||||
 | 
					    forwardedRef
 | 
				
			||||||
 | 
					  ) => {
 | 
				
			||||||
 | 
					    const htmlId = dashify(label);
 | 
				
			||||||
 | 
					    const classes = cx(
 | 
				
			||||||
 | 
					      inputStyles({ fullWidth }),
 | 
				
			||||||
 | 
					      {
 | 
				
			||||||
 | 
					        "pr-12": currency,
 | 
				
			||||||
 | 
					        "text-right": money,
 | 
				
			||||||
 | 
					      },
 | 
				
			||||||
 | 
					      props.className
 | 
				
			||||||
 | 
					    );
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    const moneyDecoratorsClasses = [
 | 
				
			||||||
 | 
					      "pointer-events-none",
 | 
				
			||||||
 | 
					      "absolute",
 | 
				
			||||||
 | 
					      "inset-y-0",
 | 
				
			||||||
 | 
					      "flex",
 | 
				
			||||||
 | 
					      "items-center",
 | 
				
			||||||
 | 
					    ];
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    return (
 | 
				
			||||||
 | 
					      <Box
 | 
				
			||||||
 | 
					        className={cx(["relative"], {
 | 
				
			||||||
 | 
					          "w-full": fullWidth,
 | 
				
			||||||
 | 
					          "max-w-xs": !fullWidth,
 | 
				
			||||||
 | 
					        })}
 | 
				
			||||||
 | 
					      >
 | 
				
			||||||
 | 
					        <label
 | 
				
			||||||
 | 
					          className={cx(
 | 
				
			||||||
 | 
					            ["text-sm", "font-semibold", "leading-6", "text-mono-primary"],
 | 
				
			||||||
 | 
					            {
 | 
				
			||||||
 | 
					              "sr-only": hideLabel,
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					          )}
 | 
				
			||||||
 | 
					          htmlFor={htmlId}
 | 
				
			||||||
 | 
					        >
 | 
				
			||||||
 | 
					          {label}
 | 
				
			||||||
 | 
					        </label>
 | 
				
			||||||
 | 
					        <Box
 | 
				
			||||||
 | 
					          className={cx(["relative"], {
 | 
				
			||||||
 | 
					            "mt-1": !hideLabel,
 | 
				
			||||||
 | 
					          })}
 | 
				
			||||||
 | 
					        >
 | 
				
			||||||
 | 
					          {match({ money })
 | 
				
			||||||
 | 
					            .with({ money: true }, () => (
 | 
				
			||||||
 | 
					              <>
 | 
				
			||||||
 | 
					                <Box className={cx(["left-0", "pl-3"], moneyDecoratorsClasses)}>
 | 
				
			||||||
 | 
					                  <span className={cx(["text-mono-primary", "sm:text-sm"])}>
 | 
				
			||||||
 | 
					                    {symbol}
 | 
				
			||||||
 | 
					                  </span>
 | 
				
			||||||
 | 
					                </Box>
 | 
				
			||||||
 | 
					                <NumericFormat
 | 
				
			||||||
 | 
					                  id={htmlId}
 | 
				
			||||||
 | 
					                  className={classes}
 | 
				
			||||||
 | 
					                  valueIsNumericString
 | 
				
			||||||
 | 
					                  {...numericFormatOptions}
 | 
				
			||||||
 | 
					                  {...props}
 | 
				
			||||||
 | 
					                  // prefix={"$"}
 | 
				
			||||||
 | 
					                  getInputRef={forwardedRef}
 | 
				
			||||||
 | 
					                />
 | 
				
			||||||
 | 
					                <Box
 | 
				
			||||||
 | 
					                  className={cx(["right-0", "pr-3"], moneyDecoratorsClasses)}
 | 
				
			||||||
 | 
					                >
 | 
				
			||||||
 | 
					                  <span className={cx(["text-mono-primary", "sm:text-sm"])}>
 | 
				
			||||||
 | 
					                    {currency}
 | 
				
			||||||
 | 
					                  </span>
 | 
				
			||||||
 | 
					                </Box>
 | 
				
			||||||
 | 
					              </>
 | 
				
			||||||
 | 
					            ))
 | 
				
			||||||
 | 
					            .otherwise(() => (
 | 
				
			||||||
 | 
					              <input
 | 
				
			||||||
 | 
					                {...props}
 | 
				
			||||||
 | 
					                id={htmlId}
 | 
				
			||||||
 | 
					                className={classes}
 | 
				
			||||||
 | 
					                ref={forwardedRef}
 | 
				
			||||||
 | 
					              />
 | 
				
			||||||
 | 
					            ))}
 | 
				
			||||||
 | 
					        </Box>
 | 
				
			||||||
 | 
					      </Box>
 | 
				
			||||||
 | 
					    );
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					export { Input };
 | 
				
			||||||
@ -0,0 +1,24 @@
 | 
				
			|||||||
 | 
					import * as React from "react";
 | 
				
			||||||
 | 
					import { Primitive } from "@radix-ui/react-primitive";
 | 
				
			||||||
 | 
					import { VariantProps } from "class-variance-authority";
 | 
				
			||||||
 | 
					import { inputStyles } from "./Input.styles";
 | 
				
			||||||
 | 
					import { NumericFormatProps } from "react-number-format";
 | 
				
			||||||
 | 
					import { InputHTMLAttributes } from "react";
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					type InputProps = Omit<InputHTMLAttributes<HTMLInputElement>, "size"> &
 | 
				
			||||||
 | 
					  VariantProps<typeof inputStyles> & {
 | 
				
			||||||
 | 
					    label: string;
 | 
				
			||||||
 | 
					    money?: boolean;
 | 
				
			||||||
 | 
					    hideLabel?: boolean;
 | 
				
			||||||
 | 
					    type?: NumericFormatProps["type"];
 | 
				
			||||||
 | 
					    value?: HTMLInputElement["value"] | NumericFormatProps["value"];
 | 
				
			||||||
 | 
					    defaultValue?:
 | 
				
			||||||
 | 
					      | HTMLInputElement["defaultValue"]
 | 
				
			||||||
 | 
					      | NumericFormatProps["defaultValue"];
 | 
				
			||||||
 | 
					    onValueChange?: NumericFormatProps["onValueChange"];
 | 
				
			||||||
 | 
					    numericFormatOptions?: NumericFormatProps;
 | 
				
			||||||
 | 
					    symbol?: string;
 | 
				
			||||||
 | 
					    currency?: string;
 | 
				
			||||||
 | 
					  };
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					export { InputProps };
 | 
				
			||||||
@ -0,0 +1 @@
 | 
				
			|||||||
 | 
					export * from "./Input";
 | 
				
			||||||
					Loading…
					
					
				
		Reference in New Issue