0.5.12 โ€ข Published 9 months ago

@fpkit/acss v0.5.12

Weekly downloads
-
License
MIT
Repository
github
Last release
9 months ago

@fpkit/acss

A lightweight React UI library for building modern and accessible components that leverage CSS custom properties for reactive styles. Built with TypeScript and designed for optimal tree-shaking and bundle size optimization.

npm version License: MIT

๐Ÿ“š Storybook Documentation | ๐ŸŽฏ Component Playground

โœจ Features

  • ๐ŸŽฏ Dual Export Strategy: Choose between convenience (barrel exports) or optimization (individual imports)
  • ๐Ÿ“ฆ Tree-Shakable: Import only the components you need
  • โ™ฟ Accessible: Built with accessibility best practices
  • ๐ŸŽจ CSS Custom Properties: Reactive styling with CSS variables
  • ๐Ÿ“ฑ Responsive: Mobile-first design approach
  • โšก TypeScript: Full type safety and excellent DX
  • ๐Ÿ”ง Headless: Minimal styling, maximum customization

๐Ÿ“ฆ Installation

npm install @fpkit/acss
# or
yarn add @fpkit/acss
# or
pnpm add @fpkit/acss

๐Ÿš€ Quick Start

Option 1: Barrel Imports (Convenience)

Perfect for rapid prototyping and when bundle size isn't critical:

import { Button, Card, Input, Modal } from '@fpkit/acss';
import '@fpkit/acss/styles';

function App() {
  return (
    <div>
      <Card>
        <Card.Title>Welcome to FPKit</Card.Title>
        <Card.Content>
          <Input type="text" placeholder="Enter your name" />
          <Button type="button">Submit</Button>
        </Card.Content>
      </Card>
    </div>
  );
}

Option 2: Individual Imports (Tree-Shaking)

Optimal for production builds and bundle size optimization:

import { Button } from '@fpkit/acss/button';
import { Card } from '@fpkit/acss/card';
import { Input } from '@fpkit/acss/input';
import '@fpkit/acss/styles';

function App() {
  return (
    <div>
      <Card>
        <Card.Title>Welcome to FPKit</Card.Title>
        <Card.Content>
          <Input type="text" placeholder="Enter your name" />
          <Button type="button">Submit</Button>
        </Card.Content>
      </Card>
    </div>
  );
}

๐Ÿงฉ Core Components

Button

Accessible button component with multiple variants:

// Barrel import
import { Button } from '@fpkit/acss';

// Individual import
import { Button } from '@fpkit/acss/button';

// Usage
<Button type="button" onClick={() => console.log('clicked')}>
  Click me
</Button>

// With TypeScript
import { Button, type ButtonProps } from '@fpkit/acss/button';

const buttonProps: ButtonProps = {
  type: 'submit',
  disabled: false,
  children: 'Submit Form'
};

Card

Flexible card component with composable parts:

// Individual import
import { Card } from '@fpkit/acss/card';

// Usage
<Card>
  <Card.Title>Card Title</Card.Title>
  <Card.Content>
    <p>This is the card content area.</p>
  </Card.Content>
  <Card.Footer>
    <Button type="button">Action</Button>
  </Card.Footer>
</Card>

// Custom styling
<Card classes="custom-card" styles={{ padding: '2rem' }}>
  <Card.Title>Styled Card</Card.Title>
  <Card.Content>Content with custom styling</Card.Content>
</Card>

Modal

Accessible modal dialog with focus management:

import { Modal } from '@fpkit/acss/modal';

<Modal
  openChild="Open Modal"
  closeChild="Close"
  modalHeader={<h2>Modal Title</h2>}
  modalFooter={
    <div>
      <Button type="button">Cancel</Button>
      <Button type="button">Confirm</Button>
    </div>
  }
>
  <p>Modal content goes here.</p>
</Modal>

Input

Form input component with validation support:

import { Input } from '@fpkit/acss/input';

<Input
  type="email"
  placeholder="Enter your email"
  required
  aria-label="Email address"
/>

// With field wrapper
import { Field } from '@fpkit/acss';

<Field>
  <Field.Label>Email Address</Field.Label>
  <Input type="email" placeholder="you@example.com" />
  <Field.Error>Please enter a valid email</Field.Error>
</Field>

Navigation

Semantic navigation components:

import { Nav, NavList, NavItem } from '@fpkit/acss';

<Nav>
  <NavList>
    <NavItem>
      <Link href="/">Home</Link>
    </NavItem>
    <NavItem>
      <Link href="/about">About</Link>
    </NavItem>
    <NavItem>
      <Link href="/contact">Contact</Link>
    </NavItem>
  </NavList>
</Nav>

Text & Typography

Semantic text components:

import { Text, Heading } from '@fpkit/acss';

<Heading as="h1" size="xl">
  Page Title
</Heading>

<Text as="p" size="lg">
  This is a paragraph with large text.
</Text>

<Text as="span" variant="muted">
  Muted text for secondary information.
</Text>

๐ŸŽจ Styling & Theming

FPKit uses CSS custom properties for theming and styling:

/* Global theme variables */
:root {
  --fp-color-primary: #007bff;
  --fp-color-secondary: #6c757d;
  --fp-spacing-sm: 0.5rem;
  --fp-spacing-md: 1rem;
  --fp-spacing-lg: 1.5rem;
  --fp-border-radius: 0.375rem;
}

/* Component-specific styling */
.custom-button {
  --fp-button-bg: var(--fp-color-primary);
  --fp-button-color: white;
  --fp-button-padding: var(--fp-spacing-md);
}

Component Styling

// Inline styles
<Button styles={{ backgroundColor: 'red', color: 'white' }}>
  Styled Button
</Button>

// CSS classes
<Card classes="shadow-lg border-rounded">
  <Card.Content>Styled card</Card.Content>
</Card>

// Data attributes for CSS targeting
<Button data-variant="primary" data-size="large">
  Data Attribute Styling
</Button>

๐Ÿ› ๏ธ Framework Integration

Next.js

// pages/_app.tsx
import '@fpkit/acss/styles';
import type { AppProps } from 'next/app';

export default function App({ Component, pageProps }: AppProps) {
  return <Component {...pageProps} />;
}

// pages/index.tsx
import { Button } from '@fpkit/acss/button';
import { Card } from '@fpkit/acss/card';

export default function Home() {
  return (
    <main>
      <Card>
        <Card.Title>Next.js + FPKit</Card.Title>
        <Card.Content>
          <Button type="button">Get Started</Button>
        </Card.Content>
      </Card>
    </main>
  );
}

Vite + React

// main.tsx
import React from 'react';
import ReactDOM from 'react-dom/client';
import '@fpkit/acss/styles';
import App from './App.tsx';

ReactDOM.createRoot(document.getElementById('root')!).render(
  <React.StrictMode>
    <App />
  </React.StrictMode>,
);

// App.tsx
import { Button, Card } from '@fpkit/acss';

function App() {
  return (
    <Card>
      <Card.Title>Vite + React + FPKit</Card.Title>
      <Card.Content>
        <Button type="button">Hello World</Button>
      </Card.Content>
    </Card>
  );
}

export default App;

๐Ÿ“‹ Available Components

Core UI Components

  • Button - Accessible button with variants
  • Card - Flexible card container with composable parts
  • Modal - Accessible modal dialog
  • Dialog - General purpose dialog component
  • Input - Form input with validation
  • Field - Form field wrapper with label and error
  • Link - Accessible link component
  • List - Semantic list components

Layout Components

  • Box - Generic container component
  • Nav - Navigation components
  • Landmarks - Semantic landmark components

Typography

  • Text - Semantic text component
  • Heading - Heading component with sizes

Media

  • Icon - SVG icon component
  • Image - Responsive image component

Data Display

  • Table - Accessible table components
  • Tag - Tag/badge component
  • Badge - Status badge component

Specialized

  • TextToSpeech - Text-to-speech component
  • Popover - Popover/tooltip component
  • Breadcrumb - Navigation breadcrumbs

๐ŸŽฏ Import Strategies

When to Use Barrel Imports

  • Rapid prototyping
  • Small applications
  • When using many components
  • Development/testing environments

When to Use Individual Imports

  • Production applications
  • Performance-critical apps
  • When using few components
  • Library/package development

Bundle Size Comparison

# Barrel import (all components)
import { Button, Card, Modal } from '@fpkit/acss';
# Bundle size: ~45KB (example)

# Individual imports (tree-shaken)
import { Button } from '@fpkit/acss/button';
import { Card } from '@fpkit/acss/card';
import { Modal } from '@fpkit/acss/modal';
# Bundle size: ~12KB (example)

๐Ÿ”ง TypeScript Support

Full TypeScript support with comprehensive type definitions:

import { Button, type ButtonProps } from '@fpkit/acss/button';
import { Card, type CardProps } from '@fpkit/acss/card';

// Type-safe props
const buttonProps: ButtonProps = {
  type: 'button',
  onClick: (e) => console.log(e),
  children: 'Click me'
};

// Component with proper typing
const MyButton: React.FC<ButtonProps> = (props) => {
  return <Button {...props} />;
};

๐Ÿงช Testing

Components are designed for easy testing:

import { render, screen } from '@testing-library/react';
import { Button } from '@fpkit/acss/button';

test('renders button with text', () => {
  render(<Button type="button">Click me</Button>);
  expect(screen.getByRole('button', { name: /click me/i })).toBeInTheDocument();
});

๐Ÿค Contributing

We welcome contributions! Please see our Contributing Guide for details.

๐Ÿ“„ License

MIT License

Copyright (c) 2024 Shawn Sandy

Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:

The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.

THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.

0.5.8

1 year ago

0.5.7

1 year ago

0.5.9

11 months ago

0.5.12

9 months ago

0.4.19

1 year ago

0.5.4

1 year ago

0.5.3

1 year ago

0.5.6

1 year ago

0.5.5

1 year ago

0.5.0

1 year ago

0.5.2

1 year ago

0.4.17

1 year ago

0.4.18

1 year ago

0.4.16

1 year ago

0.4.15

1 year ago

0.4.13

1 year ago

0.4.14

1 year ago

0.4.10

1 year ago

0.4.9

1 year ago

0.4.12

1 year ago

0.4.8

1 year ago

0.4.7

1 year ago

0.4.6

1 year ago

0.4.5

1 year ago

0.4.4

1 year ago