0.2.1 • Published 1 month ago

@switch-to-eu/layout-ui v0.2.1

Weekly downloads
-
License
MIT
Repository
github
Last release
1 month ago

@switch-to-eu/layout-ui

npm version License: MIT TypeScript

A modular, themeable UI design system for privacy-focused tools. Built with React, TypeScript, Tailwind CSS, and Radix UI primitives for maximum accessibility and customization.

✨ Features

  • šŸŽØ Fully Themeable: Customize colors via CSS custom properties
  • šŸ“± Responsive Design: Mobile-first approach with Tailwind CSS
  • ♿ Accessibility First: Built on Radix UI primitives with WCAG compliance
  • šŸ”§ TypeScript Native: 100% TypeScript with full type safety
  • šŸ“š Storybook Included: Interactive component documentation
  • šŸŽÆ Tree Shakeable: Import only the components you need (~32KB full bundle)
  • šŸ”„ Form Integration: React Hook Form + Zod validation support
  • šŸŒ™ Dark Mode Ready: Built-in light/dark theme switching
  • ⚔ Modern Stack: React 19, Next.js 15, latest tooling

šŸ“¦ Installation

npm install @switch-to-eu/layout-ui

Peer Dependencies

Ensure you have the required peer dependencies:

npm install react@^19.0.0 react-dom@^19.0.0 next@^15.2.3

šŸš€ Quick Start

1. Import Styles

Import the base styles in your project (usually in globals.css or layout.tsx):

/* Option 1: Import main styles (includes globals.css) */
@import "@switch-to-eu/layout-ui/styles";

/* Option 2: Import specific style files */
@import "@switch-to-eu/layout-ui/styles/globals.css";
@import "@switch-to-eu/layout-ui/styles/themes.css";

Or in your TypeScript/JavaScript files:

// In your root layout or App component
import "@switch-to-eu/layout-ui/styles/globals.css";

2. Use Components

import { Button, Card, CardHeader, CardTitle, CardContent } from "@switch-to-eu/layout-ui";

function App() {
  return (
    <Card className="w-96">
      <CardHeader>
        <CardTitle>Welcome to Layout UI</CardTitle>
      </CardHeader>
      <CardContent>
        <Button variant="default" size="lg">
          Get Started
        </Button>
      </CardContent>
    </Card>
  );
}

3. Customize Theme (Optional)

Override CSS custom properties to match your brand:

/* In your globals.css */
:root {
  --primary: 262 83% 58%;        /* Purple */
  --secondary: 220 14% 96%;      /* Light gray */
  --accent: 142 76% 36%;         /* Green */
  --destructive: 0 72% 51%;      /* Red */
  --radius: 0.75rem;             /* Border radius */
}

🧩 Available Components

Core UI Components

ComponentDescriptionFeatures
ButtonInteractive buttons with variants6 variants, loading states, icons
CardContent containersHeader, content, footer composition
InputText input fieldsValidation states, descriptions
LabelForm labelsAccessibility optimized
AlertStatus messagesSuccess, warning, error, info variants
SkeletonLoading placeholdersAnimated, responsive
CheckboxBoolean inputRadix UI integration
SelectDropdown selectionRadix UI integration
DialogModal dialogsRadix UI integration
CalendarDate pickerdate-fns integration

Composite Components

ComponentDescriptionUse Case
SectionCardStructured content sectionsMain content areas
SectionHeaderSection headings with iconsPage/section titles
HeaderNavigation headersApp navigation
LoadingButtonButton with loading stateForm submissions

Form Components

ComponentDescriptionIntegration
FormInputReact Hook Form inputFull validation, error handling
FormTextareaReact Hook Form textareaMulti-line text input
TextareaBase textarea componentStandalone usage

šŸŽØ Theme Customization

Method 1: CSS Custom Properties (Recommended)

Override theme variables in your CSS:

/* Your project's globals.css */
@import "@switch-to-eu/layout-ui/styles";

/* Light theme customization */
:root {
  /* Brand colors */
  --primary: 262 83% 58%;           /* Purple */
  --primary-foreground: 0 0% 100%;  /* White text */

  /* Secondary colors */
  --secondary: 220 14% 96%;         /* Light gray */
  --secondary-foreground: 222 84% 5%; /* Dark text */

  /* Accent colors */
  --accent: 142 76% 36%;            /* Green */
  --accent-foreground: 0 0% 100%;   /* White text */

  /* Status colors */
  --destructive: 0 72% 51%;         /* Red */
  --destructive-foreground: 0 0% 100%; /* White text */

  /* Layout */
  --radius: 0.75rem;                /* Border radius */
  --border: 220 13% 91%;            /* Border color */
}

/* Dark theme customization */
.dark {
  --primary: 262 83% 70%;           /* Lighter purple for dark mode */
  --secondary: 217 32% 17%;         /* Dark gray */
  --background: 222 84% 5%;         /* Dark background */
  --foreground: 210 40% 98%;        /* Light text */
}

Method 2: JavaScript Theme Utilities

Use the built-in theme utilities for dynamic theming:

import { applyTheme, setColorMode, getSystemColorMode } from "@switch-to-eu/layout-ui";

// Apply custom theme programmatically
applyTheme({
  primary: "262 83% 58%",
  accent: "142 76% 36%",
  destructive: "0 72% 51%"
});

// Handle dark mode
setColorMode("dark");
setColorMode("light");
setColorMode("system"); // Follow system preference

// Get current system preference
const systemMode = getSystemColorMode(); // "light" | "dark"

Complete Theme Properties Reference

/* Color Properties (HSL values without hsl()) */
--background: /* Main background */
--foreground: /* Main text color */
--primary: /* Primary brand color */
--primary-foreground: /* Text on primary */
--secondary: /* Secondary color */
--secondary-foreground: /* Text on secondary */
--accent: /* Accent color */
--accent-foreground: /* Text on accent */
--destructive: /* Error/danger color */
--destructive-foreground: /* Text on destructive */
--muted: /* Muted backgrounds */
--muted-foreground: /* Muted text */
--card: /* Card backgrounds */
--card-foreground: /* Text on cards */
--border: /* Border color */
--input: /* Input border color */
--ring: /* Focus ring color */

/* Layout Properties */
--radius: /* Border radius (in rem) */

šŸ”§ Form Integration

React Hook Form + Zod Example

import { useForm } from "react-hook-form";
import { zodResolver } from "@hookform/resolvers/zod";
import { z } from "zod";
import { FormInput, FormTextarea, Button, Card } from "@switch-to-eu/layout-ui";

const schema = z.object({
  name: z.string().min(2, "Name must be at least 2 characters"),
  email: z.string().email("Invalid email address"),
  message: z.string().min(10, "Message must be at least 10 characters")
});

type FormData = z.infer<typeof schema>;

function ContactForm() {
  const { control, handleSubmit, formState: { isSubmitting } } = useForm<FormData>({
    resolver: zodResolver(schema)
  });

  const onSubmit = async (data: FormData) => {
    // Handle form submission
    console.log(data);
  };

  return (
    <Card className="p-6">
      <form onSubmit={handleSubmit(onSubmit)} className="space-y-4">
        <FormInput
          control={control}
          name="name"
          label="Full Name"
          placeholder="Enter your name"
        />
        <FormInput
          control={control}
          name="email"
          label="Email Address"
          type="email"
          placeholder="Enter your email"
        />
        <FormTextarea
          control={control}
          name="message"
          label="Message"
          placeholder="Enter your message"
          rows={4}
        />
        <Button type="submit" loading={isSubmitting}>
          {isSubmitting ? "Sending..." : "Send Message"}
        </Button>
      </form>
    </Card>
  );
}

šŸ“– Development

Setup

# Clone the repository
git clone https://github.com/switch-to-eu/layout-ui.git
cd layout-ui

# Install dependencies
npm install

# Start development mode with hot reload
npm run dev

# Start Storybook for component development
npm run storybook

Available Scripts

ScriptDescription
npm run buildBuild the library for production
npm run devStart development mode with watch
npm run storybookStart Storybook development server
npm run build-storybookBuild Storybook for production
npm run lintRun ESLint
npm run type-checkRun TypeScript compiler check
npm run publish:dryTest publish without actually publishing
npm run publish:betaPublish beta version to npm

Project Structure

layout-ui/
ā”œā”€ā”€ src/
│   ā”œā”€ā”€ components/
│   │   ā”œā”€ā”€ ui/              # Core UI components
│   │   │   ā”œā”€ā”€ Button.tsx
│   │   │   ā”œā”€ā”€ Card.tsx
│   │   │   ā”œā”€ā”€ Input.tsx
│   │   │   └── ...
│   │   ā”œā”€ā”€ form/            # Form components
│   │   │   ā”œā”€ā”€ FormInput.tsx
│   │   │   ā”œā”€ā”€ FormTextarea.tsx
│   │   │   └── FormUtils.tsx
│   │   └── index.ts         # Component exports
│   ā”œā”€ā”€ lib/
│   │   ā”œā”€ā”€ utils.ts         # Utility functions
│   │   └── theme.ts         # Theme management
│   ā”œā”€ā”€ styles/
│   │   ā”œā”€ā”€ globals.css      # Base styles
│   │   └── themes.css       # Theme system
│   ā”œā”€ā”€ types/
│   │   └── index.ts         # TypeScript definitions
│   └── index.ts             # Main library export
ā”œā”€ā”€ stories/                 # Storybook stories
ā”œā”€ā”€ .storybook/             # Storybook configuration
ā”œā”€ā”€ dist/                   # Built library output
└── docs/                   # Documentation

šŸ“‹ Publishing

This library is published to npm as @switch-to-eu/layout-ui.

Version Management

# Patch version (bug fixes)
npm run version:patch

# Minor version (new features)
npm run version:minor

# Major version (breaking changes)
npm run version:major

Publishing Process

# 1. Test the build
npm run build
npm run type-check

# 2. Test publish without actually publishing
npm run publish:dry

# 3. Publish to npm
npm publish

# Or publish beta version
npm run publish:beta

šŸ¤ Contributing

This library is part of the privacy-tools ecosystem. Components are extracted and made generic from existing projects to maintain consistency.

Guidelines

  1. Keep it generic - No project-specific code in the library
  2. Theme-first - All styling should use CSS custom properties
  3. Accessibility - Use Radix UI primitives where possible
  4. TypeScript - Full type safety required
  5. Documentation - Include Storybook stories for all components

Component Migration Process

  1. Extract component from existing project
  2. Remove project-specific styling/logic
  3. Convert to use theme variables
  4. Add proper TypeScript interfaces
  5. Create Storybook story
  6. Update exports and documentation

šŸ“„ License

MIT License - see LICENSE file for details.

šŸ”— Links

šŸ™ Acknowledgments


Built with ā¤ļø for privacy-focused applications