Showing the changes to apps (7 of 7 files). Show all
Unified · Split
| @@ -179,16 +179,6 @@ function AutocompleteEmpty({ className, ...props }: AutocompletePrimitive.Empty. · 178 unmodified lines | |||
| 179 | ); | 179 | ); |
| 180 | } | 180 | } |
| 181 | 181 | ||
| 182 | function AutocompleteRow({ className, ...props }: AutocompletePrimitive.Row.Props) { | ||
| 183 | return ( | ||
| 184 | <AutocompletePrimitive.Row className={className} data-slot="autocomplete-row" {...props} /> | ||
| 185 | ); | ||
| 186 | } | ||
| 187 | |||
| 188 | function AutocompleteValue({ ...props }: AutocompletePrimitive.Value.Props) { | ||
| 189 | return <AutocompletePrimitive.Value data-slot="autocomplete-value" {...props} />; | ||
| 190 | } | ||
| 191 | |||
| 192 | function AutocompleteList({ className, ...props }: AutocompletePrimitive.List.Props) { | 182 | function AutocompleteList({ className, ...props }: AutocompletePrimitive.List.Props) { |
| 193 | return ( | 183 | return ( |
| 194 | <ScrollArea scrollbarGutter scrollFade> | 184 | <ScrollArea scrollbarGutter scrollFade> |
| @@ -216,19 +206,6 @@ function AutocompleteClear({ className, ...props }: AutocompletePrimitive.Clear. · 21 unmodified lines | |||
| 216 | ); | 206 | ); |
| 217 | } | 207 | } |
| 218 | 208 | ||
| 219 | function AutocompleteStatus({ className, ...props }: AutocompletePrimitive.Status.Props) { | ||
| 220 | return ( | ||
| 221 | <AutocompletePrimitive.Status | ||
| 222 | className={cn( | ||
| 223 | "px-3 py-2 font-medium text-muted-foreground text-xs empty:m-0 empty:p-0", | ||
| 224 | className, | ||
| 225 | )} | ||
| 226 | data-slot="autocomplete-status" | ||
| 227 | {...props} | ||
| 228 | /> | ||
| 229 | ); | ||
| 230 | } | ||
| 231 | |||
| 232 | function AutocompleteCollection({ ...props }: AutocompletePrimitive.Collection.Props) { | 209 | function AutocompleteCollection({ ...props }: AutocompletePrimitive.Collection.Props) { |
| 233 | return <AutocompletePrimitive.Collection data-slot="autocomplete-collection" {...props} />; | 210 | return <AutocompletePrimitive.Collection data-slot="autocomplete-collection" {...props} />; |
| 234 | } | 211 | } |
| @@ -249,23 +226,15 @@ function AutocompleteTrigger({ · 14 unmodified lines | |||
| 249 | ); | 226 | ); |
| 250 | } | 227 | } |
| 251 | 228 | ||
| 252 | const useAutocompleteFilter = AutocompletePrimitive.useFilter; | ||
| 253 | |||
| 254 | export { | 229 | export { |
| 255 | Autocomplete, | 230 | Autocomplete, |
| 256 | AutocompleteInput, | 231 | AutocompleteInput, |
| 257 | AutocompleteTrigger, | ||
| 258 | AutocompletePopup, | 232 | AutocompletePopup, |
| 259 | AutocompleteItem, | 233 | AutocompleteItem, |
| 260 | AutocompleteSeparator, | 234 | AutocompleteSeparator, |
| 261 | AutocompleteGroup, | 235 | AutocompleteGroup, |
| 262 | AutocompleteGroupLabel, | 236 | AutocompleteGroupLabel, |
| 263 | AutocompleteEmpty, | 237 | AutocompleteEmpty, |
| 264 | AutocompleteValue, | ||
| 265 | AutocompleteList, | 238 | AutocompleteList, |
| 266 | AutocompleteClear, | ||
| 267 | AutocompleteStatus, | ||
| 268 | AutocompleteRow, | ||
| 269 | AutocompleteCollection, | 239 | AutocompleteCollection, |
| 270 | useAutocompleteFilter, | ||
| 271 | }; | 240 | }; |
| @@ -10,17 +10,15 @@ import { ScrollArea } from "~/components/ui/scroll-area"; · 9 unmodified lines | |||
| 10 | 10 | ||
| 11 | const ComboboxContext = React.createContext<{ | 11 | const ComboboxContext = React.createContext<{ |
| 12 | chipsRef: React.RefObject<Element | null> | null; | 12 | chipsRef: React.RefObject<Element | null> | null; |
| 13 | multiple: boolean; | ||
| 14 | }>({ | 13 | }>({ |
| 15 | chipsRef: null, | 14 | chipsRef: null, |
| 16 | multiple: false, | ||
| 17 | }); | 15 | }); |
| 18 | 16 | ||
| 19 | function Combobox<Value, Multiple extends boolean | undefined = false>( | 17 | function Combobox<Value, Multiple extends boolean | undefined = false>( |
| 20 | props: ComboboxPrimitive.Root.Props<Value, Multiple>, | 18 | props: ComboboxPrimitive.Root.Props<Value, Multiple>, |
| 21 | ) { | 19 | ) { |
| 22 | const chipsRef = React.useRef<Element | null>(null); | 20 | const chipsRef = React.useRef<Element | null>(null); |
| 23 | const value = React.useMemo(() => ({ chipsRef, multiple: !!props.multiple }), [props.multiple]); | 21 | const value = React.useMemo(() => ({ chipsRef }), []); |
| 24 | return ( | 22 | return ( |
| 25 | <ComboboxContext value={value}> | 23 | <ComboboxContext value={value}> |
| 26 | <ComboboxPrimitive.Root {...props} /> | 24 | <ComboboxPrimitive.Root {...props} /> |
| @@ -28,31 +26,6 @@ function Combobox<Value, Multiple extends boolean | undefined = false>( · 1 unmodified line | |||
| 28 | ); | 26 | ); |
| 29 | } | 27 | } |
| 30 | 28 | ||
| 31 | function ComboboxChipsInput({ | ||
| 32 | className, | ||
| 33 | size, | ||
| 34 | ...props | ||
| 35 | }: Omit<ComboboxPrimitive.Input.Props, "size"> & { | ||
| 36 | size?: "sm" | "default" | "lg" | number; | ||
| 37 | ref?: React.Ref<HTMLInputElement>; | ||
| 38 | }) { | ||
| 39 | const sizeValue = (size ?? "default") as "sm" | "default" | "lg" | number; | ||
| 40 | |||
| 41 | return ( | ||
| 42 | <ComboboxPrimitive.Input | ||
| 43 | className={cn( | ||
| 44 | "min-w-12 flex-1 text-base outline-none sm:text-sm [[data-slot=combobox-chip]+&]:ps-0.5", | ||
| 45 | sizeValue === "sm" ? "ps-1.5" : "ps-2", | ||
| 46 | className, | ||
| 47 | )} | ||
| 48 | data-size={typeof sizeValue === "string" ? sizeValue : undefined} | ||
| 49 | data-slot="combobox-chips-input" | ||
| 50 | size={typeof sizeValue === "number" ? sizeValue : undefined} | ||
| 51 | {...props} | ||
| 52 | /> | ||
| 53 | ); | ||
| 54 | } | ||
| 55 | |||
| 56 | function ComboboxInput({ | 29 | function ComboboxInput({ |
| 57 | className, | 30 | className, |
| 58 | inputClassName, | 31 | inputClassName, |
| @@ -219,36 +192,6 @@ function ComboboxItem({ · 160 unmodified lines | |||
| 219 | ); | 192 | ); |
| 220 | } | 193 | } |
| 221 | 194 | ||
| 222 | function ComboboxSeparator({ className, ...props }: ComboboxPrimitive.Separator.Props) { | ||
| 223 | return ( | ||
| 224 | <ComboboxPrimitive.Separator | ||
| 225 | className={cn("mx-2 my-1 h-px bg-border last:hidden", className)} | ||
| 226 | data-slot="combobox-separator" | ||
| 227 | {...props} | ||
| 228 | /> | ||
| 229 | ); | ||
| 230 | } | ||
| 231 | |||
| 232 | function ComboboxGroup({ className, ...props }: ComboboxPrimitive.Group.Props) { | ||
| 233 | return ( | ||
| 234 | <ComboboxPrimitive.Group | ||
| 235 | className={cn("[[role=group]+&]:mt-1.5", className)} | ||
| 236 | data-slot="combobox-group" | ||
| 237 | {...props} | ||
| 238 | /> | ||
| 239 | ); | ||
| 240 | } | ||
| 241 | |||
| 242 | function ComboboxGroupLabel({ className, ...props }: ComboboxPrimitive.GroupLabel.Props) { | ||
| 243 | return ( | ||
| 244 | <ComboboxPrimitive.GroupLabel | ||
| 245 | className={cn("px-2 py-1.5 font-medium text-muted-foreground text-xs", className)} | ||
| 246 | data-slot="combobox-group-label" | ||
| 247 | {...props} | ||
| 248 | /> | ||
| 249 | ); | ||
| 250 | } | ||
| 251 | |||
| 252 | function ComboboxEmpty({ className, ...props }: ComboboxPrimitive.Empty.Props) { | 195 | function ComboboxEmpty({ className, ...props }: ComboboxPrimitive.Empty.Props) { |
| 253 | return ( | 196 | return ( |
| 254 | <ComboboxPrimitive.Empty | 197 | <ComboboxPrimitive.Empty |
| @@ -262,14 +205,6 @@ function ComboboxEmpty({ className, ...props }: ComboboxPrimitive.Empty.Props) { · 7 unmodified lines | |||
| 262 | ); | 205 | ); |
| 263 | } | 206 | } |
| 264 | 207 | ||
| 265 | function ComboboxRow({ className, ...props }: ComboboxPrimitive.Row.Props) { | ||
| 266 | return <ComboboxPrimitive.Row className={className} data-slot="combobox-row" {...props} />; | ||
| 267 | } | ||
| 268 | |||
| 269 | function ComboboxValue({ ...props }: ComboboxPrimitive.Value.Props) { | ||
| 270 | return <ComboboxPrimitive.Value data-slot="combobox-value" {...props} />; | ||
| 271 | } | ||
| 272 | |||
| 273 | function ComboboxList({ className, ...props }: ComboboxPrimitive.List.Props) { | 208 | function ComboboxList({ className, ...props }: ComboboxPrimitive.List.Props) { |
| 274 | return ( | 209 | return ( |
| 275 | <ScrollArea scrollbarGutter scrollFade> | 210 | <ScrollArea scrollbarGutter scrollFade> |
| @@ -313,91 +248,17 @@ function ComboboxStatus({ className, ...props }: ComboboxPrimitive.Status.Props) · 37 unmodified lines | |||
| 313 | ); | 248 | ); |
| 314 | } | 249 | } |
| 315 | 250 | ||
| 316 | function ComboboxCollection(props: ComboboxPrimitive.Collection.Props) { | ||
| 317 | return <ComboboxPrimitive.Collection data-slot="combobox-collection" {...props} />; | ||
| 318 | } | ||
| 319 | |||
| 320 | function ComboboxChips({ | ||
| 321 | className, | ||
| 322 | children, | ||
| 323 | startAddon, | ||
| 324 | ...props | ||
| 325 | }: ComboboxPrimitive.Chips.Props & { | ||
| 326 | startAddon?: React.ReactNode; | ||
| 327 | }) { | ||
| 328 | const { chipsRef } = React.use(ComboboxContext); | ||
| 329 | |||
| 330 | return ( | ||
| 331 | <ComboboxPrimitive.Chips | ||
| 332 | className={cn( | ||
| 333 | "relative inline-flex min-h-9 w-full flex-wrap gap-1 rounded-lg border border-input bg-background not-dark:bg-clip-padding p-[calc(--spacing(1)-1px)] text-base shadow-xs/5 outline-none ring-ring/24 transition-shadow *:min-h-7 before:pointer-events-none before:absolute before:inset-0 before:rounded-[calc(var(--radius-lg)-1px)] not-has-disabled:not-focus-within:not-aria-invalid:before:shadow-[0_1px_--theme(--color-black/4%)] focus-within:border-ring focus-within:ring-[3px] has-disabled:pointer-events-none has-data-[size=lg]:min-h-10 has-data-[size=sm]:min-h-8 has-aria-invalid:border-destructive/36 has-autofill:bg-foreground/4 has-disabled:opacity-64 has-[:disabled,:focus-within,[aria-invalid]]:shadow-none focus-within:has-aria-invalid:border-destructive/64 focus-within:has-aria-invalid:ring-destructive/16 has-data-[size=lg]:*:min-h-8 has-data-[size=sm]:*:min-h-6 sm:min-h-8 sm:text-sm sm:has-data-[size=lg]:min-h-9 sm:has-data-[size=sm]:min-h-7 sm:*:min-h-6 sm:has-data-[size=lg]:*:min-h-7 sm:has-data-[size=sm]:*:min-h-5 dark:not-has-disabled:bg-input/32 dark:has-autofill:bg-foreground/8 dark:has-aria-invalid:ring-destructive/24 dark:not-has-disabled:not-focus-within:not-aria-invalid:before:shadow-[0_-1px_--theme(--color-white/6%)]", | ||
| 334 | className, | ||
| 335 | )} | ||
| 336 | data-slot="combobox-chips" | ||
| 337 | ref={chipsRef as React.Ref<HTMLDivElement> | null} | ||
| 338 | {...props} | ||
| 339 | > | ||
| 340 | {startAddon && ( | ||
| 341 | <div | ||
| 342 | aria-hidden="true" | ||
| 343 | className="[&_svg]:-ms-0.5 [&_svg]:-me-1.5 flex shrink-0 items-center ps-2 opacity-80 has-[~[data-size=sm]]:has-[+[data-slot=combobox-chip]]:pe-1.5 has-[~[data-size=sm]]:ps-1.5 has-[+[data-slot=combobox-chip]]:pe-2 [&_svg:not([class*='size-'])]:size-4.5 sm:[&_svg:not([class*='size-'])]:size-4 [&_svg]:pointer-events-none" | ||
| 344 | data-slot="combobox-start-addon" | ||
| 345 | > | ||
| 346 | {startAddon} | ||
| 347 | </div> | ||
| 348 | )} | ||
| 349 | {children} | ||
| 350 | </ComboboxPrimitive.Chips> | ||
| 351 | ); | ||
| 352 | } | ||
| 353 | |||
| 354 | function ComboboxChip({ children, ...props }: ComboboxPrimitive.Chip.Props) { | ||
| 355 | return ( | ||
| 356 | <ComboboxPrimitive.Chip | ||
| 357 | className="flex items-center rounded-[calc(var(--radius-md)-1px)] bg-accent ps-2 font-medium text-accent-foreground text-sm outline-none sm:text-xs/(--text-xs--line-height) [&_svg:not([class*='size-'])]:size-4 sm:[&_svg:not([class*='size-'])]:size-3.5" | ||
| 358 | data-slot="combobox-chip" | ||
| 359 | {...props} | ||
| 360 | > | ||
| 361 | {children} | ||
| 362 | <ComboboxChipRemove /> | ||
| 363 | </ComboboxPrimitive.Chip> | ||
| 364 | ); | ||
| 365 | } | ||
| 366 | |||
| 367 | function ComboboxChipRemove(props: ComboboxPrimitive.ChipRemove.Props) { | ||
| 368 | return ( | ||
| 369 | <ComboboxPrimitive.ChipRemove | ||
| 370 | aria-label="Remove" | ||
| 371 | className="h-full shrink-0 cursor-pointer px-1.5 opacity-80 hover:opacity-100 [&_svg:not([class*='size-'])]:size-4 sm:[&_svg:not([class*='size-'])]:size-3.5" | ||
| 372 | data-slot="combobox-chip-remove" | ||
| 373 | {...props} | ||
| 374 | > | ||
| 375 | <XIcon /> | ||
| 376 | </ComboboxPrimitive.ChipRemove> | ||
| 377 | ); | ||
| 378 | } | ||
| 379 | |||
| 380 | const useComboboxFilter = ComboboxPrimitive.useFilter; | 251 | const useComboboxFilter = ComboboxPrimitive.useFilter; |
| 381 | 252 | ||
| 382 | export { | 253 | export { |
| 383 | Combobox, | 254 | Combobox, |
| 384 | ComboboxChipsInput, | ||
| 385 | ComboboxInput, | 255 | ComboboxInput, |
| 386 | ComboboxTrigger, | 256 | ComboboxTrigger, |
| 387 | ComboboxPopup, | 257 | ComboboxPopup, |
| 388 | ComboboxItem, | 258 | ComboboxItem, |
| 389 | ComboboxSeparator, | ||
| 390 | ComboboxGroup, | ||
| 391 | ComboboxGroupLabel, | ||
| 392 | ComboboxEmpty, | 259 | ComboboxEmpty, |
| 393 | ComboboxValue, | ||
| 394 | ComboboxList, | 260 | ComboboxList, |
| 395 | ComboboxListVirtualized, | 261 | ComboboxListVirtualized, |
| 396 | ComboboxClear, | ||
| 397 | ComboboxStatus, | 262 | ComboboxStatus, |
| 398 | ComboboxRow, | ||
| 399 | ComboboxCollection, | ||
| 400 | ComboboxChips, | ||
| 401 | ComboboxChip, | ||
| 402 | useComboboxFilter, | 263 | useComboboxFilter, |
| 403 | }; | 264 | }; |
| @@ -5,7 +5,6 @@ import type * as React from "react"; · 4 unmodified lines | |||
| 5 | 5 | ||
| 6 | import { cn } from "~/lib/utils"; | 6 | import { cn } from "~/lib/utils"; |
| 7 | import { Input, type InputProps } from "~/components/ui/input"; | 7 | import { Input, type InputProps } from "~/components/ui/input"; |
| 8 | import { Textarea, type TextareaProps } from "~/components/ui/textarea"; | ||
| 9 | 8 | ||
| 10 | const inputGroupVariants = cva( | 9 | const inputGroupVariants = cva( |
| 11 | "relative inline-flex w-full min-w-0 items-center rounded-[var(--control-radius)] border text-base text-foreground ring-ring/24 transition-shadow has-[input:focus-visible,textarea:focus-visible]:has-[input[aria-invalid],textarea[aria-invalid]]:border-destructive/64 has-[input:focus-visible,textarea:focus-visible]:has-[input[aria-invalid],textarea[aria-invalid]]:ring-destructive/16 has-[textarea]:h-auto has-data-[align=block-end]:h-auto has-data-[align=block-start]:h-auto has-data-[align=block-end]:flex-col has-data-[align=block-start]:flex-col has-[input:focus-visible,textarea:focus-visible]:border-ring has-[input[aria-invalid],textarea[aria-invalid]]:border-destructive/36 has-autofill:bg-foreground/4 has-[input:disabled,textarea:disabled]:opacity-64 has-[input:disabled,textarea:disabled,input:focus-visible,textarea:focus-visible,input[aria-invalid],textarea[aria-invalid]]:shadow-none has-[input:focus-visible,textarea:focus-visible]:ring-[3px] sm:text-sm dark:has-autofill:bg-foreground/8 dark:has-[input[aria-invalid],textarea[aria-invalid]]:ring-destructive/24 has-data-[align=inline-start]:**:[[data-size=sm]_input]:ps-1.5 has-data-[align=inline-end]:**:[[data-size=sm]_input]:pe-1.5 *:[[data-slot=input-control],[data-slot=textarea-control]]:contents *:[[data-slot=input-control],[data-slot=textarea-control]]:before:hidden has-[[data-align=block-start],[data-align=block-end]]:**:[input]:h-auto has-data-[align=inline-start]:**:[input]:ps-2 has-data-[align=inline-end]:**:[input]:pe-2 has-data-[align=block-end]:**:[input]:pt-1.5 has-data-[align=block-start]:**:[input]:pb-1.5 **:[textarea]:min-h-20.5 **:[textarea]:resize-none **:[textarea]:py-[calc(--spacing(3)-1px)] **:[textarea]:max-sm:min-h-23.5 **:[textarea_button]:rounded-[calc(var(--control-radius)-1px)]", | 10 | "relative inline-flex w-full min-w-0 items-center rounded-[var(--control-radius)] border text-base text-foreground ring-ring/24 transition-shadow has-[input:focus-visible,textarea:focus-visible]:has-[input[aria-invalid],textarea[aria-invalid]]:border-destructive/64 has-[input:focus-visible,textarea:focus-visible]:has-[input[aria-invalid],textarea[aria-invalid]]:ring-destructive/16 has-[textarea]:h-auto has-data-[align=block-end]:h-auto has-data-[align=block-start]:h-auto has-data-[align=block-end]:flex-col has-data-[align=block-start]:flex-col has-[input:focus-visible,textarea:focus-visible]:border-ring has-[input[aria-invalid],textarea[aria-invalid]]:border-destructive/36 has-autofill:bg-foreground/4 has-[input:disabled,textarea:disabled]:opacity-64 has-[input:disabled,textarea:disabled,input:focus-visible,textarea:focus-visible,input[aria-invalid],textarea[aria-invalid]]:shadow-none has-[input:focus-visible,textarea:focus-visible]:ring-[3px] sm:text-sm dark:has-autofill:bg-foreground/8 dark:has-[input[aria-invalid],textarea[aria-invalid]]:ring-destructive/24 has-data-[align=inline-start]:**:[[data-size=sm]_input]:ps-1.5 has-data-[align=inline-end]:**:[[data-size=sm]_input]:pe-1.5 *:[[data-slot=input-control],[data-slot=textarea-control]]:contents *:[[data-slot=input-control],[data-slot=textarea-control]]:before:hidden has-[[data-align=block-start],[data-align=block-end]]:**:[input]:h-auto has-data-[align=inline-start]:**:[input]:ps-2 has-data-[align=inline-end]:**:[input]:pe-2 has-data-[align=block-end]:**:[input]:pt-1.5 has-data-[align=block-start]:**:[input]:pb-1.5 **:[textarea]:min-h-20.5 **:[textarea]:resize-none **:[textarea]:py-[calc(--spacing(3)-1px)] **:[textarea]:max-sm:min-h-23.5 **:[textarea_button]:rounded-[calc(var(--control-radius)-1px)]", |
| @@ -90,24 +89,8 @@ function InputGroupAddon({ · 78 unmodified lines | |||
| 90 | ); | 89 | ); |
| 91 | } | 90 | } |
| 92 | 91 | ||
| 93 | function InputGroupText({ className, ...props }: React.ComponentProps<"span">) { | ||
| 94 | return ( | ||
| 95 | <span | ||
| 96 | className={cn( | ||
| 97 | "[&_svg]:-mx-0.5 line-clamp-1 flex items-center gap-2 text-muted-foreground leading-none in-[[data-slot=input-group]:has([data-slot=input-control],[data-slot=textarea-control])]:[&_svg:not([class*='size-'])]:size-4.5 sm:in-[[data-slot=input-group]:has([data-slot=input-control],[data-slot=textarea-control])]:[&_svg:not([class*='size-'])]:size-4 [&_svg]:pointer-events-none", | ||
| 98 | className, | ||
| 99 | )} | ||
| 100 | {...props} | ||
| 101 | /> | ||
| 102 | ); | ||
| 103 | } | ||
| 104 | |||
| 105 | function InputGroupInput({ className, ...props }: InputProps) { | 92 | function InputGroupInput({ className, ...props }: InputProps) { |
| 106 | return <Input className={className} unstyled {...props} />; | 93 | return <Input className={className} unstyled {...props} />; |
| 107 | } | 94 | } |
| 108 | 95 | ||
| 109 | function InputGroupTextarea({ className, ...props }: TextareaProps) { | 96 | export { InputGroup, InputGroupAddon, InputGroupInput }; |
| 110 | return <Textarea className={className} unstyled {...props} />; | ||
| 111 | } | ||
| 112 | |||
| 113 | export { InputGroup, InputGroupAddon, InputGroupText, InputGroupInput, InputGroupTextarea }; | ||
| @@ -4,13 +4,6 @@ import { NumberField as NumberFieldPrimitive } from "@base-ui/react/number-field · 3 unmodified lines | |||
| 4 | import { MinusIcon, PlusIcon } from "lucide-react"; | 4 | import { MinusIcon, PlusIcon } from "lucide-react"; |
| 5 | import * as React from "react"; | 5 | import * as React from "react"; |
| 6 | import { cn } from "~/lib/utils"; | 6 | import { cn } from "~/lib/utils"; |
| 7 | import { Label } from "~/components/ui/label"; | ||
| 8 | |||
| 9 | export const NumberFieldContext: React.Context<{ | ||
| 10 | fieldId: string; | ||
| 11 | } | null> = React.createContext<{ | ||
| 12 | fieldId: string; | ||
| 13 | } | null>(null); | ||
| 14 | 7 | ||
| 15 | export function NumberField({ | 8 | export function NumberField({ |
| 16 | id, | 9 | id, |
| @@ -22,18 +15,15 @@ export function NumberField({ · 5 unmodified lines | |||
| 22 | }): React.ReactElement { | 15 | }): React.ReactElement { |
| 23 | const generatedId = React.useId(); | 16 | const generatedId = React.useId(); |
| 24 | const fieldId = id ?? generatedId; | 17 | const fieldId = id ?? generatedId; |
| 25 | const contextValue = React.useMemo(() => ({ fieldId }), [fieldId]); | ||
| 26 | 18 | ||
| 27 | return ( | 19 | return ( |
| 28 | <NumberFieldContext value={contextValue}> | 20 | <NumberFieldPrimitive.Root |
| 29 | <NumberFieldPrimitive.Root | 21 | className={cn("flex w-full flex-col items-start gap-2", className)} |
| 30 | className={cn("flex w-full flex-col items-start gap-2", className)} | 22 | data-size={size} |
| 31 | data-size={size} | 23 | data-slot="number-field" |
| 32 | data-slot="number-field" | 24 | id={fieldId} |
| 33 | id={fieldId} | 25 | {...props} |
| 34 | {...props} | 26 | /> |
| 35 | /> | ||
| 36 | </NumberFieldContext> | ||
| 37 | ); | 27 | ); |
| 38 | } | 28 | } |
| 39 | 29 | ||
| @@ -104,53 +94,3 @@ export function NumberFieldInput({ · 64 unmodified lines | |||
| 104 | /> | 94 | /> |
| 105 | ); | 95 | ); |
| 106 | } | 96 | } |
| 107 | |||
| 108 | export function NumberFieldScrubArea({ | ||
| 109 | className, | ||
| 110 | label, | ||
| 111 | ...props | ||
| 112 | }: NumberFieldPrimitive.ScrubArea.Props & { | ||
| 113 | label: string; | ||
| 114 | }): React.ReactElement { | ||
| 115 | const context = React.use(NumberFieldContext); | ||
| 116 | |||
| 117 | if (!context) { | ||
| 118 | throw new Error( | ||
| 119 | "NumberFieldScrubArea must be used within a NumberField component for accessibility.", | ||
| 120 | ); | ||
| 121 | } | ||
| 122 | |||
| 123 | return ( | ||
| 124 | <NumberFieldPrimitive.ScrubArea | ||
| 125 | className={cn("flex cursor-ew-resize", className)} | ||
| 126 | data-slot="number-field-scrub-area" | ||
| 127 | {...props} | ||
| 128 | > | ||
| 129 | <Label className="cursor-ew-resize" htmlFor={context.fieldId}> | ||
| 130 | {label} | ||
| 131 | </Label> | ||
| 132 | <NumberFieldPrimitive.ScrubAreaCursor className="drop-shadow-[0_1px_1px_#0008] filter"> | ||
| 133 | <CursorGrowIcon /> | ||
| 134 | </NumberFieldPrimitive.ScrubAreaCursor> | ||
| 135 | </NumberFieldPrimitive.ScrubArea> | ||
| 136 | ); | ||
| 137 | } | ||
| 138 | |||
| 139 | export function CursorGrowIcon(props: React.ComponentProps<"svg">): React.ReactElement { | ||
| 140 | return ( | ||
| 141 | <svg | ||
| 142 | aria-hidden="true" | ||
| 143 | fill="black" | ||
| 144 | height="14" | ||
| 145 | stroke="white" | ||
| 146 | viewBox="0 0 24 14" | ||
| 147 | width="26" | ||
| 148 | xmlns="http://www.w3.org/2000/svg" | ||
| 149 | {...props} | ||
| 150 | > | ||
| 151 | <path d="M19.5 5.5L6.49737 5.51844V2L1 6.9999L6.5 12L6.49737 8.5L19.5 8.5V12L25 6.9999L19.5 2V5.5Z" /> | ||
| 152 | </svg> | ||
| 153 | ); | ||
| 154 | } | ||
| 155 | |||
| 156 | export { NumberFieldPrimitive }; | ||
| @@ -1,6 +1,5 @@ | |||
| 1 | "use client"; | 1 | "use client"; |
| 2 | 2 | ||
| 3 | import { Radio as RadioPrimitive } from "@base-ui/react/radio"; | ||
| 4 | import { RadioGroup as RadioGroupPrimitive } from "@base-ui/react/radio-group"; | 3 | import { RadioGroup as RadioGroupPrimitive } from "@base-ui/react/radio-group"; |
| 5 | 4 | ||
| 6 | import { cn } from "~/lib/utils"; | 5 | import { cn } from "~/lib/utils"; |
| @@ -15,22 +14,4 @@ function RadioGroup({ className, ...props }: RadioGroupPrimitive.Props) { · 8 unmodified lines | |||
| 15 | ); | 14 | ); |
| 16 | } | 15 | } |
| 17 | 16 | ||
| 18 | function Radio({ className, ...props }: RadioPrimitive.Root.Props) { | 17 | export { RadioGroup }; |
| 19 | return ( | ||
| 20 | <RadioPrimitive.Root | ||
| 21 | className={cn( | ||
| 22 | "relative inline-flex size-4.5 shrink-0 items-center justify-center rounded-full border border-input bg-background not-dark:bg-clip-padding shadow-xs/5 outline-none transition-shadow before:pointer-events-none before:absolute before:inset-0 before:rounded-full not-data-disabled:not-data-checked:not-aria-invalid:before:shadow-[0_1px_--theme(--color-black/4%)] focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-1 focus-visible:ring-offset-background aria-invalid:border-destructive/36 focus-visible:aria-invalid:border-destructive/64 focus-visible:aria-invalid:ring-destructive/48 data-disabled:opacity-64 sm:size-4 dark:not-data-checked:bg-input/32 dark:aria-invalid:ring-destructive/24 dark:not-data-disabled:not-data-checked:not-aria-invalid:before:shadow-[0_-1px_--theme(--color-white/6%)] [[data-disabled],[data-checked],[aria-invalid]]:shadow-none", | ||
| 23 | className, | ||
| 24 | )} | ||
| 25 | data-slot="radio" | ||
| 26 | {...props} | ||
| 27 | > | ||
| 28 | <RadioPrimitive.Indicator | ||
| 29 | className="-inset-px absolute flex size-4.5 items-center justify-center rounded-full before:size-2 before:rounded-full before:bg-primary-foreground data-unchecked:hidden data-checked:bg-primary sm:size-4 sm:before:size-1.5" | ||
| 30 | data-slot="radio-indicator" | ||
| 31 | /> | ||
| 32 | </RadioPrimitive.Root> | ||
| 33 | ); | ||
| 34 | } | ||
| 35 | |||
| 36 | export { RadioGroup, Radio, Radio as RadioGroupItem }; | ||
| @@ -1,10 +1,8 @@ | |||
| 1 | "use client"; | 1 | "use client"; |
| 2 | 2 | ||
| 3 | import { mergeProps } from "@base-ui/react/merge-props"; | ||
| 4 | import { Select as SelectPrimitive } from "@base-ui/react/select"; | 3 | import { Select as SelectPrimitive } from "@base-ui/react/select"; |
| 5 | import { useRender } from "@base-ui/react/use-render"; | ||
| 6 | import { cva, type VariantProps } from "class-variance-authority"; | 4 | import { cva, type VariantProps } from "class-variance-authority"; |
| 7 | import { CheckIcon, ChevronDownIcon, ChevronsUpDownIcon, ChevronUpIcon } from "lucide-react"; | 5 | import { CheckIcon, ChevronDownIcon, ChevronUpIcon } from "lucide-react"; |
| 8 | import type * as React from "react"; | 6 | import type * as React from "react"; |
| 9 | 7 | ||
| 10 | import { cn } from "~/lib/utils"; | 8 | import { cn } from "~/lib/utils"; |
| @@ -37,41 +35,6 @@ const selectTriggerVariants = cva( · 26 unmodified lines | |||
| 37 | }, | 35 | }, |
| 38 | ); | 36 | ); |
| 39 | 37 | ||
| 40 | const selectTriggerIconClassName = "-me-1 size-4.5 opacity-80 sm:size-4"; | ||
| 41 | |||
| 42 | interface SelectButtonProps extends useRender.ComponentProps<"button"> { | ||
| 43 | size?: VariantProps<typeof selectTriggerVariants>["size"]; | ||
| 44 | variant?: VariantProps<typeof selectTriggerVariants>["variant"]; | ||
| 45 | } | ||
| 46 | |||
| 47 | function SelectButton({ className, size, variant, render, children, ...props }: SelectButtonProps) { | ||
| 48 | const typeValue: React.ButtonHTMLAttributes<HTMLButtonElement>["type"] = render | ||
| 49 | ? undefined | ||
| 50 | : "button"; | ||
| 51 | |||
| 52 | const defaultProps = { | ||
| 53 | children: ( | ||
| 54 | <> | ||
| 55 | <span className="flex-1 truncate in-data-placeholder:text-placeholder">{children}</span> | ||
| 56 | {variant === "ghost" ? ( | ||
| 57 | <ChevronDownIcon className="-me-1 size-3 opacity-50" /> | ||
| 58 | ) : ( | ||
| 59 | <ChevronsUpDownIcon className={selectTriggerIconClassName} /> | ||
| 60 | )} | ||
| 61 | </> | ||
| 62 | ), | ||
| 63 | className: cn(selectTriggerVariants({ size, variant }), "min-w-none", className), | ||
| 64 | "data-slot": "select-button", | ||
| 65 | type: typeValue, | ||
| 66 | }; | ||
| 67 | |||
| 68 | return useRender({ | ||
| 69 | defaultTagName: "button", | ||
| 70 | props: mergeProps<"button">(defaultProps, props), | ||
| 71 | render, | ||
| 72 | }); | ||
| 73 | } | ||
| 74 | |||
| 75 | function SelectTrigger({ | 38 | function SelectTrigger({ |
| 76 | className, | 39 | className, |
| 77 | size = "default", | 40 | size = "default", |
| @@ -216,16 +179,6 @@ function SelectItem({ · 138 unmodified lines | |||
| 216 | ); | 179 | ); |
| 217 | } | 180 | } |
| 218 | 181 | ||
| 219 | function SelectSeparator({ className, ...props }: SelectPrimitive.Separator.Props) { | ||
| 220 | return ( | ||
| 221 | <SelectPrimitive.Separator | ||
| 222 | className={cn("mx-2 my-1 h-px bg-border", className)} | ||
| 223 | data-slot="select-separator" | ||
| 224 | {...props} | ||
| 225 | /> | ||
| 226 | ); | ||
| 227 | } | ||
| 228 | |||
| 229 | function SelectGroup(props: SelectPrimitive.Group.Props) { | 182 | function SelectGroup(props: SelectPrimitive.Group.Props) { |
| 230 | return <SelectPrimitive.Group data-slot="select-group" {...props} />; | 183 | return <SelectPrimitive.Group data-slot="select-group" {...props} />; |
| 231 | } | 184 | } |
| @@ -243,13 +196,11 @@ function SelectGroupLabel(props: SelectPrimitive.GroupLabel.Props) { · 11 unmodified lines | |||
| 243 | export { | 196 | export { |
| 244 | Select, | 197 | Select, |
| 245 | SelectTrigger, | 198 | SelectTrigger, |
| 246 | SelectButton, | ||
| 247 | selectTriggerVariants, | 199 | selectTriggerVariants, |
| 248 | SelectValue, | 200 | SelectValue, |
| 249 | SelectPopup, | 201 | SelectPopup, |
| 250 | SelectPopup as SelectContent, | 202 | SelectPopup as SelectContent, |
| 251 | SelectItem, | 203 | SelectItem, |
| 252 | SelectSeparator, | ||
| 253 | SelectGroup, | 204 | SelectGroup, |
| 254 | SelectGroupLabel, | 205 | SelectGroupLabel, |
| 255 | }; | 206 | }; |
| @@ -6,7 +6,6 @@ import type { VariantProps } from "class-variance-authority"; · 5 unmodified lines | |||
| 6 | import * as React from "react"; | 6 | import * as React from "react"; |
| 7 | 7 | ||
| 8 | import { cn } from "~/lib/utils"; | 8 | import { cn } from "~/lib/utils"; |
| 9 | import { Separator } from "~/components/ui/separator"; | ||
| 10 | import { Toggle as ToggleComponent, type toggleVariants } from "~/components/ui/toggle"; | 9 | import { Toggle as ToggleComponent, type toggleVariants } from "~/components/ui/toggle"; |
| 11 | 10 | ||
| 12 | const ToggleGroupContext = React.createContext<VariantProps<typeof toggleVariants>>({ | 11 | const ToggleGroupContext = React.createContext<VariantProps<typeof toggleVariants>>({ |
| @@ -76,23 +75,4 @@ function Toggle({ · 63 unmodified lines | |||
| 76 | ); | 75 | ); |
| 77 | } | 76 | } |
| 78 | 77 | ||
| 79 | function ToggleGroupSeparator({ | 78 | export { ToggleGroup, Toggle }; |
| 80 | className, | ||
| 81 | orientation = "vertical", | ||
| 82 | ...props | ||
| 83 | }: { | ||
| 84 | className?: string; | ||
| 85 | } & React.ComponentProps<typeof Separator>) { | ||
| 86 | return ( | ||
| 87 | <Separator | ||
| 88 | className={cn( | ||
| 89 | "pointer-events-none relative bg-input before:absolute before:inset-0 dark:before:bg-input/32", | ||
| 90 | className, | ||
| 91 | )} | ||
| 92 | orientation={orientation} | ||
| 93 | {...props} | ||
| 94 | /> | ||
| 95 | ); | ||
| 96 | } | ||
| 97 | |||
| 98 | export { ToggleGroup, Toggle, Toggle as ToggleGroupItem, ToggleGroupSeparator }; | ||