npm package: @pagedotapp/page-image
Description: PageImage - A reusable React component
Author: PageStudio
Latest version: 0.0.0-alpha.14

# PageImage

A flexible image component with loading states, fallback support, and various display options.

## Installation

```bash
npm install @pagedotapp/page-image
```

## Usage

```tsx
import { PageImage } from "@pagedotapp/page-image"

function App() {
	return (
		<PageImage
			src="/path/to/image.jpg"
			alt="Description of image"
			width={400}
			height={300}
			fallback={<div>Failed to load</div>}
		/>
	)
}
```

## Props

| Prop                 | Type                           | Default      | Description                                                  |
| -------------------- | ------------------------------ | ------------ | ------------------------------------------------------------ |
| `src`                | `string`                       | -            | Image source URL (required)                                  |
| `alt`                | `string`                       | -            | Alternative text for accessibility (required)                |
| `fallback`           | `React.ReactNode`              | Default icon | Fallback content when image fails to load                    |
| `fallbackSrc`        | `string`                       | -            | Fallback image URL to try if main src fails                  |
| `width`              | `string \| number`             | -            | Width of the image container                                 |
| `height`             | `string \| number`             | -            | Height of the image container                                |
| `fit`                | `ImageFit`                     | `'cover'`    | Object fit behavior (contain, cover, fill, none, scale-down) |
| `aspectRatio`        | `ImageAspectRatio`             | `'auto'`     | Aspect ratio (auto, square, 4/3, 16/9, 21/9, 9/16, 3/4)      |
| `loading`            | `'eager' \| 'lazy'`            | `'lazy'`     | Loading strategy                                             |
| `showSkeleton`       | `boolean`                      | `true`       | Whether to show loading skeleton                             |
| `rounded`            | `boolean`                      | `false`      | Whether the image should be rounded                          |
| `circle`             | `boolean`                      | `false`      | Whether the image should be circular                         |
| `radius`             | `'sm' \| 'md' \| 'lg' \| 'xl'` | `'md'`       | Border radius size (when rounded)                            |
| `className`          | `string`                       | `''`         | Additional CSS class name for the image                      |
| `containerClassName` | `string`                       | `''`         | Additional CSS class name for the container                  |
| `onLoad`             | `function`                     | -            | Called when image loads successfully                         |
| `onError`            | `function`                     | -            | Called when image fails to load                              |
| `fadeIn`             | `boolean`                      | `true`       | Whether to fade in on load                                   |
| `onClick`            | `function`                     | -            | Click handler for the image                                  |

## Examples

### Basic Usage

```tsx
<PageImage src="https://example.com/photo.jpg" alt="Example photo" />
```

### With Dimensions and Aspect Ratio

```tsx
// Fixed dimensions
<PageImage
  src="/hero-image.jpg"
  alt="Hero image"
  width={800}
  height={400}
/>

// Aspect ratio
<PageImage
  src="/photo.jpg"
  alt="Photo"
  aspectRatio="16/9"
  width="100%"
/>

// Square image
<PageImage
  src="/avatar.jpg"
  alt="User avatar"
  aspectRatio="square"
  width={200}
/>
```

### Object Fit Options

```tsx
<PageImage
  src="/banner.jpg"
  alt="Banner"
  fit="cover"  // Default - covers entire container
  aspectRatio="21/9"
/>

<PageImage
  src="/logo.png"
  alt="Logo"
  fit="contain"  // Maintains aspect ratio within container
  width={200}
  height={100}
/>
```

### Shape Variants

```tsx
// Circular image (perfect for avatars)
<PageImage
  src="/avatar.jpg"
  alt="User avatar"
  circle
  width={100}
  height={100}
/>

// Rounded corners
<PageImage
  src="/card-image.jpg"
  alt="Card image"
  rounded
  radius="lg"
/>
```

### Loading States

```tsx
// With skeleton loader (default)
<PageImage
  src="/slow-loading.jpg"
  alt="Slow loading image"
  showSkeleton
/>

// Without skeleton loader
<PageImage
  src="/fast-loading.jpg"
  alt="Fast loading image"
  showSkeleton={false}
/>

// Eager loading for above-the-fold images
<PageImage
  src="/hero.jpg"
  alt="Hero image"
  loading="eager"
/>
```

### Error Handling

```tsx
// With custom fallback content
<PageImage
  src="/might-fail.jpg"
  alt="Image that might fail"
  fallback={
    <div style={{ padding: '2rem', textAlign: 'center' }}>
      <p>Unable to load image</p>
      <button>Retry</button>
    </div>
  }
/>

// With fallback image
<PageImage
  src="/primary-image.jpg"
  alt="Product photo"
  fallbackSrc="/placeholder.jpg"
/>

// Handle load/error events
<PageImage
  src="/tracked-image.jpg"
  alt="Tracked image"
  onLoad={() => console.log('Image loaded successfully')}
  onError={() => console.log('Image failed to load')}
/>
```

### Interactive Images

```tsx
// Clickable image with proper accessibility
<PageImage
  src="/clickable.jpg"
  alt="Click to enlarge"
  onClick={(e) => console.log('Image clicked')}
  style={{ cursor: 'pointer' }}
/>

// Image gallery item
<PageImage
  src="/gallery-item.jpg"
  alt="Gallery item"
  onClick={() => openLightbox()}
  rounded
  fadeIn
/>
```

### Advanced Examples

```tsx
// Product image with all features
<PageImage
  src={product.imageUrl}
  alt={product.name}
  fallbackSrc="/product-placeholder.jpg"
  aspectRatio="4/3"
  fit="contain"
  rounded
  radius="md"
  fadeIn
  loading="lazy"
  onClick={() => setShowZoom(true)}
  className="product-image"
  containerClassName="product-image-container"
/>

// Avatar with fallback
<PageImage
  src={user.avatarUrl}
  alt={`${user.name}'s avatar`}
  fallback={
    <div className="avatar-fallback">
      {user.name.charAt(0)}
    </div>
  }
  circle
  width={60}
  height={60}
/>

// Hero banner with specific handling
<PageImage
  src="/hero-banner.jpg"
  alt="Welcome to our site"
  aspectRatio="21/9"
  fit="cover"
  loading="eager"
  showSkeleton
  fadeIn={false}  // No fade for hero images
  onLoad={() => setHeroLoaded(true)}
/>
```

## Default Fallback

When an image fails to load and no custom fallback is provided, the component displays a default fallback with:

- A subtle image icon
- The alt text as a caption
- Proper styling to match your design

## TypeScript

The component exports the following types:

```typescript
import type {
	PageImageProps,
	ImageFit,
	ImageAspectRatio,
	ImageLoadingStrategy,
} from "@pagedotapp/page-image"
```

## Styling

The component uses CSS modules for styling. You can override styles by:

- Passing a custom `className` for the image element
- Passing a custom `containerClassName` for the container
- Targeting the component's CSS classes in your global styles

## Accessibility

- Always provide meaningful `alt` text
- When using `onClick`, the component automatically adds `role="button"` and `tabIndex={0}`
- The component maintains proper aspect ratios to prevent layout shift

## Performance

- Lazy loading is enabled by default
- Images fade in smoothly when loaded (can be disabled)
- Skeleton loader provides visual feedback during loading
- Prevents layout shift with proper aspect ratio handling

## Development

To run the component in development mode:

```bash
npm run storybook
```

To run tests:

```bash
npm run test
```

To lint the component:

```bash
npm run lint
```