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:
@@ -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;
|
||||
}
|
||||
|
||||
@@ -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
|
||||
|
||||
Reference in New Issue
Block a user