feat: Refactor example page and showcase components

- Updated ExamplePage to use a single Showcase component instead of separate InputShowCase and FormShowcase components.
- Added CheckboxShowcase, FormShowcase, and InputShowCase components to the showcase directory.
- Implemented Checkbox component with various states and styles.
- Enhanced InputShowCase to demonstrate different input types and states.
- Integrated new styles for checkbox variants and states.
- Updated package dependencies to include @rc-component/checkbox.
This commit is contained in:
Firman Ramdhani
2026-01-28 11:53:03 +07:00
parent c021df8012
commit b52e458a9d
14 changed files with 557 additions and 19 deletions
+1
View File
@@ -12,6 +12,7 @@
"test:watch": "vitest --watch"
},
"dependencies": {
"@rc-component/checkbox": "^1.0.1",
"@rc-component/form": "^1.6.2",
"@rc-component/input": "^1.1.2",
"@rc-component/input-number": "^1.6.2",
@@ -0,0 +1,34 @@
import RcCheckbox from '@rc-component/checkbox';
import { CheckboxProps } from '../types';
import { forwardRef } from 'react';
import { InputRef } from '@rc-component/input/lib/interface';
export const Checkbox = forwardRef<InputRef, CheckboxProps>((props, ref) => {
const { label, status = 'default', variant = 'outlined', className, children, ...rest } = props;
const displayLabel = label || children;
const wrapperClass = [
'rc-checkbox-wrapper',
`checkbox-status-${status}`,
`checkbox-variant-${variant}`,
rest.disabled ? 'rc-checkbox-wrapper-disabled' : '',
className,
]
.filter(Boolean)
.join(' ');
return (
<label className={wrapperClass}>
<span className="rc-checkbox-container">
<RcCheckbox {...rest} prefixCls="rc-checkbox" />
{/* HAPUS BARIS DI BAWAH INI */}
{/* <span className="rc-checkbox-inner" /> */}
</span>
{displayLabel && <span className="rc-checkbox-label-text">{displayLabel}</span>}
</label>
);
});
Checkbox.displayName = 'Checkbox';
@@ -7,3 +7,4 @@ export * from './input/input-currency.component';
export * from './input/input-number.component';
export * from './textarea/textarea.component';
export * from './checkbox/checkbox.component';
@@ -1,5 +1,5 @@
import { forwardRef } from 'react';
import RcInput, { InputRef, InputProps as RcInputProps } from '@rc-component/input';
import RcInput, { InputRef } from '@rc-component/input';
import { InputProps, InputStatusType, VALID_INPUT_STATUSES } from '../types';
export const Input = forwardRef<InputRef, InputProps>((props, ref) => {
@@ -0,0 +1,294 @@
@layer components {
/* =========================================
BASE WRAPPER & LABEL
========================================= */
.rc-checkbox-wrapper {
display: inline-flex;
align-items: center;
cursor: pointer;
font-size: var(--form-label-font-size);
font-weight: var(--form-label-font-weight);
color: var(--form-label-color);
line-height: 1;
gap: 8px; /* Jarak antara kotak dan teks */
transition: all 0.2s;
}
.rc-checkbox-wrapper-disabled {
cursor: not-allowed;
color: var(--disabled-text);
}
/* =========================================
CORE CHECKBOX STRUCTURE
========================================= */
.rc-checkbox {
white-space: nowrap;
cursor: pointer;
outline: none;
display: inline-block;
position: relative;
line-height: 1;
vertical-align: middle;
top: -1px; /* Optikal alignment */
}
.rc-checkbox-input {
position: absolute;
inset: 0;
z-index: 9999;
cursor: pointer;
opacity: 0;
margin: 0;
}
.rc-checkbox-inner {
position: relative;
top: 0;
left: 0;
display: inline-block;
width: 16px; /* Sedikit diperbesar dari 14px agar proporsional dengan font 13px */
height: 16px;
border-width: 1px;
border-style: solid;
border-radius: var(--radius-sm); /* Konsisten dengan shape global */
border-color: var(--input-border);
background-color: var(--input-bg);
/* Menggunakan durasi transisi standar kita 0.2s */
transition: all 0.2s cubic-bezier(0.4, 0, 0.2, 1);
}
/* Checkmark (The L-shape) */
.rc-checkbox-inner:after {
content: ' ';
position: absolute;
display: table;
border: 2px solid #fff;
border-top: 0;
border-left: 0;
transform: rotate(45deg) scale(0);
opacity: 0;
/* Position adjust untuk 16px box */
left: 4.5px;
top: 1.5px;
width: 5px;
height: 9px;
transition:
all 0.1s cubic-bezier(0.71, -0.46, 0.88, 0.6),
opacity 0.1s;
}
/* =========================================
INTERACTION STATES
========================================= */
/* Hover */
.rc-checkbox:hover .rc-checkbox-inner,
.rc-checkbox-wrapper:hover .rc-checkbox-inner {
border-color: var(--input-border-hover);
}
/* Focus Ring */
.rc-checkbox-input:focus-visible + .rc-checkbox-inner {
border-color: var(--focus-border-color);
box-shadow: 0 0 0 3px var(--focus-ring-color);
}
/* Checked State */
.rc-checkbox-checked .rc-checkbox-inner {
border-color: var(--color-brand-500);
background-color: var(--color-brand-500);
}
.rc-checkbox-checked .rc-checkbox-inner:after {
transform: rotate(45deg) scale(1);
opacity: 1;
transition: all 0.2s cubic-bezier(0.12, 0.4, 0.29, 1.46) 0.1s;
}
/* =========================================
STATUS MATRIX (Error, Warning, Success, Info)
========================================= */
/* --- DEFAULT --- */
.checkbox-status-default .rc-checkbox-inner {
border-color: var(--input-border);
}
.checkbox-status-default:hover .rc-checkbox-inner {
border-color: var(--input-border-hover);
}
.checkbox-status-default .rc-checkbox-checked .rc-checkbox-inner {
background-color: var(--color-brand-500);
border-color: var(--color-brand-500);
}
.checkbox-status-default .rc-checkbox-input:focus-visible + .rc-checkbox-inner {
box-shadow: 0 0 0 3px var(--color-brand-100);
}
/* --- ERROR --- */
.checkbox-status-error .rc-checkbox-inner {
border-color: var(--color-error-300);
}
.checkbox-status-error:hover .rc-checkbox-inner {
border-color: var(--color-error-500);
}
.checkbox-status-error .rc-checkbox-checked .rc-checkbox-inner {
background-color: var(--color-error-500);
border-color: var(--color-error-500);
}
.checkbox-status-error .rc-checkbox-input:focus-visible + .rc-checkbox-inner {
box-shadow: 0 0 0 3px var(--color-error-100);
}
/* --- WARNING --- */
.checkbox-status-warning .rc-checkbox-inner {
border-color: var(--color-warning-300);
}
.checkbox-status-warning:hover .rc-checkbox-inner {
border-color: var(--color-warning-500);
}
.checkbox-status-warning .rc-checkbox-checked .rc-checkbox-inner {
background-color: var(--color-warning-500);
border-color: var(--color-warning-500);
}
.checkbox-status-warning .rc-checkbox-input:focus-visible + .rc-checkbox-inner {
box-shadow: 0 0 0 3px var(--color-warning-100);
}
/* --- SUCCESS --- */
.checkbox-status-success .rc-checkbox-inner {
border-color: var(--color-success-300);
}
.checkbox-status-success:hover .rc-checkbox-inner {
border-color: var(--color-success-500);
}
.checkbox-status-success .rc-checkbox-checked .rc-checkbox-inner {
background-color: var(--color-success-500);
border-color: var(--color-success-500);
}
.checkbox-status-success .rc-checkbox-input:focus-visible + .rc-checkbox-inner {
box-shadow: 0 0 0 3px var(--color-success-100);
}
/* --- INFO --- */
.checkbox-status-info .rc-checkbox-inner {
border-color: var(--color-info-300);
}
.checkbox-status-info:hover .rc-checkbox-inner {
border-color: var(--color-info-500);
}
.checkbox-status-info .rc-checkbox-checked .rc-checkbox-inner {
background-color: var(--color-info-500);
border-color: var(--color-info-500);
}
.checkbox-status-info .rc-checkbox-input:focus-visible + .rc-checkbox-inner {
box-shadow: 0 0 0 3px var(--color-info-100);
}
/* =========================================
VARIANT: FILLED
========================================= */
/* --- 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 */
}
.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 */
.checkbox-variant-filled.checkbox-status-default .rc-checkbox-checked .rc-checkbox-inner {
background-color: var(--color-brand-500);
border-color: var(--color-brand-500);
}
/* --- Error Filled --- */
.checkbox-variant-filled.checkbox-status-error .rc-checkbox-inner {
background-color: var(--color-error-50);
border-color: var(--color-error-300);
}
.checkbox-variant-filled.checkbox-status-error:hover .rc-checkbox-inner {
background-color: var(--color-error-100);
border-color: var(--color-error-500);
}
.checkbox-variant-filled.checkbox-status-error .rc-checkbox-checked .rc-checkbox-inner {
background-color: var(--color-error-500);
border-color: var(--color-error-500);
}
/* --- Warning Filled --- */
.checkbox-variant-filled.checkbox-status-warning .rc-checkbox-inner {
background-color: var(--color-warning-50);
border-color: var(--color-warning-300);
}
.checkbox-variant-filled.checkbox-status-warning:hover .rc-checkbox-inner {
background-color: var(--color-warning-100);
border-color: var(--color-warning-500);
}
.checkbox-variant-filled.checkbox-status-warning .rc-checkbox-checked .rc-checkbox-inner {
background-color: var(--color-warning-500);
border-color: var(--color-warning-500);
}
/* --- Success Filled --- */
.checkbox-variant-filled.checkbox-status-success .rc-checkbox-inner {
background-color: var(--color-success-50);
border-color: var(--color-success-300);
}
.checkbox-variant-filled.checkbox-status-success:hover .rc-checkbox-inner {
background-color: var(--color-success-100);
border-color: var(--color-success-500);
}
.checkbox-variant-filled.checkbox-status-success .rc-checkbox-checked .rc-checkbox-inner {
background-color: var(--color-success-500);
border-color: var(--color-success-500);
}
/* --- Info Filled --- */
.checkbox-variant-filled.checkbox-status-info .rc-checkbox-inner {
background-color: var(--color-info-50);
border-color: var(--color-info-300);
}
.checkbox-variant-filled.checkbox-status-info:hover .rc-checkbox-inner {
background-color: var(--color-info-100);
border-color: var(--color-info-500);
}
.checkbox-variant-filled.checkbox-status-info .rc-checkbox-checked .rc-checkbox-inner {
background-color: var(--color-info-500);
border-color: var(--color-info-500);
}
/* Logic Focus untuk Filled (tetap konsisten dengan ring status) */
.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 */
outline: none;
}
/* =========================================
DISABLED STATE
========================================= */
.rc-checkbox-disabled {
cursor: not-allowed;
}
.rc-checkbox-disabled .rc-checkbox-inner {
background-color: var(--disabled-bg) !important;
border-color: var(--disabled-border) !important;
}
.rc-checkbox-disabled.rc-checkbox-checked .rc-checkbox-inner:after {
border-color: var(--disabled-text);
}
.rc-checkbox-disabled .rc-checkbox-input {
cursor: not-allowed;
}
/* Print Support */
@media print {
.rc-checkbox-checked .rc-checkbox-inner {
box-shadow: inset 0 0 0 16px var(--color-brand-500);
}
}
}
@@ -2,3 +2,4 @@
@import './input.style.css';
@import './input-number.style.css';
@import './textarea.style.css';
@import './checkbox.style.css';
@@ -6,6 +6,8 @@ import { InputProps as RcInputProps } from '@rc-component/input';
import { TextAreaProps as RcTextAreaProps } from '@rc-component/textarea';
import { InputNumberProps as RcInputNumberProps } from '@rc-component/input-number';
import { CheckboxProps as RcCheckboxProps } from '@rc-component/checkbox';
/**
* Define possible input statuses
*/
@@ -35,7 +37,7 @@ export interface FormItemProps {
/**
* Define base component props
*/
interface BaseComponentProps {
interface BaseFormItemComponentProps {
status?: InputStatusType;
variant?: 'outlined' | 'filled';
}
@@ -43,7 +45,7 @@ interface BaseComponentProps {
/**
* Define specific component props
*/
export interface InputProps extends RcInputProps, BaseComponentProps {}
export interface InputProps extends RcInputProps, BaseFormItemComponentProps {}
export interface InputPasswordProps extends InputProps {
visibilityToggle?: boolean; // Default: true
}
@@ -51,8 +53,8 @@ export interface InputPasswordProps extends InputProps {
/**
* Define InputNumber and InputCurrency props
*/
export interface InputNumberProps extends RcInputNumberProps, BaseComponentProps {}
export interface InputCurrencyProps extends InputNumberProps, BaseComponentProps {
export interface InputNumberProps extends RcInputNumberProps, BaseFormItemComponentProps {}
export interface InputCurrencyProps extends InputNumberProps, BaseFormItemComponentProps {
prefix?: string; // Optional: Custom prefix, default 'Rp '
decimalSeparator?: ',' | '.';
decimalScale?: number; // optional
@@ -61,4 +63,11 @@ export interface InputCurrencyProps extends InputNumberProps, BaseComponentProps
/**
* Define TextArea props
*/
export interface TextAreaProps extends RcTextAreaProps, BaseComponentProps {}
export interface TextAreaProps extends RcTextAreaProps, BaseFormItemComponentProps {}
/**
* Define Checkbox props
*/
export interface CheckboxProps extends RcCheckboxProps, BaseFormItemComponentProps {
label?: ReactNode;
}
+32 -1
View File
@@ -62,26 +62,57 @@
--color-gray-800: #1f2937;
--color-gray-900: #111827;
/* Semantics */
/* -------------------------------
COLORS: SEMANTICS (COMPLETED)
------------------------------- */
/* Error (Red) */
--color-error-50: #fef2f2;
--color-error-100: #fee2e2;
--color-error-200: #fecaca;
--color-error-300: #fca5a5;
--color-error-400: #f87171;
--color-error-500: #ef4444;
--color-error-600: #dc2626;
--color-error-700: #b91c1c;
--color-error-800: #991b1b;
--color-error-900: #7f1d1d;
/* Warning (Amber/Orange) */
--color-warning-50: #fffbeb;
--color-warning-100: #fef3c7;
--color-warning-200: #fde68a;
--color-warning-300: #fcd34d;
--color-warning-400: #fbbf24;
--color-warning-500: #f59e0b;
--color-warning-600: #d97706;
--color-warning-700: #b45309;
--color-warning-800: #92400e;
--color-warning-900: #78350f;
/* Success (Green) */
--color-success-50: #f0fdf4;
--color-success-100: #dcfce7;
--color-success-200: #bbf7d0;
--color-success-300: #86efac;
--color-success-400: #4ade80;
--color-success-500: #22c55e;
--color-success-600: #16a34a;
--color-success-700: #15803d;
--color-success-800: #166534;
--color-success-900: #14532d;
/* Info (Blue/Sky) */
--color-info-50: #f0f9ff;
--color-info-100: #e0f2fe;
--color-info-200: #bae6fd;
--color-info-300: #7dd3fc;
--color-info-400: #38bdf8;
--color-info-500: #0ea5e9;
--color-info-600: #0284c7;
--color-info-700: #0369a1;
--color-info-800: #075985;
--color-info-900: #0c4a6e;
/* -------------------------------
FORM ITEM SPECIFICS