feat: enhance input showcase with new input components and status handling
This commit is contained in:
@@ -1,126 +1,193 @@
|
||||
import { Input, InputNumber, InputStatusType, TextArea } from '@repo/ui';
|
||||
import { Input, InputPassword, InputNumber, InputCurrency, InputStatusType, TextArea } from '@repo/ui';
|
||||
|
||||
// Helper untuk label kolom
|
||||
const Label = ({ children }: { children: React.ReactNode }) => (
|
||||
<div className="text-xs font-bold text-gray-400 uppercase mb-3 tracking-wider">{children}</div>
|
||||
);
|
||||
|
||||
// Helper untuk prefix/suffix visual
|
||||
const Fix = ({ children }: { children: React.ReactNode }) => <span className="text-gray-400 text-sm">{children}</span>;
|
||||
|
||||
export default function GroupComponent({ status }: { status?: InputStatusType }) {
|
||||
return (
|
||||
<div>
|
||||
<div className="space-y-4 bg-white p-5 rounded-xl border border-gray-200 shadow-xs">
|
||||
<h3 className="text-xs font-bold text-gray-400 uppercase">Default</h3>
|
||||
<div className="grid grid-cols-4 gap-4 ">
|
||||
<div className="space-y-4">
|
||||
<div className="text-gray-500 ">Default</div>
|
||||
<div className="space-y-2">
|
||||
<Input status={status} placeholder="Outlined Placeholder" />
|
||||
<InputNumber status={status} className="w-full" placeholder="OutlinedNumber Placeholder" />
|
||||
<TextArea status={status} placeholder="Outlined TextArea Placeholder" rows={2} />
|
||||
<Input status={status} variant="filled" placeholder="Filled Placeholder" />
|
||||
<InputNumber
|
||||
status={status}
|
||||
variant="filled"
|
||||
className="w-full"
|
||||
placeholder="Filled Number Placeholder"
|
||||
/>
|
||||
<TextArea status={status} variant="filled" placeholder="Filled TextArea Placeholder" rows={2} />
|
||||
<div className="space-y-12 p-8 rounded-2xl">
|
||||
{/* --- SECTION 1: OUTLINED VARIANT (DEFAULT) --- */}
|
||||
<section className="space-y-6">
|
||||
<h2 className="text-lg font-bold text-gray-800 border-b pb-2">Outlined Variant (Standard)</h2>
|
||||
<div className="grid grid-cols-1 md:grid-cols-4 gap-6">
|
||||
<div className="space-y-3">
|
||||
<Label>Basic</Label>
|
||||
<Input status={status} placeholder="Input text..." />
|
||||
<InputPassword status={status} placeholder="Password..." />
|
||||
<InputNumber status={status} className="w-full" placeholder="Number..." />
|
||||
<InputCurrency status={status} className="w-full" placeholder="Currency..." />
|
||||
<TextArea status={status} placeholder="TextArea..." rows={2} />
|
||||
</div>
|
||||
|
||||
<div className="space-y-3">
|
||||
<Label>With Prefix</Label>
|
||||
<Input status={status} prefix={<Fix>@</Fix>} placeholder="username" />
|
||||
<InputPassword status={status} prefix={<Fix>🔒</Fix>} placeholder="password" />
|
||||
<InputNumber status={status} prefix={<Fix>#</Fix>} className="w-full" placeholder="id" />
|
||||
<InputCurrency status={status} prefix="Rp " className="w-full" placeholder="price" />
|
||||
</div>
|
||||
|
||||
<div className="space-y-3">
|
||||
<Label>With Suffix</Label>
|
||||
<Input status={status} suffix={<Fix>.com</Fix>} placeholder="website" />
|
||||
<InputPassword status={status} suffix={<Fix>Required</Fix>} placeholder="password" />
|
||||
<InputNumber status={status} suffix={<Fix>kg</Fix>} className="w-full" placeholder="weight" />
|
||||
<InputCurrency status={status} suffix={<Fix>nett</Fix>} className="w-full" placeholder="total" />
|
||||
</div>
|
||||
|
||||
<div className="space-y-3">
|
||||
<Label>Both & Special</Label>
|
||||
<Input status={status} prefix={<Fix>https://</Fix>} suffix={<Fix>.io</Fix>} placeholder="domain" />
|
||||
{/* Password Tanpa Toggle */}
|
||||
<InputPassword
|
||||
status={status}
|
||||
visibilityToggle={false}
|
||||
prefix={<Fix>🔑</Fix>}
|
||||
placeholder="Hidden Password"
|
||||
/>
|
||||
<InputNumber
|
||||
status={status}
|
||||
prefix={<Fix>+</Fix>}
|
||||
suffix={<Fix>%</Fix>}
|
||||
className="w-full"
|
||||
placeholder="tax"
|
||||
/>
|
||||
<InputCurrency
|
||||
status={status}
|
||||
prefix="USD "
|
||||
suffix={<Fix>cents</Fix>}
|
||||
className="w-full"
|
||||
placeholder="amount"
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
{/* --- SECTION 2: FILLED VARIANT --- */}
|
||||
<section className="space-y-6">
|
||||
<h2 className="text-lg font-bold text-gray-800 border-b pb-2">Filled Variant</h2>
|
||||
<div className="grid grid-cols-1 md:grid-cols-4 gap-6">
|
||||
<div className="space-y-3">
|
||||
<Label>Basic Filled</Label>
|
||||
<Input variant="filled" status={status} placeholder="Filled Input" />
|
||||
<InputPassword variant="filled" status={status} placeholder="Filled Password" />
|
||||
<InputNumber variant="filled" status={status} className="w-full" placeholder="Filled Number" />
|
||||
<InputCurrency variant="filled" status={status} className="w-full" placeholder="Filled Currency" />
|
||||
<TextArea variant="filled" status={status} placeholder="Filled TextArea" rows={2} />
|
||||
</div>
|
||||
|
||||
<div className="space-y-3">
|
||||
<Label>Filled + Prefix</Label>
|
||||
<Input variant="filled" status={status} prefix={<Fix>ID</Fix>} placeholder="12345" />
|
||||
<InputPassword variant="filled" status={status} prefix={<Fix>🔑</Fix>} placeholder="password" />
|
||||
<InputNumber variant="filled" status={status} prefix={<Fix>Qty:</Fix>} className="w-full" />
|
||||
<InputCurrency variant="filled" status={status} prefix="Rp " className="w-full" />
|
||||
</div>
|
||||
|
||||
<div className="space-y-3">
|
||||
<Label>Filled + Suffix</Label>
|
||||
<Input variant="filled" status={status} suffix={<Fix>Optional</Fix>} placeholder="Full Name" />
|
||||
<InputPassword variant="filled" status={status} suffix={<Fix>?</Fix>} placeholder="password" />
|
||||
<InputNumber variant="filled" status={status} suffix={<Fix>pts</Fix>} className="w-full" />
|
||||
<InputCurrency variant="filled" status={status} suffix={<Fix>tax-incl</Fix>} className="w-full" />
|
||||
</div>
|
||||
<div className="space-y-3">
|
||||
<Label>Both & Special</Label>
|
||||
<Input
|
||||
variant="filled"
|
||||
status={status}
|
||||
prefix={<Fix>https://</Fix>}
|
||||
suffix={<Fix>.io</Fix>}
|
||||
placeholder="domain"
|
||||
/>
|
||||
{/* Password Tanpa Toggle */}
|
||||
<InputPassword
|
||||
variant="filled"
|
||||
status={status}
|
||||
visibilityToggle={false}
|
||||
prefix={<Fix>🔑</Fix>}
|
||||
placeholder="Hidden Password"
|
||||
/>
|
||||
<InputNumber
|
||||
variant="filled"
|
||||
status={status}
|
||||
prefix={<Fix>+</Fix>}
|
||||
suffix={<Fix>%</Fix>}
|
||||
className="w-full"
|
||||
placeholder="tax"
|
||||
/>
|
||||
<InputCurrency
|
||||
variant="filled"
|
||||
status={status}
|
||||
prefix="USD "
|
||||
suffix={<Fix>cents</Fix>}
|
||||
className="w-full"
|
||||
placeholder="amount"
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
{/* --- SECTION 3: Component States & Validation --- */}
|
||||
|
||||
<section className="space-y-6">
|
||||
<h2 className="text-lg font-bold text-gray-800 border-b pb-2">Component States & Validation</h2>
|
||||
|
||||
<div className="grid grid-cols-1 md:grid-cols-2 lg:grid-cols-4 gap-8">
|
||||
{/* COLUMN 1: DISABLED (Semua Component) */}
|
||||
<div className="space-y-3">
|
||||
<Label>Disabled State</Label>
|
||||
<div className="p-4 bg-gray-50 rounded-lg space-y-3 border border-dashed border-gray-200">
|
||||
<Input disabled placeholder="Disabled Input" prefix={<Fix>🚫</Fix>} />
|
||||
<InputPassword disabled placeholder="Disabled Password" />
|
||||
<InputNumber disabled className="w-full" placeholder="0" />
|
||||
<InputCurrency disabled className="w-full" placeholder="Rp 0" />
|
||||
<TextArea disabled placeholder="Disabled TextArea" rows={2} />
|
||||
</div>
|
||||
</div>
|
||||
<div className="space-y-4">
|
||||
<div className="text-gray-500 ">With Prefix</div>
|
||||
<div className="space-y-2">
|
||||
<Input
|
||||
status={status}
|
||||
placeholder="Outlined Placeholder"
|
||||
prefix={<span className="text-gray-500">$</span>}
|
||||
/>
|
||||
<InputNumber
|
||||
status={status}
|
||||
className="w-full"
|
||||
placeholder="OutlinedNumber Placeholder"
|
||||
prefix={<span className="text-gray-500">$</span>}
|
||||
/>
|
||||
<TextArea status={status} placeholder="Outlined TextArea Placeholder" rows={2} />
|
||||
<Input
|
||||
status={status}
|
||||
variant="filled"
|
||||
placeholder="Filled Placeholder"
|
||||
prefix={<span className="text-gray-500">$</span>}
|
||||
/>
|
||||
<InputNumber
|
||||
status={status}
|
||||
variant="filled"
|
||||
className="w-full"
|
||||
placeholder="Filled Number Placeholder"
|
||||
prefix={<span className="text-gray-500">$</span>}
|
||||
/>
|
||||
<TextArea status={status} variant="filled" placeholder="Filled TextArea Placeholder" rows={2} />
|
||||
|
||||
{/* COLUMN 2: READ ONLY (Semua Component) */}
|
||||
<div className="space-y-3">
|
||||
<Label>Read Only State</Label>
|
||||
<div className="p-4 bg-gray-50 rounded-lg space-y-3 border border-dashed border-gray-200">
|
||||
<Input readOnly value="Read only text" prefix={<Fix>📖</Fix>} />
|
||||
<InputPassword readOnly value="secretpassword" />
|
||||
<InputNumber readOnly className="w-full" value={12345} />
|
||||
<InputCurrency readOnly className="w-full" value={50000} />
|
||||
<TextArea readOnly value="This content is read only and cannot be edited." rows={2} />
|
||||
</div>
|
||||
</div>
|
||||
<div className="space-y-4">
|
||||
<div className="text-gray-500 ">With Suffix</div>
|
||||
<div className="space-y-2">
|
||||
<Input
|
||||
status={status}
|
||||
placeholder="Outlined Placeholder"
|
||||
suffix={<span className="text-gray-500">$</span>}
|
||||
/>
|
||||
<InputNumber
|
||||
status={status}
|
||||
className="w-full"
|
||||
placeholder="OutlinedNumber Placeholder"
|
||||
suffix={<span className="text-gray-500">$</span>}
|
||||
/>
|
||||
<TextArea status={status} placeholder="Outlined TextArea Placeholder" rows={2} />
|
||||
<Input
|
||||
status={status}
|
||||
variant="filled"
|
||||
placeholder="Filled Placeholder"
|
||||
suffix={<span className="text-gray-500">$</span>}
|
||||
/>
|
||||
<InputNumber
|
||||
status={status}
|
||||
variant="filled"
|
||||
className="w-full"
|
||||
placeholder="Filled Number Placeholder"
|
||||
suffix={<span className="text-gray-500">$</span>}
|
||||
/>
|
||||
<TextArea status={status} variant="filled" placeholder="Filled TextArea Placeholder" rows={2} />
|
||||
|
||||
{/* COLUMN 3: ERROR OUTLINED */}
|
||||
<div className="space-y-3">
|
||||
<Label>Error (Outlined)</Label>
|
||||
<div className="space-y-3">
|
||||
<Input status="error" placeholder="Invalid input" />
|
||||
<InputPassword status="error" placeholder="Wrong password" />
|
||||
<InputNumber status="error" className="w-full" placeholder="Out of range" />
|
||||
<InputCurrency status="error" className="w-full" placeholder="Invalid amount" />
|
||||
<TextArea status="error" placeholder="Error in message" rows={2} />
|
||||
</div>
|
||||
</div>
|
||||
<div className="space-y-4">
|
||||
<div className="text-gray-500 ">With Prefix and Suffix</div>
|
||||
<div className="space-y-2">
|
||||
<Input
|
||||
status={status}
|
||||
placeholder="Outlined Placeholder"
|
||||
prefix={<span className="text-gray-500">$</span>}
|
||||
suffix={<span className="text-gray-500">$</span>}
|
||||
/>
|
||||
<InputNumber
|
||||
status={status}
|
||||
className="w-full"
|
||||
placeholder="OutlinedNumber Placeholder"
|
||||
prefix={<span className="text-gray-500">$</span>}
|
||||
suffix={<span className="text-gray-500">$</span>}
|
||||
/>
|
||||
<TextArea status={status} placeholder="Outlined TextArea Placeholder" rows={2} />
|
||||
<Input
|
||||
status={status}
|
||||
variant="filled"
|
||||
placeholder="Filled Placeholder"
|
||||
prefix={<span className="text-gray-500">$</span>}
|
||||
suffix={<span className="text-gray-500">$</span>}
|
||||
/>
|
||||
<InputNumber
|
||||
status={status}
|
||||
variant="filled"
|
||||
className="w-full"
|
||||
placeholder="Filled Number Placeholder"
|
||||
prefix={<span className="text-gray-500">$</span>}
|
||||
suffix={<span className="text-gray-500">$</span>}
|
||||
/>
|
||||
<TextArea status={status} variant="filled" placeholder="Filled TextArea Placeholder" rows={2} />
|
||||
|
||||
{/* COLUMN 4: ERROR FILLED */}
|
||||
<div className="space-y-3">
|
||||
<Label>Error (Filled)</Label>
|
||||
<div className="space-y-3">
|
||||
<Input variant="filled" status="error" placeholder="Invalid input" />
|
||||
<InputPassword variant="filled" status="error" placeholder="Wrong password" />
|
||||
<InputNumber variant="filled" status="error" className="w-full" placeholder="Out of range" />
|
||||
<InputCurrency variant="filled" status="error" className="w-full" placeholder="Invalid amount" />
|
||||
<TextArea variant="filled" status="error" placeholder="Error in message" rows={2} />
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
@@ -1,28 +1,69 @@
|
||||
import { useState } from 'react';
|
||||
import GroupComponent from './group-component';
|
||||
import { InputStatusType } from '@repo/ui';
|
||||
|
||||
export default function InputShowCase() {
|
||||
// State untuk menyimpan status yang dipilih
|
||||
const [selectedStatus, setSelectedStatus] = useState<InputStatusType>('normal');
|
||||
|
||||
const statuses: { label: string; value: InputStatusType; color: string }[] = [
|
||||
{ label: 'Normal', value: 'normal', color: 'bg-gray-500' },
|
||||
{ label: 'Error', value: 'error', color: 'bg-red-500' },
|
||||
{ label: 'Warning', value: 'warning', color: 'bg-amber-500' },
|
||||
{ label: 'Success', value: 'success', color: 'bg-emerald-500' },
|
||||
{ label: 'Info', value: 'info', color: 'bg-blue-500' },
|
||||
];
|
||||
|
||||
return (
|
||||
<div className="min-h-screen ">
|
||||
<main className="mx-auto p-8 space-y-12">
|
||||
<section className="space-y-6">
|
||||
<div className="flex items-center gap-2">
|
||||
<h2 className="text-lg font-bold">1. All Conditions Matrix</h2>
|
||||
<span className="px-2 py-0.5 text-[10px] bg-gray-200 text-gray-600 rounded uppercase tracking-wider">
|
||||
Visual Audit
|
||||
</span>
|
||||
<div className="min-h-screen bg-gray-50/50">
|
||||
<main className="mx-auto p-8 space-y-8">
|
||||
{/* HEADER & SELECTOR */}
|
||||
<div className="flex flex-col md:flex-row md:items-center justify-between gap-4 bg-white p-6 rounded-2xl border border-gray-200 shadow-sm">
|
||||
<div className="space-y-1">
|
||||
<div className="flex items-center gap-2">
|
||||
<h2 className="text-xl font-bold text-gray-800">Input Components</h2>
|
||||
<span className="px-2 py-0.5 text-[10px] bg-blue-100 text-blue-600 rounded-full uppercase tracking-wider font-bold">
|
||||
Interactive Lab
|
||||
</span>
|
||||
</div>
|
||||
<p className="text-sm text-gray-500">
|
||||
Pilih status untuk melihat perubahan validasi pada semua tipe input.
|
||||
</p>
|
||||
</div>
|
||||
|
||||
<div className="grid grid-cols-1 gap-6">
|
||||
{/* COLUMN: ERROR */}
|
||||
<GroupComponent status="error" />
|
||||
{/* COLUMN: NORMAL */}
|
||||
<GroupComponent />
|
||||
{/* COLUMN: INFO */}
|
||||
<GroupComponent status="info" />
|
||||
{/* COLUMN: WARNING */}
|
||||
<GroupComponent status="warning" />
|
||||
{/* COLUMN: SUCCESS */}
|
||||
<GroupComponent status="success" />
|
||||
{/* TAB SELECTOR */}
|
||||
<div className="flex bg-gray-100 p-1 rounded-xl w-fit border border-gray-200">
|
||||
{statuses.map((item) => (
|
||||
<button
|
||||
key={item.value}
|
||||
onClick={() => setSelectedStatus(item.value)}
|
||||
className={`
|
||||
px-4 py-2 text-sm font-medium rounded-lg transition-all duration-200
|
||||
${
|
||||
selectedStatus === item.value
|
||||
? 'bg-white text-gray-900 shadow-sm'
|
||||
: 'text-gray-500 hover:text-gray-700 hover:bg-gray-50'
|
||||
}
|
||||
`}
|
||||
>
|
||||
<div className="flex items-center gap-2">
|
||||
<span className={`w-2 h-2 rounded-full ${item.color}`} />
|
||||
{item.label}
|
||||
</div>
|
||||
</button>
|
||||
))}
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{/* RENDER COMPONENT */}
|
||||
<section className="animate-in fade-in slide-in-from-bottom-2 duration-500">
|
||||
<div className="relative">
|
||||
{/* Label Indikator Status Aktif */}
|
||||
<div className="absolute -top-3 left-8 px-3 py-1 rounded-full text-[10px] font-bold uppercase tracking-widest bg-white border border-gray-200 shadow-sm z-10">
|
||||
Active Status: <span className="text-blue-600">{selectedStatus}</span>
|
||||
</div>
|
||||
|
||||
<GroupComponent status={selectedStatus} />
|
||||
</div>
|
||||
</section>
|
||||
</main>
|
||||
|
||||
Reference in New Issue
Block a user