Skip to content

Commit

Permalink
refactor: textarea bordered
Browse files Browse the repository at this point in the history
Signed-off-by: Innei <i@innei.in>
  • Loading branch information
Innei committed Apr 4, 2024
1 parent d9fd460 commit e55a213
Show file tree
Hide file tree
Showing 7 changed files with 124 additions and 6 deletions.
1 change: 1 addition & 0 deletions src/app/(app)/thinking/page.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -80,6 +80,7 @@ const PostBox = () => {
return (
<form onSubmit={preventDefault} className="mb-8">
<TextArea
bordered={false}
wrapperClassName="h-[150px] bg-gray-200/50 dark:bg-zinc-800/50"
value={value}
placeholder="此刻在想什么?"
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -75,6 +75,7 @@ export const UniversalTextArea: Component = ({ className }) => {
const [sendComment] = useSendComment()
return (
<TextArea
bordered={false}
wrapperClassName={className}
ref={taRef}
defaultValue={value}
Expand Down
4 changes: 3 additions & 1 deletion src/components/modules/dashboard/comments/ReplyModal.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -132,7 +132,9 @@ export const ReplyModal = (props: { comment: CommentModel }) => {
<Label>回复 {author}</Label>
<div className="relative mt-4 h-[100px]">
<TextArea
className="cursor-not-allowed rounded-md bg-gray-100 dark:bg-neutral-900"
bordered={false}
className="cursor-not-allowed bg-gray-100 dark:bg-neutral-900"
rounded="md"
readOnly
value={text}
onCmdEnter={(e) => {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,8 @@ export const SummaryInput = () => {
return (
<SidebarSection label="摘要" className="relative">
<TextArea
className="rounded-md border p-2 focus-visible:border-accent"
className="p-2 focus-visible:border-accent"
rounded="md"
placeholder="摘要"
value={summary || ''}
onChange={(e) => {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -76,7 +76,8 @@ export const ImportMarkdownButton: FC<{
ref.current = el
setTextAreaEl(el)
}}
className="h-[calc(70vh-15rem)] max-h-[600px] w-[600px] max-w-full grow resize-none rounded-md border focus-visible:border-accent"
className="h-[calc(70vh-15rem)] max-h-[600px] w-[600px] max-w-full grow resize-none focus-visible:border-accent"
rounded="md"
/>

<DeclarativeModal.FooterAction>
Expand Down
80 changes: 80 additions & 0 deletions src/components/ui/form/FormTextarea.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,80 @@
import { memo, useCallback, useRef } from 'react'
import type { DetailedHTMLProps, FC, InputHTMLAttributes } from 'react'
import type { FormFieldBaseProps } from './types'

import { AutoResizeHeight } from '~/components/modules/shared/AutoResizeHeight'
import { clsxm } from '~/lib/helper'

import { TextArea } from '../input'
import { useFormConfig } from './FormContext'
import {
useAddField,
useCheckFieldStatus,
useFormErrorMessage,
useResetFieldStatus,
} from './hooks'

export const FormTextarea: FC<
Omit<
DetailedHTMLProps<
InputHTMLAttributes<HTMLTextAreaElement>,
HTMLTextAreaElement
>,
'name'
> &
FormFieldBaseProps<string>
> = memo(({ className, rules, onKeyDown, transform, name, ...rest }) => {
const { showErrorMessage } = useFormConfig()

const inputRef = useRef<HTMLTextAreaElement>(null)

const errorMessage = useFormErrorMessage(name)
useAddField({
rules: rules || [],
transform,
getEl: () => inputRef.current,
name,
})
const resetFieldStatus = useResetFieldStatus(name)

const handleKeyDown = useCallback(
(e: React.KeyboardEvent<HTMLTextAreaElement>) => {
if (onKeyDown) onKeyDown(e)
resetFieldStatus()
},
[onKeyDown, resetFieldStatus],
)

const validateField = useCheckFieldStatus(name)

return (
<>
<TextArea
name={name}
ref={inputRef}
className={clsxm(
!!errorMessage && 'ring-2 ring-red-400 dark:ring-orange-700',
'w-full',
className,
)}
type="text"
onKeyDown={handleKeyDown}
onBlur={(e) => {
validateField()
rest.onBlur?.(e)
}}
{...rest}
/>

{showErrorMessage && (
<AutoResizeHeight duration={0.2}>
<p className="text-left text-sm text-red-400 dark:text-orange-700">
{errorMessage}
</p>
</AutoResizeHeight>
)}
</>
)
})

FormTextarea.displayName = 'FormTextarea'
38 changes: 35 additions & 3 deletions src/components/ui/input/TextArea.tsx
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
'use client'

import { forwardRef, useCallback, useState } from 'react'
import clsx from 'clsx'
import { m, useMotionTemplate, useMotionValue } from 'framer-motion'
import type {
DetailedHTMLProps,
Expand All @@ -12,6 +13,15 @@ import { useIsMobile } from '~/atoms/hooks'
import { useInputComposition } from '~/hooks/common/use-input-composition'
import { clsxm } from '~/lib/helper'

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<
Expand All @@ -21,9 +31,18 @@ export const TextArea = forwardRef<
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, ...rest } = props
const {
className,
wrapperClassName,
children,
rounded = 'xl',
bordered = true,
...rest
} = props
const mouseX = useMotionValue(0)
const mouseY = useMotionValue(0)
const handleMouseMove = useCallback(
Expand All @@ -41,7 +60,8 @@ export const TextArea = forwardRef<
return (
<div
className={clsxm(
'group relative h-full rounded-xl border ring-0 ring-accent/20 duration-200 [--spotlight-color:oklch(var(--a)_/_0.12)]',
'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',
Expand All @@ -53,12 +73,24 @@ export const TextArea = forwardRef<
>
{!isMobile && (
<m.div
className="pointer-events-none absolute inset-0 z-0 rounded-xl opacity-0 transition-opacity duration-500 group-hover:opacity-100"
className={clsx(
'pointer-events-none absolute inset-0 z-0 opacity-0 transition-opacity duration-500 group-hover:opacity-100',
roundedMap[rounded],
)}
style={{ background }}
aria-hidden="true"
/>
)}

{bordered && (
<div
className={clsx(
'border-border pointer-events-none absolute inset-0 z-0 border',
roundedMap[rounded],
)}
aria-hidden="true"
/>
)}
<textarea
ref={ref}
className={clsxm(
Expand Down

0 comments on commit e55a213

Please sign in to comment.