barsa 57f2c543d1 style: update typography and layout across components
- Replaced font references in globals.css to use DM Sans and JetBrains Mono for improved typography consistency.
- Adjusted various components to utilize the new font styles, enhancing visual hierarchy and readability.
- Updated layout properties in AppShell and Sidebar for better alignment and spacing.
- Enhanced button styles to include a new subtle variant for improved UI flexibility.
- Refactored SearchFilterBar to support active filter display, improving user interaction experience.
- Made minor adjustments to the DashboardView and landing page components for better visual consistency.
2026-03-06 10:45:51 +09:00
..
2026-01-15 11:30:29 +09:00
2026-01-15 11:30:29 +09:00

Atomic UI Component Library

This directory contains the atomic UI components for the customer portal application. These components are built with accessibility, consistency, and reusability in mind.

Core Components

Button

A versatile button component with multiple variants, sizes, and states.

import { Button } from "@/components/atoms";

// Basic usage
<Button>Click me</Button>

// With variants and sizes
<Button variant="destructive" size="lg">Delete</Button>

// With loading state
<Button loading loadingText="Saving...">Save</Button>

// With icons
<Button leftIcon={<PlusIcon />}>Add Item</Button>

// As a link
<Button as="a" href="/dashboard">Go to Dashboard</Button>

Props:

  • variant: "default" | "destructive" | "outline" | "secondary" | "ghost" | "link"
  • size: "xs" | "sm" | "default" | "lg" | "xl"
  • loading: boolean
  • loadingText: string
  • leftIcon, rightIcon: React.ReactNode
  • as: "button" | "a" (for polymorphic behavior)

Input

Enhanced input component with validation states and accessibility features.

import { Input } from "@/components/atoms";

// Basic usage
<Input placeholder="Enter your name" />

// With validation states
<Input variant="error" error="This field is required" />
<Input variant="success" />

// With icons
<Input leftIcon={<SearchIcon />} placeholder="Search..." />

// With label and helper text
<Input
  label="Email Address"
  required
  helperText="We'll never share your email"
/>

Props:

  • variant: "default" | "error" | "success" | "warning"
  • size: "sm" | "default" | "lg"
  • leftIcon, rightIcon: React.ReactNode
  • error: string
  • helperText: string
  • label: string
  • required: boolean

FormField

Combines Label, Input, and ErrorMessage for complete form fields.

import { FormField } from "@/components/molecules";

<FormField
  label="Email Address"
  type="email"
  required
  error={errors.email}
  helperText="We'll never share your email"
/>;

Label

Accessible label component with required field indicators.

import { Label } from "@/components/atoms";

<Label htmlFor="email" required>
  Email Address
</Label>;

Status & Feedback Components

StatusPill

Displays status information with consistent styling.

import { StatusPill } from "@/components/ui";

<StatusPill variant="success" label="Active" />
<StatusPill variant="error" dot>Failed</StatusPill>
<StatusPill variant="warning" icon={<ClockIcon />}>Pending</StatusPill>

Props:

  • variant: "success" | "warning" | "info" | "error" | "neutral" | "primary" | "secondary"
  • size: "sm" | "default" | "lg"
  • dot: boolean
  • icon: React.ReactNode

Badge

General-purpose badge component for labels and status indicators.

import { Badge } from "@/components/ui";

<Badge variant="success">New</Badge>
<Badge variant="outline" removable onRemove={() => {}}>Tag</Badge>
<Badge dot variant="error">Critical</Badge>

Props:

  • variant: "default" | "secondary" | "success" | "warning" | "error" | "info" | "outline" | "ghost"
  • size: "sm" | "default" | "lg"
  • dot: boolean
  • icon: React.ReactNode
  • removable: boolean
  • onRemove: () => void

LoadingSpinner

Accessible loading spinner with multiple sizes and variants.

import { LoadingSpinner, CenteredLoadingSpinner } from "@/components/ui";

<LoadingSpinner size="lg" />
<CenteredLoadingSpinner label="Loading data..." />

Props:

  • size: "xs" | "sm" | "default" | "lg" | "xl"
  • variant: "default" | "white" | "gray" | "current"
  • label: string (for accessibility)

ErrorState

Displays error states with optional retry functionality.

import { ErrorState, NetworkErrorState } from "@/components/ui";

<ErrorState
  title="Something went wrong"
  message="Please try again later"
  onRetry={() => refetch()}
/>

<NetworkErrorState onRetry={() => refetch()} />

Props:

  • title: string
  • message: string
  • onRetry: () => void
  • variant: "page" | "card" | "inline"

EmptyState

Displays empty states with optional actions.

import { EmptyState, NoDataEmptyState } from "@/components/ui";

<EmptyState
  title="No items found"
  description="Get started by creating your first item"
  action={{
    label: "Create Item",
    onClick: () => createItem()
  }}
/>

<NoDataEmptyState />

Form Validation with Zod

The application uses Zod for type-safe form validation. Use the useZodForm hook for consistent form handling:

import { useZodForm } from "@/core/forms";
import { loginRequestSchema, type LoginRequest } from "@customer-portal/domain/auth";

function MyForm() {
  const { values, errors, touched, isSubmitting, setValue, setTouchedField, handleSubmit } =
    useZodForm({
      schema: loginRequestSchema,
      initialValues: {
        email: "",
        password: "",
      },
      onSubmit: async (data: LoginRequest) => {
        // Handle form submission
        await submitLogin(data);
      },
    });

  return (
    <form onSubmit={handleSubmit}>
      <FormField error={touched.email ? errors.email : undefined}>
        <Input
          value={values.email}
          onChange={e => setValue("email", e.target.value)}
          onBlur={() => setTouchedField("email")}
        />
      </FormField>
      <Button type="submit" disabled={isSubmitting}>
        Submit
      </Button>
    </form>
  );
}

Available Zod schemas in @customer-portal/domain:

  • loginRequestSchema - Login request validation (shared domain schema)
  • signupFormSchema - User registration
  • profileEditFormSchema - Profile updates
  • addressFormSchema - Address validation
  • passwordResetFormSchema - Password reset flows

Design Principles

Accessibility

  • All components include proper ARIA attributes
  • Focus management and keyboard navigation
  • Screen reader support with semantic HTML
  • Color contrast compliance

Consistency

  • Unified design tokens through CSS variables
  • Consistent spacing and typography
  • Standardized color palette
  • Predictable component APIs

Flexibility

  • Polymorphic components (Button as link/button)
  • Composable architecture
  • Customizable through className prop
  • Variant-based styling with class-variance-authority

Performance

  • Tree-shakeable exports
  • Minimal bundle impact
  • Efficient re-renders with forwardRef
  • Optimized for production builds

Usage Guidelines

  1. Import from the index file for better tree-shaking:

    import { Button, Input, StatusPill } from "@/components/ui";
    
  2. Use semantic variants that match the intent:

    <Button variant="destructive">Delete</Button> // Not variant="red"
    
  3. Provide accessibility labels for interactive elements:

    <Button aria-label="Close dialog">×</Button>
    
  4. Combine components for complex UI patterns:

    <FormField
      label="Search"
      leftIcon={<SearchIcon />}
      rightIcon={loading && <LoadingSpinner size="sm" />}
    />
    
  5. Use Zod validation for consistent form handling:

    const { values, errors, setValue } = useZodForm({
      schema: emailFormSchema,
      initialValues: { email: "" },
      onSubmit: handleSubmit,
    });
    

Contributing

When adding new components:

  1. Follow the existing patterns and conventions
  2. Include proper TypeScript types
  3. Add accessibility features
  4. Use class-variance-authority for variants
  5. Export from the index file
  6. Update this README with usage examples