mirror of
https://github.com/lukevella/rallly.git
synced 2025-06-06 20:51:48 +02:00
🎨 Update UI package (#1070)
Add new components and update various existing ones.
This commit is contained in:
parent
a4ffbee081
commit
e6792a4283
33 changed files with 386 additions and 56 deletions
|
@ -63,6 +63,7 @@ export const PollDetailsForm = () => {
|
|||
<Input
|
||||
type="text"
|
||||
id="location"
|
||||
className="w-full"
|
||||
placeholder={t("locationPlaceholder")}
|
||||
{...register("location")}
|
||||
/>
|
||||
|
@ -77,6 +78,7 @@ export const PollDetailsForm = () => {
|
|||
</span>
|
||||
</div>
|
||||
<Textarea
|
||||
className="w-full"
|
||||
id="description"
|
||||
placeholder={t("descriptionPlaceholder")}
|
||||
rows={5}
|
||||
|
|
|
@ -49,7 +49,7 @@ const DateTimePreferencesForm = () => {
|
|||
form.reset(data);
|
||||
})}
|
||||
>
|
||||
<div className="space-y-4">
|
||||
<div className="space-y-6">
|
||||
<FormField
|
||||
control={form.control}
|
||||
name="timeZone"
|
||||
|
|
|
@ -3,7 +3,7 @@ import { Tooltip, TooltipContent, TooltipTrigger } from "@rallly/ui/tooltip";
|
|||
import { InfoIcon } from "lucide-react";
|
||||
|
||||
export const Settings = ({ children }: React.PropsWithChildren) => {
|
||||
return <div className="">{children}</div>;
|
||||
return <div className="space-y-6">{children}</div>;
|
||||
};
|
||||
|
||||
export const SettingsHeader = ({ children }: React.PropsWithChildren) => {
|
||||
|
@ -51,7 +51,7 @@ export const SettingsItemTitle = ({
|
|||
{hint ? (
|
||||
<Tooltip>
|
||||
<TooltipTrigger asChild>
|
||||
<InfoIcon className="size-4 inline-block text-gray-500" />
|
||||
<InfoIcon className="inline-block size-4 text-gray-500" />
|
||||
</TooltipTrigger>
|
||||
<TooltipContent side="right" className="max-w-sm">
|
||||
{hint}
|
||||
|
|
4
packages/ui/custom.d.ts
vendored
Normal file
4
packages/ui/custom.d.ts
vendored
Normal file
|
@ -0,0 +1,4 @@
|
|||
declare module "*.svg" {
|
||||
const content: React.FunctionComponent<React.SVGAttributes<SVGElement>>;
|
||||
export default content;
|
||||
}
|
|
@ -4,7 +4,7 @@ import * as AccordionPrimitive from "@radix-ui/react-accordion";
|
|||
import { ChevronDown } from "lucide-react";
|
||||
import * as React from "react";
|
||||
|
||||
import { cn } from "@rallly/ui";
|
||||
import { cn } from "./lib/utils";
|
||||
|
||||
const Accordion = AccordionPrimitive.Root;
|
||||
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
import { type VariantProps, cva } from "class-variance-authority";
|
||||
import * as React from "react";
|
||||
|
||||
import { cn } from "@rallly/ui";
|
||||
import { cn } from "./lib/utils";
|
||||
|
||||
const alertVariants = cva(
|
||||
"flex sm:flex-row flex-col gap-x-3 gap-y-2 rounded-md border p-4",
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
import { type VariantProps, cva } from "class-variance-authority";
|
||||
import * as React from "react";
|
||||
|
||||
import { cn } from "@rallly/ui";
|
||||
import { cn } from "./lib/utils";
|
||||
|
||||
const badgeVariants = cva(
|
||||
"inline-flex items-center rounded-full border px-2 py-0.5 text-xs font-semibold transition-colors focus:outline-none focus:ring-2 focus:ring-ring focus:ring-offset-2",
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
import { CheckCircle2Icon } from "lucide-react";
|
||||
|
||||
import { cn } from "@rallly/ui";
|
||||
import { cn } from "./lib/utils";
|
||||
|
||||
export const BillingPlan = ({
|
||||
children,
|
||||
|
|
|
@ -4,22 +4,22 @@ import { Loader2Icon } from "lucide-react";
|
|||
import { cva, VariantProps } from "class-variance-authority";
|
||||
import * as React from "react";
|
||||
|
||||
import { cn } from "@rallly/ui";
|
||||
import { cn } from "./lib/utils";
|
||||
|
||||
const buttonVariants = cva(
|
||||
cn(
|
||||
"inline-flex border font-medium disabled:text-muted-foreground disabled:bg-muted disabled:pointer-events-none select-none items-center justify-center whitespace-nowrap rounded-md border",
|
||||
"focus-visible:ring-offset-input-background focus-visible:border-primary-400 focus-visible:ring-2 focus-visible:ring-indigo-100",
|
||||
"inline-flex border font-medium disabled:pointer-events-none select-none disabled:opacity-50 items-center justify-center whitespace-nowrap rounded-md border",
|
||||
"focus:ring-offset-input-background focus:border-primary-400 focus:ring-2 focus:ring-indigo-100",
|
||||
),
|
||||
{
|
||||
variants: {
|
||||
variant: {
|
||||
primary:
|
||||
"border-transparent bg-primary text-white focus:ring-offset-1 shadow-sm hover:bg-primary-500 active:bg-primary-700",
|
||||
"border-primary-700 bg-primary disabled:bg-gray-400 disabled:border-transparent text-primary-foreground shadow-sm hover:bg-primary-500 active:bg-primary-700",
|
||||
destructive:
|
||||
"bg-destructive text-destructive-foreground focus:ring-offset-1 active:bg-destructive border-destructive hover:bg-destructive/90",
|
||||
default:
|
||||
"rounded-md px-3.5 py-2.5 data-[state=open]:shadow-none data-[state=open]:bg-gray-100 active:bg-gray-200 focus:border-gray-300 hover:bg-gray-100 bg-gray-50",
|
||||
"rounded-md px-3.5 py-2.5 data-[state=open]:shadow-none data-[state=open]:bg-gray-100 active:bg-gray-200 hover:bg-gray-100 bg-gray-50",
|
||||
secondary:
|
||||
"bg-secondary text-secondary-foreground hover:bg-secondary/80",
|
||||
ghost: "border-transparent hover:bg-gray-200 active:bg-gray-300",
|
||||
|
@ -27,7 +27,7 @@ const buttonVariants = cva(
|
|||
},
|
||||
size: {
|
||||
default: "h-9 px-2.5 gap-x-2.5 text-sm",
|
||||
sm: "h-7 text-xs px-2 gap-x-1.5 rounded-md",
|
||||
sm: "h-7 text-xs px-1.5 gap-x-1.5 rounded-md",
|
||||
lg: "h-11 text-base gap-x-3 px-4 rounded-md",
|
||||
},
|
||||
},
|
||||
|
@ -65,6 +65,7 @@ const Button = React.forwardRef<HTMLButtonElement, ButtonProps>(
|
|||
return (
|
||||
<Comp
|
||||
className={cn(
|
||||
"group",
|
||||
buttonVariants({ variant, size }),
|
||||
{
|
||||
"pointer-events-none": loading,
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
import * as React from "react";
|
||||
|
||||
import { cn } from "@rallly/ui";
|
||||
import { cn } from "./lib/utils";
|
||||
|
||||
const Card = React.forwardRef<
|
||||
HTMLDivElement,
|
||||
|
@ -23,7 +23,7 @@ const CardHeader = React.forwardRef<
|
|||
>(({ className, ...props }, ref) => (
|
||||
<div
|
||||
ref={ref}
|
||||
className={cn("grid border-b border-gray-100 p-3 sm:p-4", className)}
|
||||
className={cn("grid rounded-t-md border-b p-2 py-3 sm:px-5", className)}
|
||||
{...props}
|
||||
/>
|
||||
));
|
||||
|
@ -35,10 +35,7 @@ const CardTitle = React.forwardRef<
|
|||
>(({ className, ...props }, ref) => (
|
||||
<h3
|
||||
ref={ref}
|
||||
className={cn(
|
||||
"mb-1 font-semibold tracking-tight sm:leading-tight",
|
||||
className,
|
||||
)}
|
||||
className={cn("font-semibold tracking-tight sm:leading-tight", className)}
|
||||
{...props}
|
||||
/>
|
||||
));
|
||||
|
@ -50,7 +47,7 @@ const CardDescription = React.forwardRef<
|
|||
>(({ className, ...props }, ref) => (
|
||||
<p
|
||||
ref={ref}
|
||||
className={cn("text-muted-foreground text-sm", className)}
|
||||
className={cn("text-muted-foreground mt-1 text-sm", className)}
|
||||
{...props}
|
||||
/>
|
||||
));
|
||||
|
|
3
packages/ui/src/checkbox-check.svg
Normal file
3
packages/ui/src/checkbox-check.svg
Normal file
|
@ -0,0 +1,3 @@
|
|||
<svg xmlns="http://www.w3.org/2000/svg" fill="currentColor" viewBox="0 0 10 8">
|
||||
<path fill-rule="evenodd" d="M9.33 1.066a1.25 1.25 0 0 1 .104 1.764l-4 4.5a1.25 1.25 0 0 1-1.627.21l-3-2a1.25 1.25 0 0 1 1.386-2.08l2.095 1.397L7.566 1.17a1.25 1.25 0 0 1 1.764-.104Z" clip-rule="evenodd"/>
|
||||
</svg>
|
After Width: | Height: | Size: 295 B |
|
@ -2,9 +2,8 @@
|
|||
|
||||
import * as React from "react";
|
||||
import * as CheckboxPrimitive from "@radix-ui/react-checkbox";
|
||||
import { CheckIcon } from "lucide-react";
|
||||
|
||||
import { cn } from "@rallly/ui";
|
||||
import CheckboxCheckIcon from "./checkbox-check.svg";
|
||||
import { cn } from "./lib/utils";
|
||||
|
||||
const Checkbox = React.forwardRef<
|
||||
React.ElementRef<typeof CheckboxPrimitive.Root>,
|
||||
|
@ -13,7 +12,9 @@ const Checkbox = React.forwardRef<
|
|||
<CheckboxPrimitive.Root
|
||||
ref={ref}
|
||||
className={cn(
|
||||
"border-primary ring-offset-background focus-visible:ring-ring data-[state=checked]:bg-primary data-[state=checked]:text-primary-foreground peer h-4 w-4 shrink-0 rounded-sm border focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-offset-2 disabled:cursor-not-allowed disabled:opacity-50",
|
||||
"data-[state=checked]:bg-primary data-[state=checked]:border-primary-600 data-[state=checked]:focus:ring-primary-200 data-[state=checked]:focus:ring-2",
|
||||
"focus-visible:ring-gray-100",
|
||||
"peer inline-flex h-5 w-5 shrink-0 items-center justify-center rounded border border-gray-200 bg-gray-50 ring-0 disabled:cursor-not-allowed disabled:opacity-50",
|
||||
className,
|
||||
)}
|
||||
{...props}
|
||||
|
@ -21,7 +22,7 @@ const Checkbox = React.forwardRef<
|
|||
<CheckboxPrimitive.Indicator
|
||||
className={cn("flex items-center justify-center text-current")}
|
||||
>
|
||||
<CheckIcon className="h-4 w-4" />
|
||||
<CheckboxCheckIcon className="text-primary-50 size-2.5" />
|
||||
</CheckboxPrimitive.Indicator>
|
||||
</CheckboxPrimitive.Root>
|
||||
));
|
||||
|
|
|
@ -5,8 +5,8 @@ import { SearchIcon } from "lucide-react";
|
|||
import { Command as CommandPrimitive } from "cmdk";
|
||||
import * as React from "react";
|
||||
|
||||
import { Dialog, DialogContent } from "@rallly/ui/dialog";
|
||||
import { cn } from "@rallly/ui";
|
||||
import { Dialog, DialogContent } from "./dialog";
|
||||
import { cn } from "./lib/utils";
|
||||
|
||||
const Command = React.forwardRef<
|
||||
React.ElementRef<typeof CommandPrimitive>,
|
||||
|
|
|
@ -4,7 +4,7 @@ import * as DialogPrimitive from "@radix-ui/react-dialog";
|
|||
import { XIcon } from "lucide-react";
|
||||
import * as React from "react";
|
||||
|
||||
import { cn } from "@rallly/ui";
|
||||
import { cn } from "./lib/utils";
|
||||
|
||||
const Dialog = DialogPrimitive.Root;
|
||||
|
||||
|
|
|
@ -4,7 +4,8 @@ import * as DropdownMenuPrimitive from "@radix-ui/react-dropdown-menu";
|
|||
import { CheckIcon, ChevronRightIcon, PlusCircleIcon } from "lucide-react";
|
||||
import * as React from "react";
|
||||
|
||||
import { cn } from "@rallly/ui";
|
||||
import { cn } from "./lib/utils";
|
||||
import { Icon } from "./icon";
|
||||
|
||||
const DropdownMenu = DropdownMenuPrimitive.Root;
|
||||
|
||||
|
@ -83,6 +84,7 @@ const DropdownMenuItem = React.forwardRef<
|
|||
<DropdownMenuPrimitive.Item
|
||||
ref={ref}
|
||||
className={cn(
|
||||
"flex items-center gap-x-2.5",
|
||||
"focus:bg-accent focus:text-accent-foreground relative flex cursor-default select-none items-center rounded-sm px-2 py-1.5 text-sm font-medium outline-none data-[disabled]:pointer-events-none data-[disabled]:opacity-50",
|
||||
inset && "pl-8",
|
||||
className,
|
||||
|
@ -107,7 +109,9 @@ const DropdownMenuCheckboxItem = React.forwardRef<
|
|||
>
|
||||
<span className="absolute left-2 flex h-3.5 w-3.5 items-center justify-center">
|
||||
<DropdownMenuPrimitive.ItemIndicator>
|
||||
<CheckIcon className="size-4" />
|
||||
<Icon variant="success">
|
||||
<CheckIcon />
|
||||
</Icon>
|
||||
</DropdownMenuPrimitive.ItemIndicator>
|
||||
</span>
|
||||
{children}
|
||||
|
@ -123,7 +127,7 @@ const DropdownMenuRadioItem = React.forwardRef<
|
|||
<DropdownMenuPrimitive.RadioItem
|
||||
ref={ref}
|
||||
className={cn(
|
||||
"focus:bg-accent focus:text-accent-foreground relative flex cursor-default select-none items-center rounded-sm py-1.5 pl-8 pr-2 outline-none transition-colors data-[disabled]:pointer-events-none data-[disabled]:opacity-50",
|
||||
"focus:bg-accent focus:text-accent-foreground relative flex cursor-default select-none items-center rounded-sm py-1.5 pl-8 pr-2 text-sm font-medium outline-none transition-colors data-[disabled]:pointer-events-none data-[disabled]:opacity-50",
|
||||
className,
|
||||
)}
|
||||
{...props}
|
||||
|
|
75
packages/ui/src/flex.tsx
Normal file
75
packages/ui/src/flex.tsx
Normal file
|
@ -0,0 +1,75 @@
|
|||
import * as React from "react";
|
||||
|
||||
import { Slot } from "@radix-ui/react-slot";
|
||||
import { cn } from "./lib/utils";
|
||||
import { VariantProps, cva } from "class-variance-authority";
|
||||
import { ComponentPropsWithout, RemovedProps } from "./helpers/component-props";
|
||||
|
||||
type FlexElement = React.ElementRef<"div">;
|
||||
type FlexDivProps = { as?: "div" } & ComponentPropsWithout<"div", RemovedProps>;
|
||||
type FlexSpanProps = { as: "span" } & ComponentPropsWithout<
|
||||
"span",
|
||||
RemovedProps
|
||||
>;
|
||||
type FlexAttributeProps = FlexSpanProps | FlexDivProps;
|
||||
|
||||
const flexVariants = cva("box-border flex justify-start", {
|
||||
variants: {
|
||||
direction: {
|
||||
row: "flex-row",
|
||||
column: "flex-col",
|
||||
},
|
||||
align: {
|
||||
start: "items-start",
|
||||
center: "items-center",
|
||||
end: "items-end",
|
||||
stretch: "items-stretch",
|
||||
},
|
||||
justify: {
|
||||
start: "justify-start",
|
||||
center: "justify-center",
|
||||
end: "justify-end",
|
||||
between: "justify-between",
|
||||
around: "justify-around",
|
||||
},
|
||||
wrap: {
|
||||
noWrap: "flex-nowrap",
|
||||
wrap: "flex-wrap",
|
||||
wrapReverse: "flex-wrap-reverse",
|
||||
},
|
||||
gap: {
|
||||
none: "gap-0",
|
||||
sm: "gap-2.5",
|
||||
md: "gap-4",
|
||||
},
|
||||
},
|
||||
defaultVariants: {
|
||||
direction: "row",
|
||||
align: "start",
|
||||
justify: "start",
|
||||
wrap: "noWrap",
|
||||
gap: "md",
|
||||
},
|
||||
});
|
||||
|
||||
interface FlexProps extends VariantProps<typeof flexVariants> {
|
||||
asChild?: boolean;
|
||||
}
|
||||
|
||||
const Flex = React.forwardRef<FlexElement, FlexProps & FlexAttributeProps>(
|
||||
(props, forwardedRef) => {
|
||||
const { className, asChild, as: Tag = "div", ...flexProps } = props;
|
||||
const Comp = asChild ? Slot : Tag;
|
||||
return (
|
||||
<Comp
|
||||
{...flexProps}
|
||||
ref={forwardedRef}
|
||||
className={cn(flexVariants(flexProps), className)}
|
||||
/>
|
||||
);
|
||||
},
|
||||
);
|
||||
Flex.displayName = "Flex";
|
||||
|
||||
export { Flex };
|
||||
export type { FlexProps };
|
|
@ -11,7 +11,7 @@ import {
|
|||
} from "react-hook-form";
|
||||
|
||||
import { Label } from "./label";
|
||||
import { cn } from "@rallly/ui";
|
||||
import { cn } from "./lib/utils";
|
||||
|
||||
const Form = FormProvider;
|
||||
|
||||
|
@ -78,7 +78,7 @@ const FormItem = React.forwardRef<
|
|||
|
||||
return (
|
||||
<FormItemContext.Provider value={{ id }}>
|
||||
<div ref={ref} className={cn("grid gap-y-2.5", className)} {...props} />
|
||||
<div ref={ref} className={cn("space-y-2.5", className)} {...props} />
|
||||
</FormItemContext.Provider>
|
||||
);
|
||||
});
|
||||
|
|
22
packages/ui/src/helpers/component-props.ts
Normal file
22
packages/ui/src/helpers/component-props.ts
Normal file
|
@ -0,0 +1,22 @@
|
|||
import type React from "react";
|
||||
|
||||
type ComponentPropsAs<
|
||||
C extends React.ElementType<any>,
|
||||
T extends React.ComponentPropsWithoutRef<C>["as"],
|
||||
> = Omit<
|
||||
Extract<React.ComponentPropsWithoutRef<C>, { as: T }>,
|
||||
"as" | "asChild"
|
||||
>;
|
||||
|
||||
// Omits the specified props from the component props. Autocomplete will suggest props
|
||||
// of the component, but won't restrict the omittable props to those that actually exist.
|
||||
type ComponentPropsWithout<
|
||||
T extends React.ElementType,
|
||||
O extends
|
||||
| Omit<string, keyof React.ComponentPropsWithoutRef<T>>
|
||||
| keyof React.ComponentPropsWithoutRef<T>,
|
||||
> = Omit<React.ComponentPropsWithoutRef<T>, O & string>;
|
||||
|
||||
type RemovedProps = "asChild" | "defaultChecked" | "defaultValue" | "color";
|
||||
|
||||
export type { ComponentPropsAs, ComponentPropsWithout, RemovedProps };
|
85
packages/ui/src/helpers/input-attributes.ts
Normal file
85
packages/ui/src/helpers/input-attributes.ts
Normal file
|
@ -0,0 +1,85 @@
|
|||
// https://developer.mozilla.org/en-US/docs/Web/HTML/Element/input#attributes
|
||||
|
||||
type InputAttributes =
|
||||
| "accept"
|
||||
| "alt"
|
||||
| "autocapitalize"
|
||||
| "autocomplete"
|
||||
| "capture"
|
||||
| "checked"
|
||||
| "defaultChecked"
|
||||
| "defaultValue"
|
||||
| "disabled"
|
||||
| "form"
|
||||
| "formaction"
|
||||
| "formenctype"
|
||||
| "formmethod"
|
||||
| "formnovalidate"
|
||||
| "formtarget"
|
||||
| "height"
|
||||
| "list"
|
||||
| "max"
|
||||
| "maxlength"
|
||||
| "min"
|
||||
| "minlength"
|
||||
| "multiple"
|
||||
| "name"
|
||||
| "pattern"
|
||||
| "placeholder"
|
||||
| "popovertarget"
|
||||
| "popovertargetaction"
|
||||
| "readonly"
|
||||
| "required"
|
||||
| "size"
|
||||
| "src"
|
||||
| "step"
|
||||
| "type"
|
||||
| "value"
|
||||
| "width";
|
||||
|
||||
// Includes all text-like inputs, e.g. text, email, password, number, date, etc.
|
||||
type InputTextualAttributes =
|
||||
| "autoCapitalize"
|
||||
| "autoComplete"
|
||||
| "defaultValue"
|
||||
| "disabled"
|
||||
| "form"
|
||||
| "list"
|
||||
| "maxLength"
|
||||
| "minLength"
|
||||
| "min"
|
||||
| "multiple"
|
||||
| "max"
|
||||
| "name"
|
||||
| "pattern"
|
||||
| "placeholder"
|
||||
| "readOnly"
|
||||
| "required"
|
||||
| "size"
|
||||
| "step"
|
||||
| "type"
|
||||
| "value";
|
||||
|
||||
type InputRadioAttributes =
|
||||
| "checked"
|
||||
| "defaultChecked"
|
||||
| "defaultValue"
|
||||
| "disabled"
|
||||
| "form"
|
||||
| "name"
|
||||
| "required"
|
||||
| "value";
|
||||
|
||||
type NotInputRadioAttributes = Exclude<InputAttributes, InputRadioAttributes>;
|
||||
type NotInputTextualAttributes = Exclude<
|
||||
InputAttributes,
|
||||
InputTextualAttributes
|
||||
>;
|
||||
|
||||
export type {
|
||||
InputAttributes,
|
||||
InputRadioAttributes,
|
||||
InputTextualAttributes,
|
||||
NotInputRadioAttributes,
|
||||
NotInputTextualAttributes,
|
||||
};
|
40
packages/ui/src/icon.tsx
Normal file
40
packages/ui/src/icon.tsx
Normal file
|
@ -0,0 +1,40 @@
|
|||
"use client";
|
||||
import { Slot } from "@radix-ui/react-slot";
|
||||
import { cn } from "./lib/utils";
|
||||
import { VariantProps, cva } from "class-variance-authority";
|
||||
|
||||
const iconVariants = cva("", {
|
||||
variants: {
|
||||
variant: {
|
||||
default: "text-gray-500",
|
||||
success: "text-green-500",
|
||||
danger: "text-rose-500",
|
||||
primary: "text-primary-200",
|
||||
},
|
||||
size: {
|
||||
md: "w-4 h-4",
|
||||
lg: "w-5 h-5",
|
||||
},
|
||||
},
|
||||
defaultVariants: {
|
||||
size: "md",
|
||||
variant: "default",
|
||||
},
|
||||
});
|
||||
|
||||
export interface IconProps extends VariantProps<typeof iconVariants> {
|
||||
children?: React.ReactNode;
|
||||
}
|
||||
|
||||
export function Icon({ children, size, variant }: IconProps) {
|
||||
return (
|
||||
<Slot
|
||||
className={cn(
|
||||
iconVariants({ size, variant }),
|
||||
"group-[.bg-primary]:text-primary-200 group",
|
||||
)}
|
||||
>
|
||||
{children}
|
||||
</Slot>
|
||||
);
|
||||
}
|
|
@ -1,6 +1,6 @@
|
|||
import * as React from "react";
|
||||
|
||||
import { cn } from "@rallly/ui";
|
||||
import { cn } from "./lib/utils";
|
||||
import { cva } from "class-variance-authority";
|
||||
|
||||
export type InputProps = Omit<
|
||||
|
@ -13,15 +13,21 @@ export type InputProps = Omit<
|
|||
|
||||
const inputVariants = cva(
|
||||
cn(
|
||||
"border-input placeholder:text-muted-foreground flex h-9 w-full rounded border bg-transparent file:border-0 file:bg-transparent file:text-sm file:font-medium disabled:cursor-not-allowed disabled:opacity-50",
|
||||
"focus:visible:border-primary-400 focus:visible:ring-primary-200 focus:visible:ring-2",
|
||||
"border-input placeholder:text-muted-foreground h-9 rounded border bg-gray-50 file:border-0 file:bg-transparent file:text-sm file:font-medium disabled:cursor-not-allowed disabled:opacity-50",
|
||||
),
|
||||
{
|
||||
variants: {
|
||||
size: {
|
||||
sm: "h-6 text-sm px-1",
|
||||
sm: "h-7 text-xs px-1",
|
||||
md: "h-9 text-sm px-2",
|
||||
lg: "h-12 text-lg px-3",
|
||||
},
|
||||
variant: {
|
||||
default: "border-primary-400 focus-visible:border-primary-400",
|
||||
error: "border-rose-400 focus-visible:border-rose-400",
|
||||
ghost: "border-transparent focus-visible:border-primary-400",
|
||||
},
|
||||
},
|
||||
defaultVariants: {
|
||||
size: "md",
|
||||
|
@ -35,7 +41,6 @@ const Input = React.forwardRef<HTMLInputElement, InputProps>(
|
|||
<input
|
||||
type={type}
|
||||
className={cn(
|
||||
"focus-visible:ring-offset-input-background focus-visible:ring-1 focus-visible:ring-offset-1",
|
||||
inputVariants({ size }),
|
||||
error
|
||||
? "focus-visible:border-rose-400 focus-visible:ring-rose-100"
|
||||
|
|
|
@ -4,7 +4,7 @@ import * as LabelPrimitive from "@radix-ui/react-label";
|
|||
import { cva, VariantProps } from "class-variance-authority";
|
||||
import * as React from "react";
|
||||
|
||||
import { cn } from "@rallly/ui";
|
||||
import { cn } from "./lib/utils";
|
||||
|
||||
const labelVariants = cva(
|
||||
"text-sm font-medium leading-none peer-disabled:cursor-not-allowed peer-disabled:opacity-70",
|
||||
|
|
|
@ -3,7 +3,7 @@
|
|||
import * as PopoverPrimitive from "@radix-ui/react-popover";
|
||||
import * as React from "react";
|
||||
|
||||
import { cn } from "@rallly/ui";
|
||||
import { cn } from "./lib/utils";
|
||||
|
||||
const Popover = PopoverPrimitive.Root;
|
||||
|
||||
|
|
|
@ -4,7 +4,7 @@ import * as RadioGroupPrimitive from "@radix-ui/react-radio-group";
|
|||
import { CircleIcon } from "lucide-react";
|
||||
import * as React from "react";
|
||||
|
||||
import { cn } from "@rallly/ui";
|
||||
import { cn } from "./lib/utils";
|
||||
|
||||
const RadioGroup = React.forwardRef<
|
||||
React.ElementRef<typeof RadioGroupPrimitive.Root>,
|
||||
|
|
|
@ -1,10 +1,12 @@
|
|||
"use client";
|
||||
|
||||
import * as SelectPrimitive from "@radix-ui/react-select";
|
||||
import { CheckIcon, ChevronDownIcon } from "lucide-react";
|
||||
import { CheckIcon, ChevronsUpDownIcon } from "lucide-react";
|
||||
import * as React from "react";
|
||||
|
||||
import { cn } from "@rallly/ui";
|
||||
import { cn } from "./lib/utils";
|
||||
import { buttonVariants } from "./button";
|
||||
import { Icon } from "./icon";
|
||||
|
||||
const Select = SelectPrimitive.Root;
|
||||
|
||||
|
@ -18,15 +20,12 @@ const SelectTrigger = React.forwardRef<
|
|||
>(({ className, children, ...props }, ref) => (
|
||||
<SelectPrimitive.Trigger
|
||||
ref={ref}
|
||||
className={cn(
|
||||
"flex h-10 w-full items-center justify-between rounded-md border bg-white px-3 py-2 text-sm focus:outline-none disabled:cursor-not-allowed disabled:opacity-50",
|
||||
className,
|
||||
)}
|
||||
className={cn(buttonVariants(), className)}
|
||||
{...props}
|
||||
>
|
||||
{children}
|
||||
<SelectPrimitive.Icon asChild>
|
||||
<ChevronDownIcon className="ml-2 size-4 opacity-50" />
|
||||
<ChevronsUpDownIcon className="ml-2 size-4 opacity-50" />
|
||||
</SelectPrimitive.Icon>
|
||||
</SelectPrimitive.Trigger>
|
||||
));
|
||||
|
@ -87,7 +86,9 @@ const SelectItem = React.forwardRef<
|
|||
>
|
||||
<span className="absolute left-2 flex h-3.5 w-3.5 items-center justify-center">
|
||||
<SelectPrimitive.ItemIndicator>
|
||||
<Icon>
|
||||
<CheckIcon className="size-4" />
|
||||
</Icon>
|
||||
</SelectPrimitive.ItemIndicator>
|
||||
</span>
|
||||
<SelectPrimitive.ItemText>{children}</SelectPrimitive.ItemText>
|
||||
|
|
|
@ -3,7 +3,7 @@
|
|||
import * as SwitchPrimitives from "@radix-ui/react-switch";
|
||||
import * as React from "react";
|
||||
|
||||
import { cn } from "@rallly/ui";
|
||||
import { cn } from "./lib/utils";
|
||||
|
||||
const Switch = React.forwardRef<
|
||||
React.ElementRef<typeof SwitchPrimitives.Root>,
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
import * as React from "react";
|
||||
|
||||
import { cn } from "@rallly/ui";
|
||||
import { cn } from "./lib/utils";
|
||||
|
||||
const Table = React.forwardRef<
|
||||
HTMLTableElement,
|
||||
|
|
|
@ -3,7 +3,7 @@
|
|||
import * as TabsPrimitive from "@radix-ui/react-tabs";
|
||||
import * as React from "react";
|
||||
|
||||
import { cn } from "@rallly/ui";
|
||||
import { cn } from "./lib/utils";
|
||||
|
||||
const Tabs = TabsPrimitive.Root;
|
||||
|
||||
|
|
90
packages/ui/src/text-field.tsx
Normal file
90
packages/ui/src/text-field.tsx
Normal file
|
@ -0,0 +1,90 @@
|
|||
"use client";
|
||||
|
||||
import * as React from "react";
|
||||
|
||||
import { cn } from "./lib/utils";
|
||||
import { VariantProps, cva } from "class-variance-authority";
|
||||
import { Icon, IconProps } from "./icon";
|
||||
|
||||
const inputVariants = cva(
|
||||
cn(
|
||||
"focus:border-primary-400 focus-visible:ring-primary-100 focus-visible:ring-2",
|
||||
"border-input placeholder:text-muted-foreground h-9 rounded border bg-gray-50 file:border-0 file:bg-transparent file:text-sm file:font-medium disabled:cursor-not-allowed disabled:opacity-50",
|
||||
),
|
||||
{
|
||||
variants: {
|
||||
size: {
|
||||
sm: "h-7 text-xs px-1",
|
||||
md: "h-9 text-sm px-2",
|
||||
lg: "h-12 text-lg px-3",
|
||||
},
|
||||
},
|
||||
defaultVariants: {
|
||||
size: "md",
|
||||
},
|
||||
},
|
||||
);
|
||||
|
||||
export type InputProps = Omit<
|
||||
React.InputHTMLAttributes<HTMLInputElement>,
|
||||
"size"
|
||||
> &
|
||||
VariantProps<typeof inputVariants>;
|
||||
|
||||
const TextFieldInput = React.forwardRef<HTMLInputElement, InputProps>(
|
||||
({ className, size, type, ...props }, ref) => {
|
||||
return (
|
||||
<input
|
||||
type={type}
|
||||
className={cn(
|
||||
inputVariants({ size }),
|
||||
"group-[.text-field]:border-0 group-[.text-field]:bg-transparent group-[.text-field]:p-0 group-[.text-field]:ring-0 group-[.text-field]:ring-offset-0",
|
||||
className,
|
||||
)}
|
||||
ref={ref}
|
||||
{...props}
|
||||
/>
|
||||
);
|
||||
},
|
||||
);
|
||||
|
||||
interface TextFieldProps extends InputProps {
|
||||
children?: React.ReactNode;
|
||||
}
|
||||
|
||||
const TextField = React.forwardRef<HTMLDivElement, TextFieldProps>(
|
||||
({ className, size, type, children, ...props }, ref) => {
|
||||
return (
|
||||
<div
|
||||
ref={ref}
|
||||
onClick={(e) => {
|
||||
const target = e.target as HTMLElement;
|
||||
// find an input that s a direct descendant of the target
|
||||
target.querySelector("input")?.focus();
|
||||
}}
|
||||
className={cn(
|
||||
"flex items-center",
|
||||
"text-field group",
|
||||
"focus-within:border-primary-400 focus-within:ring-primary-100 focus-within:ring-2",
|
||||
inputVariants({ size }),
|
||||
"p-0",
|
||||
className,
|
||||
)}
|
||||
{...props}
|
||||
>
|
||||
{children}
|
||||
</div>
|
||||
);
|
||||
},
|
||||
);
|
||||
TextField.displayName = "TextField";
|
||||
|
||||
function TextFieldIcon(props: IconProps) {
|
||||
return (
|
||||
<div className="pointer-events-none px-2">
|
||||
<Icon {...props} />
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
export { TextField, TextFieldIcon, TextFieldInput };
|
|
@ -1,6 +1,6 @@
|
|||
import * as React from "react";
|
||||
|
||||
import { cn } from "@rallly/ui";
|
||||
import { cn } from "./lib/utils";
|
||||
|
||||
export type TextareaProps = React.TextareaHTMLAttributes<HTMLTextAreaElement>;
|
||||
|
||||
|
@ -9,7 +9,7 @@ const Textarea = React.forwardRef<HTMLTextAreaElement, TextareaProps>(
|
|||
return (
|
||||
<textarea
|
||||
className={cn(
|
||||
"border-input placeholder:text-muted-foreground flex min-h-[80px] w-full rounded border bg-transparent px-3 py-2 text-sm disabled:cursor-not-allowed disabled:opacity-50",
|
||||
"border-input placeholder:text-muted-foreground flex min-h-[80px] rounded border bg-gray-50 px-2 py-2 text-sm disabled:cursor-not-allowed disabled:opacity-50",
|
||||
"focus-visible:ring-offset-input-background focus-visible:ring-1 focus-visible:ring-offset-1",
|
||||
"focus-visible:border-primary-400 focus-visible:ring-primary-100",
|
||||
className,
|
||||
|
|
|
@ -3,7 +3,7 @@ import * as ToastPrimitives from "@radix-ui/react-toast";
|
|||
import { cva, type VariantProps } from "class-variance-authority";
|
||||
import { X } from "lucide-react";
|
||||
|
||||
import { cn } from "@rallly/ui";
|
||||
import { cn } from "./lib/utils";
|
||||
|
||||
const ToastProvider = ToastPrimitives.Provider;
|
||||
|
||||
|
|
|
@ -3,7 +3,7 @@
|
|||
import * as TooltipPrimitive from "@radix-ui/react-tooltip";
|
||||
import * as React from "react";
|
||||
|
||||
import { cn } from "@rallly/ui";
|
||||
import { cn } from "./lib/utils";
|
||||
|
||||
const TooltipProvider = TooltipPrimitive.Provider;
|
||||
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
{
|
||||
"extends": "@rallly/tsconfig/react.json",
|
||||
"extends": "@rallly/tsconfig/next.json",
|
||||
"compilerOptions": {
|
||||
"baseUrl": ".",
|
||||
"paths": {
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue