Skip to content

Commit

Permalink
feat: re-design <Input /> (#67)
Browse files Browse the repository at this point in the history
* feat: resign `<Input />`

Signed-off-by: Innei <[email protected]>

* fix: unify styles and prevent `esc` to trigger input event

Signed-off-by: Innei <[email protected]>

* fix: adjust button height

Signed-off-by: Innei <[email protected]>

* fix: unify button style

Signed-off-by: Innei <[email protected]>

* fix: popover button

Signed-off-by: Innei <[email protected]>

---------

Signed-off-by: Innei <[email protected]>
  • Loading branch information
Innei authored Jun 17, 2024
1 parent bf39825 commit f54df88
Show file tree
Hide file tree
Showing 21 changed files with 372 additions and 105 deletions.
2 changes: 1 addition & 1 deletion components.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"$schema": "https://ui.shadcn.com/schema.json",
"style": "default",
"style": "new-york",
"rsc": false,
"tsx": true,
"tailwind": {
Expand Down
2 changes: 1 addition & 1 deletion src/renderer/index.html
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,7 @@
<div id="root">
<!-- Skeleton -->
<div class="h-full w-full flex">
<div class="w-64 h-full"></div>
<div class="w-64 shrink-0 h-full"></div>
<div class="grow w-full h-full bg-background"></div>
</div>
</div>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -205,7 +205,7 @@ export const Autocomplete = forwardRef<HTMLInputElement, AutocompleteProps>(
exit={{ opacity: 0, y: 10 }}
className={clsx(
"pointer-events-auto max-h-48 grow",
"overflow-auto rounded-md border border-zinc-200 bg-zinc-50/90 backdrop-blur dark:border-neutral-800 dark:bg-neutral-900/90",
"overflow-auto rounded-md border border-zinc-200 bg-popover text-popover-foreground",
)}
// FIXME: https://github.com/radix-ui/primitives/issues/2125
onWheel={stopPropagation}
Expand All @@ -220,7 +220,7 @@ export const Autocomplete = forwardRef<HTMLInputElement, AutocompleteProps>(
}
return (
<li
className="cursor-default px-4 py-2 text-sm hover:bg-zinc-200 dark:hover:bg-neutral-800"
className="cursor-default px-4 py-1.5 text-sm hover:bg-theme-item-hover dark:hover:bg-neutral-800"
key={suggestion.value}
onMouseDown={handleClick}
onClick={handleClick}
Expand Down
3 changes: 1 addition & 2 deletions src/renderer/src/components/ui/button/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -97,7 +97,6 @@ export const MotionButtonBase = React.forwardRef<
layout="size"
initial
whileFocus={{ scale: 1.02 }}
whileHover={{ scale: 1.02 }}
whileTap={{ scale: 0.95 }}
{...rest}
ref={ref}
Expand Down Expand Up @@ -145,7 +144,7 @@ export const StyledButton = React.forwardRef<
<LoadingCircle size="small" className="mr-2" />
</m.span>
)}
<m.span>{props.children}</m.span>
<m.span className={cn("center", className)}>{props.children}</m.span>
</m.span>
</MotionButtonBase>
)
Expand Down
2 changes: 1 addition & 1 deletion src/renderer/src/components/ui/button/variants.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,7 @@ export const buttonVariants = cva(
},
)
export const styledButtonVariant = cva(
"inline-flex select-none disabled:cursor-not-allowed cursor-default items-center gap-2 justify-center rounded-lg py-2 px-3 text-sm outline-offset-2 transition active:transition-none",
"inline-flex select-none disabled:cursor-not-allowed cursor-default items-center gap-2 justify-center rounded-lg py-1.5 px-3 text-sm outline-offset-2 transition active:transition-none",
{
compoundVariants: [
{
Expand Down
19 changes: 6 additions & 13 deletions src/renderer/src/components/ui/form.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -3,16 +3,8 @@ import { Slot } from "@radix-ui/react-slot"
import { Label } from "@renderer/components/ui/label"
import { cn } from "@renderer/lib/utils"
import * as React from "react"
import type {
ControllerProps,
FieldPath,
FieldValues,
} from "react-hook-form"
import {
Controller,
FormProvider,
useFormContext,
} from "react-hook-form"
import type { ControllerProps, FieldPath, FieldValues } from "react-hook-form"
import { Controller, FormProvider, useFormContext } from "react-hook-form"

const Form = FormProvider

Expand Down Expand Up @@ -92,7 +84,7 @@ const FormLabel = React.forwardRef<
return (
<Label
ref={ref}
className={cn(error && "text-destructive", className)}
className={cn(error && "text-destructive", "font-semibold", className)}
htmlFor={formItemId}
{...props}
/>
Expand All @@ -104,7 +96,8 @@ const FormControl = React.forwardRef<
React.ElementRef<typeof Slot>,
React.ComponentPropsWithoutRef<typeof Slot>
>(({ ...props }, ref) => {
const { error, formItemId, formDescriptionId, formMessageId } = useFormField()
const { error, formItemId, formDescriptionId, formMessageId } =
useFormField()

return (
<Slot
Expand Down Expand Up @@ -132,7 +125,7 @@ const FormDescription = React.forwardRef<
<p
ref={ref}
id={formDescriptionId}
className={cn("text-sm text-muted-foreground", className)}
className={cn("text-xs text-muted-foreground", className)}
{...props}
/>
)
Expand Down
21 changes: 0 additions & 21 deletions src/renderer/src/components/ui/input.tsx

This file was deleted.

36 changes: 36 additions & 0 deletions src/renderer/src/components/ui/input/Input.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
import { useInputComposition } from "@renderer/hooks/common/use-input-composition"
import { cn } from "@renderer/lib/utils"
import type { DetailedHTMLProps, InputHTMLAttributes } from "react"
import { forwardRef } from "react"

// This composition handler is not perfect
// @see https://foxact.skk.moe/use-composition-input
export const Input = forwardRef<
HTMLInputElement,
Omit<
DetailedHTMLProps<InputHTMLAttributes<HTMLInputElement>, HTMLInputElement>,
"ref"
>
>(({ className, ...props }, ref) => {
const inputProps = useInputComposition(props)
return (
<input
ref={ref}
className={cn(
"min-w-0 flex-auto appearance-none rounded-lg text-sm",
"bg-background px-3 py-[calc(theme(spacing.2)-1px)] placeholder:text-zinc-400 dark:bg-zinc-700/[0.15]",
"ring-theme-accent/20 duration-200 focus:border-theme-accent/80 focus:outline-none focus:ring-2",
"border border-border",
"dark:text-zinc-200 dark:placeholder:text-zinc-500",
props.type === "password" ?
"font-mono placeholder:font-sans" :
"font-sans",
"w-full",
className,
)}
{...props}
{...inputProps}
/>
)
})
Input.displayName = "Input"
114 changes: 114 additions & 0 deletions src/renderer/src/components/ui/input/TextArea.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,114 @@
"use client"

import { useInputComposition } from "@renderer/hooks/common/use-input-composition"
import { cn } from "@renderer/lib/utils"
import clsx from "clsx"
import { useMotionValue } from "framer-motion"
import type {
DetailedHTMLProps,
PropsWithChildren,
TextareaHTMLAttributes,
} from "react"
import { forwardRef, useCallback, useState } from "react"

const roundedMap = {
"sm": "rounded-sm",
"md": "rounded-md",
"lg": "rounded-lg",
"xl": "rounded-xl",
"2xl": "rounded-2xl",
"3xl": "rounded-3xl",
"default": "rounded",
}
export const TextArea = forwardRef<
HTMLTextAreaElement,
DetailedHTMLProps<
TextareaHTMLAttributes<HTMLTextAreaElement>,
HTMLTextAreaElement
> &
PropsWithChildren<{
wrapperClassName?: string
onCmdEnter?: (e: React.KeyboardEvent<HTMLTextAreaElement>) => void
rounded?: "sm" | "md" | "lg" | "xl" | "2xl" | "3xl" | "default"
bordered?: boolean
}>
>((props, ref) => {
const {
className,
wrapperClassName,
children,
rounded = "xl",
bordered = true,
onCmdEnter,
...rest
} = props
const mouseX = useMotionValue(0)
const mouseY = useMotionValue(0)
const handleMouseMove = useCallback(
({ clientX, clientY, currentTarget }: React.MouseEvent) => {
const bounds = currentTarget.getBoundingClientRect()
mouseX.set(clientX - bounds.left)
mouseY.set(clientY - bounds.top)
},
[mouseX, mouseY],
)

const inputProps = useInputComposition(props)
const [isFocus, setIsFocus] = useState(false)
return (
<div
className={cn(
"group relative h-full border ring-0 ring-accent/20 duration-200 [--spotlight-color:oklch(var(--a)_/_0.12)]",
roundedMap[rounded],

"border-transparent",
isFocus && "border-accent/80 ring-2",

"dark:text-zinc-200 dark:placeholder:text-zinc-500",
wrapperClassName,
)}
onMouseMove={handleMouseMove}
>
{bordered && (
<div
className={clsx(
"border-border pointer-events-none absolute inset-0 z-0 border",
roundedMap[rounded],
)}
aria-hidden="true"
/>
)}
<textarea
ref={ref}
className={cn(
"size-full resize-none bg-transparent",
"overflow-auto px-3 py-4",
"!outline-none",
"text-neutral-900/80 dark:text-slate-100/80",
roundedMap[rounded],
className,
)}
{...rest}
onFocus={(e) => {
setIsFocus(true)
rest.onFocus?.(e)
}}
onBlur={(e) => {
setIsFocus(false)
rest.onBlur?.(e)
}}
{...inputProps}
onKeyDown={(e) => {
if (e.key === "Enter" && (e.metaKey || e.ctrlKey)) {
onCmdEnter?.(e)
}
rest.onKeyDown?.(e)
inputProps.onKeyDown?.(e)
}}
/>

{children}
</div>
)
})
TextArea.displayName = "TextArea"
2 changes: 2 additions & 0 deletions src/renderer/src/components/ui/input/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
export * from "./Input"
export * from "./TextArea"
15 changes: 8 additions & 7 deletions src/renderer/src/components/ui/select.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,9 @@ const SelectTrigger = React.forwardRef<
<SelectPrimitive.Trigger
ref={ref}
className={cn(
"flex h-10 w-full items-center justify-between rounded-md border border-input bg-background px-3 py-2 text-sm ring-offset-background placeholder:text-muted-foreground focus:outline-none focus:ring-2 focus:ring-ring focus:ring-offset-2 disabled:cursor-not-allowed disabled:opacity-50 [&>span]:line-clamp-1",
"flex h-9 w-full items-center justify-between whitespace-nowrap rounded-md bg-transparent px-3 py-2 text-sm placeholder:text-muted-foreground disabled:cursor-not-allowed disabled:opacity-50 [&>span]:line-clamp-1",
"ring-theme-accent/20 duration-200 focus:border-theme-accent/80 focus:outline-none focus:ring-2",
"border border-border",
className,
)}
{...props}
Expand All @@ -41,7 +43,7 @@ const SelectScrollUpButton = React.forwardRef<
)}
{...props}
>
<ChevronUp className="size-4" />
<ChevronUp />
</SelectPrimitive.ScrollUpButton>
))
SelectScrollUpButton.displayName = SelectPrimitive.ScrollUpButton.displayName
Expand All @@ -58,7 +60,7 @@ const SelectScrollDownButton = React.forwardRef<
)}
{...props}
>
<ChevronDown className="size-4" />
<ChevronDown />
</SelectPrimitive.ScrollDownButton>
))
SelectScrollDownButton.displayName =
Expand Down Expand Up @@ -102,7 +104,7 @@ const SelectLabel = React.forwardRef<
>(({ className, ...props }, ref) => (
<SelectPrimitive.Label
ref={ref}
className={cn("py-1.5 pl-8 pr-2 text-sm font-semibold", className)}
className={cn("px-2 py-1.5 text-sm font-semibold", className)}
{...props}
/>
))
Expand All @@ -115,17 +117,16 @@ const SelectItem = React.forwardRef<
<SelectPrimitive.Item
ref={ref}
className={cn(
"relative flex w-full cursor-default select-none items-center rounded-sm py-1.5 pl-8 pr-2 text-sm outline-none focus:bg-accent focus:text-accent-foreground data-[disabled]:pointer-events-none data-[disabled]:opacity-50",
"relative flex w-full cursor-default select-none items-center rounded-sm py-1.5 pl-2 pr-8 text-sm outline-none focus:bg-theme-item-active focus:text-accent-foreground data-[disabled]:pointer-events-none data-[disabled]:opacity-50",
className,
)}
{...props}
>
<span className="absolute left-2 flex size-3.5 items-center justify-center">
<span className="absolute right-2 flex size-3.5 items-center justify-center">
<SelectPrimitive.ItemIndicator>
<Check className="size-4" />
</SelectPrimitive.ItemIndicator>
</span>

<SelectPrimitive.ItemText>{children}</SelectPrimitive.ItemText>
</SelectPrimitive.Item>
))
Expand Down
Loading

0 comments on commit f54df88

Please sign in to comment.