diff --git a/packages/ui/src/components/forms/checkbox/checkbox.component.tsx b/packages/ui/src/components/forms/checkbox/checkbox.component.tsx index 1a7a2b0..3368a10 100644 --- a/packages/ui/src/components/forms/checkbox/checkbox.component.tsx +++ b/packages/ui/src/components/forms/checkbox/checkbox.component.tsx @@ -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((props, ref) => { const { label, status = 'default', variant = 'outlined', className, children, ...rest } = props; @@ -21,11 +42,8 @@ export const Checkbox = forwardRef((props, ref) => { return ( ); diff --git a/packages/ui/src/components/forms/form-provider/form-control.component.tsx b/packages/ui/src/components/forms/form-provider/form-control.component.tsx index f83fa88..9f2d84f 100644 --- a/packages/ui/src/components/forms/form-provider/form-control.component.tsx +++ b/packages/ui/src/components/forms/form-provider/form-control.component.tsx @@ -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({ children, ...props }: FormProps) { return {children}; } diff --git a/packages/ui/src/components/forms/form-provider/form-item.component.tsx b/packages/ui/src/components/forms/form-provider/form-item.component.tsx index 3097030..e06ecb0 100644 --- a/packages/ui/src/components/forms/form-provider/form-item.component.tsx +++ b/packages/ui/src/components/forms/form-provider/form-item.component.tsx @@ -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 + * + * + * + * ``` + * + * @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} [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; diff --git a/packages/ui/src/components/forms/form-provider/index.tsx b/packages/ui/src/components/forms/form-provider/index.tsx index 6b9124d..5a9d50f 100644 --- a/packages/ui/src/components/forms/form-provider/index.tsx +++ b/packages/ui/src/components/forms/form-provider/index.tsx @@ -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 ( props: FormProps & { ref?: React.ForwardedRef }, ) => React.ReactElement; diff --git a/packages/ui/src/components/forms/input/input-number.component.tsx b/packages/ui/src/components/forms/input/input-number.component.tsx index 9a242b4..6ea694e 100644 --- a/packages/ui/src/components/forms/input/input-number.component.tsx +++ b/packages/ui/src/components/forms/input/input-number.component.tsx @@ -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(null); + * 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} 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 = () => ( diff --git a/packages/ui/src/components/forms/input/input.component.tsx b/packages/ui/src/components/forms/input/input.component.tsx index 68cd26c..3cffe68 100644 --- a/packages/ui/src/components/forms/input/input.component.tsx +++ b/packages/ui/src/components/forms/input/input.component.tsx @@ -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((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) diff --git a/packages/ui/src/components/forms/styles/checkbox.style.css b/packages/ui/src/components/forms/styles/checkbox.style.css index 789a539..d4daae1 100644 --- a/packages/ui/src/components/forms/styles/checkbox.style.css +++ b/packages/ui/src/components/forms/styles/checkbox.style.css @@ -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,18 +47,18 @@ 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); } - /* Checkmark (The L-shape) */ + /* Check mark (The L-shape) */ .rc-checkbox-inner:after { content: ' '; position: absolute; @@ -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; } diff --git a/packages/ui/src/components/forms/styles/form-item.style.css b/packages/ui/src/components/forms/styles/form-item.style.css index ed38617..651982d 100644 --- a/packages/ui/src/components/forms/styles/form-item.style.css +++ b/packages/ui/src/components/forms/styles/form-item.style.css @@ -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); diff --git a/packages/ui/src/components/forms/styles/input-number.style.css b/packages/ui/src/components/forms/styles/input-number.style.css index 4ed51e8..e84c6f4 100644 --- a/packages/ui/src/components/forms/styles/input-number.style.css +++ b/packages/ui/src/components/forms/styles/input-number.style.css @@ -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); } diff --git a/packages/ui/src/components/forms/styles/input.style.css b/packages/ui/src/components/forms/styles/input.style.css index 1e9d251..d915c11 100644 --- a/packages/ui/src/components/forms/styles/input.style.css +++ b/packages/ui/src/components/forms/styles/input.style.css @@ -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); diff --git a/packages/ui/src/components/forms/textarea/textarea.component.tsx b/packages/ui/src/components/forms/textarea/textarea.component.tsx index 1b0cc16..26f466f 100644 --- a/packages/ui/src/components/forms/textarea/textarea.component.tsx +++ b/packages/ui/src/components/forms/textarea/textarea.component.tsx @@ -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-` class + * (falling back to 'default' when `status` is missing or not one of VALID_INPUT_STATUSES), and a + * `textarea-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 + * + */ export const TextArea = forwardRef((props, ref) => { const { status, className, variant = 'outlined', ...restProps } = props;