feat: Add detailed documentation and improve styling for form components
This commit is contained in:
@@ -3,6 +3,27 @@ import { CheckboxProps } from '../types';
|
||||
import { forwardRef } from 'react';
|
||||
import { InputRef } from '@rc-component/input/lib/interface';
|
||||
|
||||
/**
|
||||
* Checkbox component built on top of RcCheckbox.
|
||||
*
|
||||
* Renders a checkbox with an optional label (uses `label` prop or `children`).
|
||||
* Default prop values: `status = 'default'`, `variant = 'outlined'`.
|
||||
*
|
||||
* The wrapper element will receive these classes:
|
||||
* - 'rc-checkbox-wrapper'
|
||||
* - `checkbox-status-{status}`
|
||||
* - `checkbox-variant-{variant}`
|
||||
* - 'rc-checkbox-wrapper-disabled' when `disabled` is true
|
||||
* and any additional classes passed via `className`.
|
||||
*
|
||||
* All remaining props are forwarded to the underlying RcCheckbox, which is rendered with `prefixCls="rc-checkbox"`.
|
||||
*
|
||||
* Note: a `ref` parameter is accepted by the forwardRef call but is not currently attached to the rendered input element.
|
||||
*
|
||||
* @param props - Checkbox props
|
||||
* @param ref - Forwarded ref (InputRef). Accepted but not applied to the DOM node in the current implementation.
|
||||
* @returns JSX.Element
|
||||
*/
|
||||
export const Checkbox = forwardRef<InputRef, CheckboxProps>((props, ref) => {
|
||||
const { label, status = 'default', variant = 'outlined', className, children, ...rest } = props;
|
||||
|
||||
@@ -21,11 +42,8 @@ export const Checkbox = forwardRef<InputRef, CheckboxProps>((props, ref) => {
|
||||
return (
|
||||
<label className={wrapperClass}>
|
||||
<span className="rc-checkbox-container">
|
||||
<RcCheckbox {...rest} prefixCls="rc-checkbox" />
|
||||
{/* HAPUS BARIS DI BAWAH INI */}
|
||||
{/* <span className="rc-checkbox-inner" /> */}
|
||||
<RcCheckbox ref={ref} {...rest} prefixCls="rc-checkbox" />
|
||||
</span>
|
||||
|
||||
{displayLabel && <span className="rc-checkbox-label-text">{displayLabel}</span>}
|
||||
</label>
|
||||
);
|
||||
|
||||
@@ -1,6 +1,14 @@
|
||||
import RcForm from '@rc-component/form';
|
||||
import { FormProps } from '../types';
|
||||
|
||||
/**
|
||||
* A form control component that wraps the underlying form library.
|
||||
*
|
||||
* @template Values - The type of values managed by the form. Defaults to `any`.
|
||||
* @param props - The form configuration properties.
|
||||
* @param props.children - The child elements to render within the form.
|
||||
* @returns A rendered form component with the provided children.
|
||||
*/
|
||||
export default function FormControl<Values = any>({ children, ...props }: FormProps<Values>) {
|
||||
return <RcForm {...props}>{children}</RcForm>;
|
||||
}
|
||||
|
||||
@@ -2,6 +2,36 @@ import React, { ReactElement } from 'react';
|
||||
import { Field } from '@rc-component/form';
|
||||
import { FormItemProps } from '../types';
|
||||
|
||||
/**
|
||||
* FormItem component that wraps form fields with validation, error/warning messaging, and styling.
|
||||
*
|
||||
* This component manages the rendering of a form field with associated label, validation rules,
|
||||
* and status-based styling. It integrates with a Field control system to handle form state,
|
||||
* errors, and warnings.
|
||||
*
|
||||
* @component
|
||||
* @example
|
||||
* ```tsx
|
||||
* <FormItem
|
||||
* name="username"
|
||||
* label="Username"
|
||||
* rules={[{ required: true, message: 'Username is required' }]}
|
||||
* >
|
||||
* <Input />
|
||||
* </FormItem>
|
||||
* ```
|
||||
*
|
||||
* @param {FormItemProps} props - The component props
|
||||
* @param {string} props.name - The field name for form control binding
|
||||
* @param {string} [props.label] - The label text to display above the input
|
||||
* @param {ReactNode} props.children - The form control element (e.g., Input, Textarea)
|
||||
* @param {Array<ValidationRule>} [props.rules] - Validation rules for the field
|
||||
* @param {string} [props.valuePropName='value'] - The prop name used to bind the field value
|
||||
* @param {any} [props.initialValue] - The initial value for the field
|
||||
* @param {'error' | 'warning' | 'normal'} [props.status] - Override the status appearance
|
||||
*
|
||||
* @returns {ReactElement} A form item container with label, control, and validation messages
|
||||
*/
|
||||
export default function FormItem(props: FormItemProps) {
|
||||
const { name, label, children, rules, valuePropName = 'value', initialValue, status: OverrideStatus } = props;
|
||||
|
||||
|
||||
@@ -9,6 +9,18 @@ import FormItem from './form-item.component';
|
||||
/**
|
||||
* Internal Form component using forwardRef to handle RcForm instance
|
||||
*/
|
||||
/**
|
||||
* React component that provides form context and forwards a ref to the underlying FormControl.
|
||||
*
|
||||
* @template Values - Shape of the form values (extends object). Defaults to any.
|
||||
* @param props - FormProps for the form, augmented with an optional forwarded ref.
|
||||
* @param props.ref - Optional forwarded ref passed to the underlying FormControl.
|
||||
* @returns A React element that sets up form context and delegates rendering/behavior to FormControl.
|
||||
*
|
||||
* @remarks
|
||||
* - Built using React.forwardRef and typed as a generic component so callers can infer form value types.
|
||||
* - Use to wrap form fields and access form state/actions via context.
|
||||
*/
|
||||
const FormProvider = React.forwardRef(FormControl) as <Values extends object = any>(
|
||||
props: FormProps<Values> & { ref?: React.ForwardedRef<any> },
|
||||
) => React.ReactElement;
|
||||
|
||||
@@ -1,9 +1,35 @@
|
||||
/**
|
||||
* A controlled input component for numeric values with increment/decrement handlers.
|
||||
*
|
||||
* Wraps the rc-component InputNumber with custom styling support and status indicators.
|
||||
* Features custom chevron-style up/down icons and support for multiple visual variants.
|
||||
*
|
||||
* @component
|
||||
* @example
|
||||
* ```tsx
|
||||
* const ref = useRef<HTMLInputElement>(null);
|
||||
* <InputNumber
|
||||
* ref={ref}
|
||||
* value={10}
|
||||
* onChange={(val) => console.log(val)}
|
||||
* status="success"
|
||||
* variant="outlined"
|
||||
* />
|
||||
* ```
|
||||
*
|
||||
* @param {InputNumberProps} props - The input number component props
|
||||
* @param {InputStatusType} [props.status] - The validation status ('default', 'success', 'error', etc.)
|
||||
* @param {string} [props.className] - Additional CSS classes to apply
|
||||
* @param {'outlined' | 'filled' | 'borderless'} [props.variant='outlined'] - The visual variant style
|
||||
* @param {React.Ref<HTMLInputElement>} ref - Ref to the underlying input element
|
||||
*
|
||||
* @returns {React.ReactElement} The rendered input number component
|
||||
*/
|
||||
import { forwardRef } from 'react';
|
||||
import RcInputNumber from '@rc-component/input-number';
|
||||
import { InputNumberProps, InputStatusType, VALID_INPUT_STATUSES } from '../types';
|
||||
|
||||
// Handler Icons (Chevron Modern)
|
||||
// Kita bungkus dengan span agar styling flexbox lebih mudah diatur nanti
|
||||
const UpIcon = () => (
|
||||
<span className="input-number-handler-up-inner flex items-center justify-center w-full h-full">
|
||||
<svg viewBox="0 0 16 16" width="1em" height="1em" fill="currentColor" className="w-2.5 h-2.5">
|
||||
|
||||
@@ -2,19 +2,36 @@ import { forwardRef } from 'react';
|
||||
import RcInput, { InputRef } from '@rc-component/input';
|
||||
import { InputProps, InputStatusType, VALID_INPUT_STATUSES } from '../types';
|
||||
|
||||
/**
|
||||
* Input component that wraps the RC Input library with custom status and variant support.
|
||||
*
|
||||
* @component
|
||||
* @param {InputProps} props - The input component props
|
||||
* @param {InputStatusType} [props.status] - The validation status of the input (validated against VALID_INPUT_STATUSES)
|
||||
* @param {string} [props.className] - Additional CSS classes to apply to the input
|
||||
* @param {'outlined' | 'filled'} [props.variant='outlined'] - The visual variant of the input
|
||||
* @param {boolean} [props.disabled] - Whether the input is disabled
|
||||
* @param {InputRef} ref - Reference to the underlying RC Input element
|
||||
* @returns {React.ReactElement} The rendered Input component with computed classes for status, variant, and disabled state
|
||||
*
|
||||
* @remarks
|
||||
* - Invalid status values default to 'default'
|
||||
* - The 'rc-input-disabled' class is automatically applied by RC Input library when disabled={true}
|
||||
* - The 'input-disabled' helper class is manually added for custom wrapper styling when needed
|
||||
*/
|
||||
export const Input = forwardRef<InputRef, InputProps>((props, ref) => {
|
||||
const { status, className, variant = 'outlined', disabled, ...restProps } = props;
|
||||
|
||||
// Validasi status agar aman
|
||||
// Determine current status, defaulting to 'default' if invalid
|
||||
const currentStatus: InputStatusType = status && VALID_INPUT_STATUSES.includes(status) ? status : 'default';
|
||||
|
||||
// Construct classname
|
||||
// Note: class 'rc-input-disabled' biasanya otomatis ditambahkan oleh library jika disabled={true}
|
||||
// Note: class 'rc-input-disabled' is added automatically by RC Input when disabled
|
||||
const computedClassName = [
|
||||
className,
|
||||
`input-status-${currentStatus}`,
|
||||
`input-variant-${variant}`,
|
||||
// Kita tambahkan class helper ini manual jika ingin styling spesifik wrapper saat disabled
|
||||
// Add custom disabled class if disabled
|
||||
disabled ? 'input-disabled' : '',
|
||||
]
|
||||
.filter(Boolean)
|
||||
|
||||
@@ -10,7 +10,7 @@
|
||||
font-weight: var(--form-label-font-weight);
|
||||
color: var(--form-label-color);
|
||||
line-height: 1;
|
||||
gap: 8px; /* Jarak antara kotak dan teks */
|
||||
gap: 8px; /* Distance between checkbox and label */
|
||||
transition: all 0.2s;
|
||||
}
|
||||
|
||||
@@ -30,7 +30,7 @@
|
||||
position: relative;
|
||||
line-height: 1;
|
||||
vertical-align: middle;
|
||||
top: -1px; /* Optikal alignment */
|
||||
top: -1px; /* Optically aligns the checkbox */
|
||||
}
|
||||
|
||||
.rc-checkbox-input {
|
||||
@@ -47,14 +47,14 @@
|
||||
top: 0;
|
||||
left: 0;
|
||||
display: inline-block;
|
||||
width: 16px; /* Sedikit diperbesar dari 14px agar proporsional dengan font 13px */
|
||||
width: 16px; /* Size of the checkbox */
|
||||
height: 16px;
|
||||
border-width: 1px;
|
||||
border-style: solid;
|
||||
border-radius: var(--radius-sm); /* Konsisten dengan shape global */
|
||||
border-radius: var(--radius-sm); /* Consistent with global shape */
|
||||
border-color: var(--input-border);
|
||||
background-color: var(--input-bg);
|
||||
/* Menggunakan durasi transisi standar kita 0.2s */
|
||||
/* Use standard 0.2s transition */
|
||||
transition: all 0.2s cubic-bezier(0.4, 0, 0.2, 1);
|
||||
}
|
||||
|
||||
@@ -68,7 +68,7 @@
|
||||
border-left: 0;
|
||||
transform: rotate(45deg) scale(0);
|
||||
opacity: 0;
|
||||
/* Position adjust untuk 16px box */
|
||||
/* Position adjust for 16px box */
|
||||
left: 4.5px;
|
||||
top: 1.5px;
|
||||
width: 5px;
|
||||
@@ -191,13 +191,13 @@
|
||||
/* --- Default Filled --- */
|
||||
.checkbox-variant-filled .rc-checkbox-inner {
|
||||
background-color: var(--color-gray-50);
|
||||
border-color: var(--input-border); /* Sedikit border agar tetap terlihat di bg putih */
|
||||
border-color: var(--input-border); /* Slightly border to remain visible on white background */
|
||||
}
|
||||
.checkbox-variant-filled:hover .rc-checkbox-inner {
|
||||
background-color: var(--color-gray-100);
|
||||
border-color: var(--input-border-hover);
|
||||
}
|
||||
/* Saat checked, filled beralih ke warna solid brand */
|
||||
/* Checked State for Filled */
|
||||
.checkbox-variant-filled.checkbox-status-default .rc-checkbox-checked .rc-checkbox-inner {
|
||||
background-color: var(--color-brand-500);
|
||||
border-color: var(--color-brand-500);
|
||||
@@ -259,9 +259,9 @@
|
||||
border-color: var(--color-info-500);
|
||||
}
|
||||
|
||||
/* Logic Focus untuk Filled (tetap konsisten dengan ring status) */
|
||||
/* Focus Ring for Filled Variant */
|
||||
.checkbox-variant-filled .rc-checkbox-input:focus-visible + .rc-checkbox-inner {
|
||||
/* Box shadow akan mengikuti warna status masing-masing dari block STATUS MATRIX di atas */
|
||||
/* Box shadow will follow the status color from the STATUS MATRIX block above */
|
||||
outline: none;
|
||||
}
|
||||
|
||||
|
||||
@@ -25,7 +25,7 @@
|
||||
.rc-form-item-required-mark {
|
||||
margin-left: 0.25rem;
|
||||
color: var(--color-error-500);
|
||||
font-family: SimSun, sans-serif; /* Standard font for asterisks agar vertical align bagus */
|
||||
font-family: SimSun, sans-serif; /* Standard font for asterisks agar vertical align */
|
||||
}
|
||||
|
||||
/* =========================
|
||||
@@ -35,7 +35,7 @@
|
||||
margin-top: var(--form-msg-margin-top);
|
||||
font-size: var(--form-msg-font-size);
|
||||
line-height: 1.4;
|
||||
min-height: 1.4em; /* Mencegah layout jumping jika error muncul/hilang */
|
||||
min-height: 1.4em; /* Reserve space even when empty to prevent layout shift */
|
||||
transition: color 0.2s;
|
||||
}
|
||||
|
||||
@@ -45,7 +45,7 @@
|
||||
|
||||
/* --- ERROR STATE --- */
|
||||
.rc-form-item.status-error .rc-form-item-label {
|
||||
color: var(--color-error-600); /* Label jadi merah saat error (opsional UI pattern) */
|
||||
color: var(--color-error-600); /* Darker shade for label on error */
|
||||
}
|
||||
.rc-form-item.status-error .rc-form-item-explain {
|
||||
color: var(--color-error-500);
|
||||
|
||||
@@ -19,7 +19,7 @@
|
||||
background-color: var(--input-bg);
|
||||
border: 1px solid transparent;
|
||||
|
||||
/* Transisi standar */
|
||||
/* Standard Transition */
|
||||
transition: all 0.2s cubic-bezier(0.4, 0, 0.2, 1);
|
||||
|
||||
margin: 0;
|
||||
@@ -35,10 +35,10 @@
|
||||
border: 0;
|
||||
border-radius: var(--input-radius);
|
||||
outline: 0;
|
||||
color: inherit; /* Mewarisi dari parent */
|
||||
color: inherit; /* Inherit from .rc-input-number */
|
||||
transition: all 0.2s linear;
|
||||
|
||||
/* Padding Kanan Wajib (Space untuk Actions) */
|
||||
/* Prevent text under action buttons */
|
||||
padding-right: var(--input-handler-width);
|
||||
}
|
||||
|
||||
@@ -74,7 +74,7 @@
|
||||
transition: margin-right 0.2s ease-in-out;
|
||||
}
|
||||
|
||||
/* Animation Trigger: Geser Suffix saat hover/focus agar tidak tertutup tombol action */
|
||||
/* Animation Trigger: On Hover/Focus, Suffix shifts left to accommodate action buttons */
|
||||
.rc-input-number:hover .rc-input-number-suffix,
|
||||
.rc-input-number-affix-wrapper:hover .rc-input-number-suffix,
|
||||
.rc-input-number-focused .rc-input-number-suffix,
|
||||
@@ -97,10 +97,10 @@
|
||||
width: var(--input-handler-width);
|
||||
height: 100%;
|
||||
|
||||
/* Menggunakan var input-bg agar konsisten (putih) */
|
||||
/* Using var input-bg for consistency (white) */
|
||||
background: var(--input-bg);
|
||||
|
||||
/* Default Border (akan di-override status) */
|
||||
/* Default Border (will be overridden by status) */
|
||||
border-left: 1px solid var(--input-border);
|
||||
border-radius: 0 var(--input-radius) var(--input-radius) 0;
|
||||
|
||||
@@ -138,10 +138,10 @@
|
||||
|
||||
.rc-input-number-action:hover {
|
||||
color: var(--color-brand-500);
|
||||
height: 60%; /* Efek hover button membesar dikit */
|
||||
height: 60%; /* Effect hover slightly reduces height */
|
||||
}
|
||||
|
||||
/* Border Bawah untuk Action UP */
|
||||
/* Border between Up/Down Buttons */
|
||||
.rc-input-number-action-up {
|
||||
border-bottom: 1px solid var(--input-border);
|
||||
}
|
||||
|
||||
@@ -3,15 +3,15 @@
|
||||
BASE RESET & SHARED
|
||||
========================================= */
|
||||
.rc-input {
|
||||
/* Wajib border-box agar padding tidak merusak lebar */
|
||||
/* Use box-sizing border-box for predictable sizing */
|
||||
box-sizing: border-box;
|
||||
|
||||
display: inline-block;
|
||||
width: 100%;
|
||||
|
||||
/* Menggunakan Variable Dimensi Input */
|
||||
/* Using variable dimensions */
|
||||
height: var(--input-height);
|
||||
padding: 0 var(--input-padding-x); /* Konsisten dengan 0.92rem */
|
||||
padding: 0 var(--input-padding-x); /* Consistent with 0.92rem */
|
||||
|
||||
font-size: var(--input-font-size);
|
||||
line-height: 1.5;
|
||||
@@ -21,7 +21,7 @@
|
||||
border: 1px solid transparent;
|
||||
border-radius: var(--input-radius);
|
||||
|
||||
/* Transisi standar */
|
||||
/* Standard Transition */
|
||||
transition: all 0.2s cubic-bezier(0.4, 0, 0.2, 1);
|
||||
outline: none;
|
||||
}
|
||||
@@ -43,7 +43,7 @@
|
||||
|
||||
/* =========================================
|
||||
CLEAR ICON
|
||||
Tombol (x) untuk reset value
|
||||
Button (x) to clear input content
|
||||
========================================= */
|
||||
.rc-input-clear-icon {
|
||||
/* Reset Button Styles */
|
||||
@@ -57,20 +57,20 @@
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
font-size: var(--text-sm); /* ~12px sesuai global */
|
||||
font-size: var(--text-sm); /* ~12px icon size */
|
||||
line-height: 1;
|
||||
cursor: pointer;
|
||||
|
||||
/* Colors & Transition */
|
||||
color: var(--color-gray-400); /* Warna default (abu muda) */
|
||||
color: var(--color-gray-400); /* Default gray color */
|
||||
transition: color 0.2s cubic-bezier(0.4, 0, 0.2, 1);
|
||||
|
||||
/* Visibility Control (Opacity lebih smooth dari display:none jika mau animasi) */
|
||||
/* Tapi untuk simplicity sesuai request, kita pakai logic display/visibility standar */
|
||||
/* Visibility Control ( Smooth appearance/disappearance could use opacity + pointer-events )
|
||||
/* visibility: hidden; */
|
||||
visibility: visible;
|
||||
}
|
||||
|
||||
/* Hover State: Lebih gelap agar user tahu bisa diklik */
|
||||
/* Hover State: Darker Gray */
|
||||
.rc-input-clear-icon:hover {
|
||||
color: var(--color-gray-500);
|
||||
}
|
||||
@@ -83,19 +83,16 @@
|
||||
/* Hidden State */
|
||||
.rc-input-clear-icon-hidden {
|
||||
display: none;
|
||||
/* Alternatif jika ingin layout tetap terjaga tapi invisible:
|
||||
/* Alternative approach to keep layout but invisible:
|
||||
visibility: hidden;
|
||||
pointer-events: none;
|
||||
*/
|
||||
}
|
||||
|
||||
/* Placement Helper:
|
||||
Biasanya clear icon muncul di dalam suffix atau menggantikan suffix.
|
||||
Jika dia berdiri sendiri sebagai sibling terakhir:
|
||||
*/
|
||||
/* Placement Helper: Margin to separate from input text */
|
||||
.rc-input-affix-wrapper .rc-input-clear-icon {
|
||||
margin-left: 0.5rem; /* ~8px spacing dari text */
|
||||
z-index: 2; /* Pastikan di atas layer lain */
|
||||
margin-left: 0.5rem; /* ~8px spacing from text */
|
||||
z-index: 2; /* Above input text */
|
||||
}
|
||||
|
||||
/* =========================================
|
||||
@@ -109,7 +106,7 @@
|
||||
align-items: center;
|
||||
width: 100%;
|
||||
|
||||
/* Menggunakan Variable Dimensi Input */
|
||||
/* Using variable dimensions */
|
||||
height: var(--input-height);
|
||||
padding: 0 var(--input-padding-x);
|
||||
|
||||
@@ -119,7 +116,7 @@
|
||||
transition: all 0.2s cubic-bezier(0.4, 0, 0.2, 1);
|
||||
}
|
||||
|
||||
/* Reset Input di dalam Wrapper */
|
||||
/* Reset Input inside Affix Wrapper */
|
||||
.rc-input-affix-wrapper .rc-input {
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
@@ -133,7 +130,7 @@
|
||||
|
||||
/* Prefix & Suffix Positioning */
|
||||
.rc-input-prefix {
|
||||
margin-right: 0.5rem; /* ~8px, hardcoded ok atau bisa buat var baru */
|
||||
margin-right: 0.5rem; /* ~8px, hardcoded */
|
||||
display: flex;
|
||||
align-items: center;
|
||||
flex: none;
|
||||
@@ -260,7 +257,7 @@
|
||||
background-color: var(--color-error-50);
|
||||
border-color: var(--color-error-500);
|
||||
}
|
||||
/* Saat focus, background jadi default input-bg (putih) */
|
||||
/* When focused, background becomes default input-bg (white) */
|
||||
.input-variant-filled.input-status-error:focus,
|
||||
.input-variant-filled.input-status-error.rc-input-affix-wrapper-focused {
|
||||
background-color: var(--input-bg);
|
||||
|
||||
@@ -1,7 +1,31 @@
|
||||
import React, { forwardRef } from 'react';
|
||||
import { forwardRef } from 'react';
|
||||
import RcTextArea, { TextAreaRef } from '@rc-component/textarea';
|
||||
import { InputStatusType, TextAreaProps, VALID_INPUT_STATUSES } from '../types';
|
||||
|
||||
/**
|
||||
* Forwarding React component that renders an RcTextArea with normalized status and variant styling.
|
||||
*
|
||||
* The component computes a CSS class string from the optional `className`, a `textarea-status-<status>` class
|
||||
* (falling back to 'default' when `status` is missing or not one of VALID_INPUT_STATUSES), and a
|
||||
* `textarea-variant-<variant>` class. All other props are passed through to the underlying RcTextArea.
|
||||
*
|
||||
* The component forwards a ref to the underlying RcTextArea element.
|
||||
*
|
||||
* @remarks
|
||||
* - `variant` defaults to `'outlined'`.
|
||||
* - `status` is validated against `VALID_INPUT_STATUSES`; if invalid or absent, `'default'` is used.
|
||||
* - Computed className shape: [className?, `textarea-status-${status}`, `textarea-variant-${variant}`].filter(Boolean).join(' ')
|
||||
*
|
||||
* @param props.status - Optional input status (validated against VALID_INPUT_STATUSES).
|
||||
* @param props.className - Optional additional class name(s) to apply.
|
||||
* @param props.variant - Visual variant of the textarea; defaults to `'outlined'`.
|
||||
* @param props.rest - All other props are forwarded to RcTextArea.
|
||||
*
|
||||
* @returns A React element: the wrapped RcTextArea with forwarded ref and computed classes.
|
||||
*
|
||||
* @example
|
||||
* <TextArea status="error" variant="filled" placeholder="Enter text" />
|
||||
*/
|
||||
export const TextArea = forwardRef<TextAreaRef, TextAreaProps>((props, ref) => {
|
||||
const { status, className, variant = 'outlined', ...restProps } = props;
|
||||
|
||||
|
||||
Reference in New Issue
Block a user