History

refactor(web): remove unused input component variants

Julius Marminge committed 2 months ago

Commit 9d12bd71 parent 7503d747 files · +12 −347Browse files

Showing the changes to apps/web/src (7 of 7 files). Show all

Unified · Split

7 files
  1. apps/web/src/components/ui/autocomplete.tsx +0 −31
  2. apps/web/src/components/ui/combobox.tsx +1 −140
  3. apps/web/src/components/ui/input-group.tsx +1 −18
  4. apps/web/src/components/ui/number-field.tsx +7 −67
  5. apps/web/src/components/ui/radio-group.tsx +1 −20
  6. apps/web/src/components/ui/select.tsx +1 −50
  7. apps/web/src/components/ui/toggle-group.tsx +1 −21
apps/web/src/components/ui/autocomplete.tsx+0−31
@@ -179,16 +179,6 @@ function AutocompleteEmpty({ className, ...props }: AutocompletePrimitive.Empty. · 178 unmodified lines
179 );179 );
180}180}
181 181
182function AutocompleteRow({ className, ...props }: AutocompletePrimitive.Row.Props) {
183 return (
184 <AutocompletePrimitive.Row className={className} data-slot="autocomplete-row" {...props} />
185 );
186}
187
188function AutocompleteValue({ ...props }: AutocompletePrimitive.Value.Props) {
189 return <AutocompletePrimitive.Value data-slot="autocomplete-value" {...props} />;
190}
191
192function AutocompleteList({ className, ...props }: AutocompletePrimitive.List.Props) {182function 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
219function 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
232function AutocompleteCollection({ ...props }: AutocompletePrimitive.Collection.Props) {209function 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
252const useAutocompleteFilter = AutocompletePrimitive.useFilter;
253
254export {229export {
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};
apps/web/src/components/ui/combobox.tsx+1−140
@@ -10,17 +10,15 @@ import { ScrollArea } from "~/components/ui/scroll-area"; · 9 unmodified lines
10 10
11const ComboboxContext = React.createContext<{11const 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
19function Combobox<Value, Multiple extends boolean | undefined = false>(17function 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
31function 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
56function ComboboxInput({29function ComboboxInput({
57 className,30 className,
58 inputClassName,31 inputClassName,
@@ -219,36 +192,6 @@ function ComboboxItem({ · 160 unmodified lines
219 );192 );
220}193}
221 194
222function 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
232function 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
242function 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
252function ComboboxEmpty({ className, ...props }: ComboboxPrimitive.Empty.Props) {195function ComboboxEmpty({ className, ...props }: ComboboxPrimitive.Empty.Props) {
253 return (196 return (
254 <ComboboxPrimitive.Empty197 <ComboboxPrimitive.Empty
@@ -262,14 +205,6 @@ function ComboboxEmpty({ className, ...props }: ComboboxPrimitive.Empty.Props) { · 7 unmodified lines
262 );205 );
263}206}
264 207
265function ComboboxRow({ className, ...props }: ComboboxPrimitive.Row.Props) {
266 return <ComboboxPrimitive.Row className={className} data-slot="combobox-row" {...props} />;
267}
268
269function ComboboxValue({ ...props }: ComboboxPrimitive.Value.Props) {
270 return <ComboboxPrimitive.Value data-slot="combobox-value" {...props} />;
271}
272
273function ComboboxList({ className, ...props }: ComboboxPrimitive.List.Props) {208function 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
316function ComboboxCollection(props: ComboboxPrimitive.Collection.Props) {
317 return <ComboboxPrimitive.Collection data-slot="combobox-collection" {...props} />;
318}
319
320function 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
354function 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
367function 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
380const useComboboxFilter = ComboboxPrimitive.useFilter;251const useComboboxFilter = ComboboxPrimitive.useFilter;
381 252
382export {253export {
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};
apps/web/src/components/ui/input-group.tsx+1−18
@@ -5,7 +5,6 @@ import type * as React from "react"; · 4 unmodified lines
5 5
6import { cn } from "~/lib/utils";6import { cn } from "~/lib/utils";
7import { Input, type InputProps } from "~/components/ui/input";7import { Input, type InputProps } from "~/components/ui/input";
8import { Textarea, type TextareaProps } from "~/components/ui/textarea";
9 8
10const inputGroupVariants = cva(9const 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
93function 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
105function InputGroupInput({ className, ...props }: InputProps) {92function InputGroupInput({ className, ...props }: InputProps) {
106 return <Input className={className} unstyled {...props} />;93 return <Input className={className} unstyled {...props} />;
107}94}
108 95
109function InputGroupTextarea({ className, ...props }: TextareaProps) {96export { InputGroup, InputGroupAddon, InputGroupInput };
110 return <Textarea className={className} unstyled {...props} />;
111}
112
113export { InputGroup, InputGroupAddon, InputGroupText, InputGroupInput, InputGroupTextarea };
apps/web/src/components/ui/number-field.tsx+7−67
@@ -4,13 +4,6 @@ import { NumberField as NumberFieldPrimitive } from "@base-ui/react/number-field · 3 unmodified lines
4import { MinusIcon, PlusIcon } from "lucide-react";4import { MinusIcon, PlusIcon } from "lucide-react";
5import * as React from "react";5import * as React from "react";
6import { cn } from "~/lib/utils";6import { cn } from "~/lib/utils";
7import { Label } from "~/components/ui/label";
8
9export const NumberFieldContext: React.Context<{
10 fieldId: string;
11} | null> = React.createContext<{
12 fieldId: string;
13} | null>(null);
14 7
15export function NumberField({8export 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.Root21 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
108export 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
139export 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
156export { NumberFieldPrimitive };
apps/web/src/components/ui/radio-group.tsx+1−20
@@ -1,6 +1,5 @@
1"use client";1"use client";
2 2
3import { Radio as RadioPrimitive } from "@base-ui/react/radio";
4import { RadioGroup as RadioGroupPrimitive } from "@base-ui/react/radio-group";3import { RadioGroup as RadioGroupPrimitive } from "@base-ui/react/radio-group";
5 4
6import { cn } from "~/lib/utils";5import { cn } from "~/lib/utils";
@@ -15,22 +14,4 @@ function RadioGroup({ className, ...props }: RadioGroupPrimitive.Props) { · 8 unmodified lines
15 );14 );
16}15}
17 16
18function Radio({ className, ...props }: RadioPrimitive.Root.Props) {17export { 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
36export { RadioGroup, Radio, Radio as RadioGroupItem };
apps/web/src/components/ui/select.tsx+1−50
@@ -1,10 +1,8 @@
1"use client";1"use client";
2 2
3import { mergeProps } from "@base-ui/react/merge-props";
4import { Select as SelectPrimitive } from "@base-ui/react/select";3import { Select as SelectPrimitive } from "@base-ui/react/select";
5import { useRender } from "@base-ui/react/use-render";
6import { cva, type VariantProps } from "class-variance-authority";4import { cva, type VariantProps } from "class-variance-authority";
7import { CheckIcon, ChevronDownIcon, ChevronsUpDownIcon, ChevronUpIcon } from "lucide-react";5import { CheckIcon, ChevronDownIcon, ChevronUpIcon } from "lucide-react";
8import type * as React from "react";6import type * as React from "react";
9 7
10import { cn } from "~/lib/utils";8import { cn } from "~/lib/utils";
@@ -37,41 +35,6 @@ const selectTriggerVariants = cva( · 26 unmodified lines
37 },35 },
38);36);
39 37
40const selectTriggerIconClassName = "-me-1 size-4.5 opacity-80 sm:size-4";
41
42interface SelectButtonProps extends useRender.ComponentProps<"button"> {
43 size?: VariantProps<typeof selectTriggerVariants>["size"];
44 variant?: VariantProps<typeof selectTriggerVariants>["variant"];
45}
46
47function 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
75function SelectTrigger({38function 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
219function 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
229function SelectGroup(props: SelectPrimitive.Group.Props) {182function 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
243export {196export {
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};
apps/web/src/components/ui/toggle-group.tsx+1−21
@@ -6,7 +6,6 @@ import type { VariantProps } from "class-variance-authority"; · 5 unmodified lines
6import * as React from "react";6import * as React from "react";
7 7
8import { cn } from "~/lib/utils";8import { cn } from "~/lib/utils";
9import { Separator } from "~/components/ui/separator";
10import { Toggle as ToggleComponent, type toggleVariants } from "~/components/ui/toggle";9import { Toggle as ToggleComponent, type toggleVariants } from "~/components/ui/toggle";
11 10
12const ToggleGroupContext = React.createContext<VariantProps<typeof toggleVariants>>({11const ToggleGroupContext = React.createContext<VariantProps<typeof toggleVariants>>({
@@ -76,23 +75,4 @@ function Toggle({ · 63 unmodified lines
76 );75 );
77}76}
78 77
79function ToggleGroupSeparator({78export { 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
98export { ToggleGroup, Toggle, Toggle as ToggleGroupItem, ToggleGroupSeparator };