The weeb for the next gen discord boat - Wamellow wamellow.com
bot discord
at master 213 lines 5.9 kB view raw
1"use client"; 2 3import { Button } from "@/components/ui/button"; 4import { cn } from "@/utils/cn"; 5import { composeEventHandlers } from "@radix-ui/primitive"; 6import { useComposedRefs } from "@radix-ui/react-compose-refs"; 7import { Primitive } from "@radix-ui/react-primitive"; 8import { Slot } from "@radix-ui/react-slot"; 9import * as React from "react"; 10 11export type InputBaseContextProps = Pick< 12 InputBaseProps, 13 "autoFocus" | "disabled" 14> & { 15 controlRef: React.RefObject<HTMLElement | null>; 16 onFocusedChange: (focused: boolean) => void; 17}; 18 19const InputBaseContext = React.createContext<InputBaseContextProps>({ 20 autoFocus: false, 21 controlRef: { current: null }, 22 disabled: false, 23 onFocusedChange: () => {} 24}); 25 26function useInputBase() { 27 const context = React.useContext(InputBaseContext); 28 if (!context) { 29 throw new Error("useInputBase must be used within a <InputBase />."); 30 } 31 32 return context; 33} 34 35export interface InputBaseProps 36 extends React.ComponentProps<typeof Primitive.div> { 37 autoFocus?: boolean; 38 disabled?: boolean; 39 error?: boolean; 40} 41 42function InputBase({ 43 autoFocus, 44 disabled, 45 className, 46 onClick, 47 error, 48 ...props 49}: InputBaseProps) { 50 const [focused, setFocused] = React.useState(false); 51 const controlRef = React.useRef<HTMLElement>(null); 52 const handleClick = React.useCallback<React.MouseEventHandler<HTMLDivElement>>((event) => { 53 onClick?.(event); 54 if (event.defaultPrevented) return; 55 if (controlRef.current && event.currentTarget === event.target) { 56 controlRef.current.focus(); 57 } 58 }, [onClick]); 59 60 return ( 61 <InputBaseContext.Provider 62 value={{ 63 autoFocus, 64 controlRef, 65 disabled, 66 onFocusedChange: setFocused 67 }} 68 > 69 <Primitive.div 70 data-slot="input-base" 71 onClick={handleClick} 72 className={cn( 73 "border-input dark:bg-input/30 flex min-h-9 cursor-text items-center gap-2 rounded-lg border bg-transparent px-3 py-1 text-base shadow-2xs transition-[color,box-shadow] outline-hidden md:text-sm", 74 disabled && "pointer-events-none cursor-not-allowed opacity-50", 75 focused && "border-ring ring-ring/50 ring-[3px]", 76 error && 77 "ring-destructive/20 dark:ring-destructive/40 border-destructive", 78 className 79 )} 80 {...props} 81 /> 82 </InputBaseContext.Provider> 83 ); 84} 85 86function InputBaseFlexWrapper({ 87 className, 88 ...props 89}: React.ComponentProps<typeof Primitive.div>) { 90 return ( 91 <Primitive.div 92 data-slot="input-base-flex-wrapper" 93 className={cn("flex flex-1 flex-wrap", className)} 94 {...props} 95 /> 96 ); 97} 98 99function InputBaseControl({ 100 ref, 101 onFocus, 102 onBlur, 103 ...props 104}: React.ComponentProps<typeof Slot>) { 105 const { controlRef, autoFocus, disabled, onFocusedChange } = useInputBase(); 106 107 const composedRefs = useComposedRefs(controlRef, ref); 108 109 return ( 110 <Slot 111 data-slot="input-base-control" 112 ref={composedRefs} 113 autoFocus={autoFocus} 114 onFocus={composeEventHandlers(onFocus, () => onFocusedChange(true))} 115 onBlur={composeEventHandlers(onBlur, () => onFocusedChange(false))} 116 {...{ disabled }} 117 {...props} 118 /> 119 ); 120} 121 122export interface InputBaseAdornmentProps extends React.ComponentProps<"div"> { 123 asChild?: boolean; 124} 125 126function InputBaseAdornment({ 127 className, 128 asChild, 129 children, 130 ...props 131}: InputBaseAdornmentProps) { 132 const Comp = asChild ? Slot : typeof children === "string" ? "p" : "div"; 133 134 return ( 135 <Comp 136 data-slot="input-base-adornment" 137 className={cn( 138 "text-muted-foreground flex items-center [&_svg:not([class*='size-'])]:size-4", 139 "[&:not(:has(button))]:pointer-events-none", 140 className 141 )} 142 {...props} 143 > 144 {children} 145 </Comp> 146 ); 147} 148 149function InputBaseAdornmentButton({ 150 type = "button", 151 variant = "ghost", 152 size = "icon", 153 disabled: disabledProp, 154 className, 155 ...props 156}: React.ComponentProps<typeof Button>) { 157 const { disabled } = useInputBase(); 158 159 return ( 160 <Button 161 data-slot="input-base-adornment-button" 162 type={type} 163 variant={variant} 164 size={size} 165 disabled={disabled || disabledProp} 166 className={cn("size-6", className)} 167 {...props} 168 /> 169 ); 170} 171 172function InputBaseInput({ 173 className, 174 ...props 175}: React.ComponentProps<typeof Primitive.input>) { 176 return ( 177 <Primitive.input 178 data-slot="input-base-input" 179 className={cn( 180 "placeholder:text-muted-foreground file:text-foreground w-full flex-1 bg-transparent file:border-0 file:bg-transparent file:text-sm file:font-medium focus:outline-hidden disabled:pointer-events-none", 181 className 182 )} 183 {...props} 184 /> 185 ); 186} 187 188function InputBaseTextarea({ 189 className, 190 ...props 191}: React.ComponentProps<"textarea">) { 192 return ( 193 <textarea 194 data-slot="input-base-textarea" 195 className={cn( 196 "placeholder:text-muted-foreground min-h-16 flex-1 bg-transparent focus:outline-hidden disabled:pointer-events-none", 197 className 198 )} 199 {...props} 200 /> 201 ); 202} 203 204export { 205 InputBase, 206 InputBaseAdornment, 207 InputBaseAdornmentButton, 208 InputBaseControl, 209 InputBaseFlexWrapper, 210 InputBaseInput, 211 InputBaseTextarea, 212 useInputBase 213};