| 1 | "use client"; |
| 2 | |
| 3 | import { NumberField as NumberFieldPrimitive } from "@base-ui/react/number-field"; |
| 4 | import { MinusIcon, PlusIcon } from "lucide-react"; |
| 5 | import * as React from "react"; |
| 6 | import { cn } from "~/lib/utils"; |
| 7 | |
| 8 | export function NumberField({ |
| 9 | id, |
| 10 | className, |
| 11 | size = "default", |
| 12 | ...props |
| 13 | }: NumberFieldPrimitive.Root.Props & { |
| 14 | size?: "sm" | "default" | "lg"; |
| 15 | }): React.ReactElement { |
| 16 | const generatedId = React.useId(); |
| 17 | const fieldId = id ?? generatedId; |
| 18 | return ( |
| 19 | <NumberFieldPrimitive.Root |
| 20 | className={cn("flex w-full flex-col items-start gap-2", className)} |
| 21 | data-size={size} |
| 22 | data-slot="number-field" |
| 23 | id={fieldId} |
| 24 | {...props} |
| 25 | /> |
| 26 | ); |
| 27 | } |
| 28 | |
| 29 | export function NumberFieldGroup({ |
| 30 | className, |
| 31 | ...props |
| 32 | }: NumberFieldPrimitive.Group.Props): React.ReactElement { |
| 33 | return ( |
| 34 | <NumberFieldPrimitive.Group |
| 35 | className={cn( |
| 36 | "relative flex w-full justify-between rounded-lg border border-input bg-background not-dark:bg-clip-padding text-base text-foreground shadow-xs/5 ring-ring/24 transition-shadow before:pointer-events-none before:absolute before:inset-0 before:rounded-[calc(var(--radius-lg)-1px)] not-data-disabled:not-focus-within:not-aria-invalid:before:shadow-[0_1px_--theme(--color-black/4%)] focus-within:border-ring focus-within:ring-[3px] focus-within:ring-inset has-aria-invalid:border-destructive/36 has-autofill:bg-foreground/4 focus-within:has-aria-invalid:border-destructive/64 focus-within:has-aria-invalid:ring-destructive/48 data-disabled:pointer-events-none data-disabled:opacity-64 sm:text-sm dark:bg-input/32 dark:has-autofill:bg-foreground/8 dark:has-aria-invalid:ring-destructive/24 dark:not-data-disabled:not-focus-within:not-aria-invalid:before:shadow-[0_-1px_--theme(--color-white/6%)] [&_svg:not([class*='size-'])]:size-4.5 sm:[&_svg:not([class*='size-'])]:size-4 [&_svg]:pointer-events-none [&_svg]:shrink-0 [[data-disabled],:focus-within,[aria-invalid]]:shadow-none", |
| 37 | className, |
| 38 | )} |
| 39 | data-slot="number-field-group" |
| 40 | {...props} |
| 41 | /> |
| 42 | ); |
| 43 | } |
| 44 | |
| 45 | export function NumberFieldDecrement({ |
| 46 | className, |
| 47 | ...props |
| 48 | }: NumberFieldPrimitive.Decrement.Props): React.ReactElement { |
| 49 | return ( |
| 50 | <NumberFieldPrimitive.Decrement |
| 51 | className={cn( |
| 52 | "relative flex shrink-0 cursor-pointer items-center justify-center rounded-s-[calc(var(--radius-lg)-1px)] in-data-[size=sm]:px-[calc(--spacing(2.5)-1px)] px-[calc(--spacing(3)-1px)] transition-colors pointer-coarse:after:absolute pointer-coarse:after:size-full pointer-coarse:after:min-h-11 pointer-coarse:after:min-w-11 hover:bg-accent", |
| 53 | className, |
| 54 | )} |
| 55 | data-slot="number-field-decrement" |
| 56 | {...props} |
| 57 | > |
| 58 | <MinusIcon /> |
| 59 | </NumberFieldPrimitive.Decrement> |
| 60 | ); |
| 61 | } |
| 62 | |
| 63 | export function NumberFieldIncrement({ |
| 64 | className, |
| 65 | ...props |
| 66 | }: NumberFieldPrimitive.Increment.Props): React.ReactElement { |
| 67 | return ( |
| 68 | <NumberFieldPrimitive.Increment |
| 69 | className={cn( |
| 70 | "relative flex shrink-0 cursor-pointer items-center justify-center rounded-e-[calc(var(--radius-lg)-1px)] in-data-[size=sm]:px-[calc(--spacing(2.5)-1px)] px-[calc(--spacing(3)-1px)] transition-colors pointer-coarse:after:absolute pointer-coarse:after:size-full pointer-coarse:after:min-h-11 pointer-coarse:after:min-w-11 hover:bg-accent", |
| 71 | className, |
| 72 | )} |
| 73 | data-slot="number-field-increment" |
| 74 | {...props} |
| 75 | > |
| 76 | <PlusIcon /> |
| 77 | </NumberFieldPrimitive.Increment> |
| 78 | ); |
| 79 | } |
| 80 | |
| 81 | export function NumberFieldInput({ |
| 82 | className, |
| 83 | ...props |
| 84 | }: NumberFieldPrimitive.Input.Props): React.ReactElement { |
| 85 | return ( |
| 86 | <NumberFieldPrimitive.Input |
| 87 | className={cn( |
| 88 | "h-8.5 in-data-[size=lg]:h-9.5 in-data-[size=sm]:h-7.5 w-full min-w-0 grow bg-transparent in-data-[size=sm]:px-[calc(--spacing(2.5)-1px)] px-[calc(--spacing(3)-1px)] text-center tabular-nums in-data-[size=lg]:leading-9.5 in-data-[size=sm]:leading-7.5 leading-8.5 outline-none [transition:background-color_5000000s_ease-in-out_0s] sm:h-7.5 sm:in-data-[size=lg]:h-8.5 sm:in-data-[size=sm]:h-6.5 sm:in-data-[size=lg]:leading-8.5 sm:in-data-[size=sm]:leading-8.5 sm:leading-7.5", |
| 89 | className, |
| 90 | )} |
| 91 | data-slot="number-field-input" |
| 92 | {...props} |
| 93 | /> |
| 94 | ); |
| 95 | } |
| 96 | |
| 97 | export { NumberFieldPrimitive }; |