mirror of
https://github.com/yangshun/tech-interview-handbook.git
synced 2025-07-27 12:12:03 +08:00
[ui][textarea] add description prop
This commit is contained in:
@ -15,6 +15,9 @@ export default {
|
|||||||
autoComplete: {
|
autoComplete: {
|
||||||
control: 'text',
|
control: 'text',
|
||||||
},
|
},
|
||||||
|
description: {
|
||||||
|
control: 'text',
|
||||||
|
},
|
||||||
disabled: {
|
disabled: {
|
||||||
control: 'boolean',
|
control: 'boolean',
|
||||||
},
|
},
|
||||||
@ -108,6 +111,20 @@ export function Error() {
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export function Description() {
|
||||||
|
const [value, setValue] = useState('Some comment');
|
||||||
|
|
||||||
|
return (
|
||||||
|
<TextArea
|
||||||
|
description="Your message must be at least 6 characters"
|
||||||
|
errorMessage={value.length < 6 ? 'Your comment is too short' : undefined}
|
||||||
|
label="Leave a reply"
|
||||||
|
value={value}
|
||||||
|
onChange={setValue}
|
||||||
|
/>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
export function ReadOnly() {
|
export function ReadOnly() {
|
||||||
return (
|
return (
|
||||||
<TextArea
|
<TextArea
|
||||||
|
@ -27,6 +27,7 @@ export type TextAreaResize = 'both' | 'horizontal' | 'none' | 'vertical';
|
|||||||
|
|
||||||
type Props = Readonly<{
|
type Props = Readonly<{
|
||||||
defaultValue?: string;
|
defaultValue?: string;
|
||||||
|
description?: React.ReactNode;
|
||||||
errorMessage?: React.ReactNode;
|
errorMessage?: React.ReactNode;
|
||||||
id?: string;
|
id?: string;
|
||||||
isLabelHidden?: boolean;
|
isLabelHidden?: boolean;
|
||||||
@ -66,6 +67,7 @@ const resizeClasses: Record<TextAreaResize, string> = {
|
|||||||
function TextArea(
|
function TextArea(
|
||||||
{
|
{
|
||||||
defaultValue,
|
defaultValue,
|
||||||
|
description,
|
||||||
disabled,
|
disabled,
|
||||||
errorMessage,
|
errorMessage,
|
||||||
id: idParam,
|
id: idParam,
|
||||||
@ -82,7 +84,7 @@ function TextArea(
|
|||||||
const hasError = errorMessage != null;
|
const hasError = errorMessage != null;
|
||||||
const generatedId = useId();
|
const generatedId = useId();
|
||||||
const id = idParam ?? generatedId;
|
const id = idParam ?? generatedId;
|
||||||
const errorId = useId();
|
const messageId = useId();
|
||||||
const state: State = hasError ? 'error' : 'normal';
|
const state: State = hasError ? 'error' : 'normal';
|
||||||
|
|
||||||
return (
|
return (
|
||||||
@ -105,7 +107,9 @@ function TextArea(
|
|||||||
<div>
|
<div>
|
||||||
<textarea
|
<textarea
|
||||||
ref={ref}
|
ref={ref}
|
||||||
aria-describedby={hasError ? errorId : undefined}
|
aria-describedby={
|
||||||
|
hasError || description != null ? messageId : undefined
|
||||||
|
}
|
||||||
aria-invalid={hasError ? true : undefined}
|
aria-invalid={hasError ? true : undefined}
|
||||||
className={clsx(
|
className={clsx(
|
||||||
'block w-full rounded-md text-sm disabled:bg-slate-50 disabled:text-slate-500',
|
'block w-full rounded-md text-sm disabled:bg-slate-50 disabled:text-slate-500',
|
||||||
@ -128,9 +132,14 @@ function TextArea(
|
|||||||
{...props}
|
{...props}
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
{errorMessage && (
|
{(errorMessage ?? description) && (
|
||||||
<p className="text-danger-600 mt-2 text-sm" id={errorId}>
|
<p
|
||||||
{errorMessage}
|
className={clsx(
|
||||||
|
'mt-2 text-sm',
|
||||||
|
errorMessage ? 'text-danger-600' : 'text-slate-500',
|
||||||
|
)}
|
||||||
|
id={messageId}>
|
||||||
|
{errorMessage ?? description}
|
||||||
</p>
|
</p>
|
||||||
)}
|
)}
|
||||||
</div>
|
</div>
|
||||||
|
Reference in New Issue
Block a user