bdsa-react-components
v0.1.26
Published
Reusable React components for the Digital Slide Archive project
Downloads
367
Maintainers
Readme
BDSA React Components
A reusable React component library for the Digital Slide Archive project. This library provides a collection of well-tested, accessible, and customizable components that can be used across multiple BDSA React applications.
Features
- 🎨 Modern UI Components - Beautiful, accessible components built with React
- 📦 Tree-shakeable - Import only what you need
- 🔧 TypeScript Support - Full type definitions included
- ✅ Well-tested - Comprehensive test coverage with Vitest
- 📚 Storybook Documentation - Interactive component demos and documentation
- 🎯 Flexible - Customizable through props and CSS
Installation
In Your Project
Once published, you can install this library using npm or yarn:
npm install bdsa-react-components
# or
yarn add bdsa-react-componentsFor Development
Clone this repository and install dependencies:
git clone <repository-url>
cd bdsaReactComponents
npm installUsage
Basic Import
import { Button, Card } from 'bdsa-react-components'
import 'bdsa-react-components/styles.css'
function App() {
return (
<Card header="Welcome">
<p>Digital Slide Archive</p>
<Button variant="primary">Get Started</Button>
</Card>
)
}Individual Component Import
import { Button } from 'bdsa-react-components'
import 'bdsa-react-components/styles.css'
function MyComponent() {
return (
<Button
variant="primary"
size="large"
onClick={() => console.log('Clicked!')}
>
Click Me
</Button>
)
}Available Components
Button
A versatile button component with multiple variants and states.
<Button variant="primary" size="medium" loading={false}>
Click Me
</Button>Props:
variant: 'primary' | 'secondary' | 'danger' | 'success'size: 'small' | 'medium' | 'large'loading: booleanfullWidth: boolean- Plus all standard HTML button attributes
Card
A flexible card component for displaying content in a contained format.
<Card
header="Card Title"
footer="Footer text"
shadow="medium"
hoverable
>
Card content goes here
</Card>Props:
header: ReactNodefooter: ReactNodeshadow: 'none' | 'small' | 'medium' | 'large'bordered: booleanhoverable: booleanpadding: 'none' | 'small' | 'medium' | 'large'- Plus all standard HTML div attributes
AnnotationManager
A component for managing annotation loading, visibility, and opacity in conjunction with SlideViewer. Provides a simplified integration pattern with automatic state synchronization.
import { AnnotationManager, SlideViewer, IndexedDBAnnotationCache } from 'bdsa-react-components'
import 'bdsa-react-components/styles.css'
import { useState, useCallback, useMemo } from 'react'
function AnnotationViewer({ imageId, apiBaseUrl, dziUrl }) {
const cache = useMemo(() => new IndexedDBAnnotationCache(), [])
const [state, setState] = useState({
loadedIds: [],
opacities: new Map(),
visibility: new Map(),
})
const [headers, setHeaders] = useState(new Map())
const handleReady = useCallback((id) => console.log('Ready:', id), [])
return (
<div style={{ display: 'flex', height: '800px' }}>
<AnnotationManager
imageId={imageId}
apiBaseUrl={apiBaseUrl}
annotationCache={cache}
slideViewerOnAnnotationReady={handleReady}
onAnnotationStateChange={setState}
onAnnotationHeadersChange={setHeaders}
/>
<SlideViewer
imageInfo={{ dziUrl }}
annotationIds={state.loadedIds}
annotationOpacities={state.opacities}
annotationHeaders={headers}
onAnnotationReady={handleReady}
height="800px"
/>
</div>
)
}Key Props:
slideViewerOnAnnotationReady: Callback shared with SlideViewer (no render props needed!)onAnnotationStateChange: Unified callback that fires immediately on all state changesonAnnotationHeadersChange: Automatic headers sync for cache versioning
SlideViewer
A powerful slide viewer component that integrates OpenSeadragon with Paper.js annotations for viewing Digital Slide Archive images with annotation overlays.
import { SlideViewer } from 'bdsa-react-components'
import 'bdsa-react-components/styles.css'
function SlideApp() {
const imageInfo = {
imageId: 'slide-123',
width: 40000,
height: 30000,
tileWidth: 256,
levels: 8,
baseUrl: 'http://localhost:5000', // Your DSA base URL
}
const annotations = [
{
id: 'annotation-1',
left: 5000,
top: 6000,
width: 2000,
height: 1500,
color: '#ff0000',
label: 'Region of Interest',
},
]
return (
<div style={{ width: '100%', height: '600px' }}>
<SlideViewer
imageInfo={imageInfo}
annotations={annotations}
onAnnotationClick={(annotation) => {
console.log('Clicked:', annotation)
}}
/>
</div>
)
}Props:
imageInfo: Object containing image metadata (imageId, width, height, tileWidth, levels, baseUrl)annotations: Array of annotation objects or GeoJSON FeatureCollectiononViewerReady: Callback when OpenSeadragon viewer is readyonAnnotationClick: Callback when an annotation is clickeddefaultAnnotationColor: Default stroke color for annotations (default: '#ff0000')strokeWidth: Stroke width for annotations (default: 2)osdOptions: Additional OpenSeadragon configuration optionsclassName: Custom CSS class name
Annotation Format:
You can provide annotations in two formats:
- Array of annotation objects:
[
{
id: 'ann-1',
left: 100,
top: 200,
width: 150,
height: 100,
color: '#ff0000',
label: 'My annotation',
}
]- GeoJSON FeatureCollection:
{
type: 'FeatureCollection',
features: [
{
type: 'Feature',
id: 'geo-ann-1',
properties: {
color: '#00ff00',
label: 'GeoJSON annotation',
},
geometry: {
type: 'Polygon',
coordinates: [
[
[100, 200],
[250, 200],
[250, 300],
[100, 300],
[100, 200],
],
],
},
},
],
}Development
Running Storybook
View and interact with all components:
npm run storybookThis will open Storybook at http://localhost:6006 where you can see all components, their variants, and interactive documentation.
Running Tests
# Run tests in watch mode
npm test
# Run tests with coverage
npm run test:coverage
# Run tests with UI
npm run test:uiBuilding the Library
npm run buildThis creates optimized production builds in the dist folder with:
- ESM format (
index.js) - CommonJS format (
index.cjs) - TypeScript definitions (
index.d.ts) - Bundled CSS (
style.css)
Project Structure
bdsaReactComponents/
├── src/
│ ├── components/
│ │ ├── Button/
│ │ │ ├── Button.tsx # Component implementation
│ │ │ ├── Button.css # Component styles
│ │ │ ├── Button.test.tsx # Unit tests
│ │ │ └── Button.stories.tsx # Storybook stories
│ │ └── Card/
│ │ ├── Card.tsx
│ │ ├── Card.css
│ │ ├── Card.test.tsx
│ │ └── Card.stories.tsx
│ ├── test/
│ │ └── setup.ts # Test setup and configuration
│ └── index.ts # Main export file
├── .storybook/ # Storybook configuration
├── dist/ # Build output (generated)
├── package.json
├── tsconfig.json
├── vite.config.ts
└── vitest.config.tsAdding New Components
Follow this pattern when creating new components:
- Create component folder:
src/components/YourComponent/ - Create component file:
YourComponent.tsxwith TypeScript types - Create styles:
YourComponent.css - Create tests:
YourComponent.test.tsx - Create stories:
YourComponent.stories.tsx - Export component: Add to
src/index.ts
Example Component Template
// YourComponent.tsx
import React from 'react'
import './YourComponent.css'
export interface YourComponentProps {
/** Component props */
variant?: 'primary' | 'secondary'
children: React.ReactNode
}
export const YourComponent = React.forwardRef<HTMLDivElement, YourComponentProps>(
({ variant = 'primary', children, ...props }, ref) => {
return (
<div ref={ref} className={`bdsa-your-component bdsa-your-component--${variant}`} {...props}>
{children}
</div>
)
}
)
YourComponent.displayName = 'YourComponent'Design Principles
- Consistency: All components follow similar naming and prop conventions
- Accessibility: Components are built with a11y best practices
- Flexibility: Components accept standard HTML attributes
- Ref Forwarding: All components support ref forwarding
- TypeScript: Full type safety with exported type definitions
- Testing: Every component has comprehensive test coverage
- Documentation: Storybook stories demonstrate all use cases
Contributing
When contributing to this library:
- Follow the existing component structure
- Write tests for all new components
- Create Storybook stories for documentation
- Use TypeScript for type safety
- Follow naming conventions (prefix classes with
bdsa-) - Keep components focused and composable
CSS Naming Convention
Use the BEM-like naming convention with the bdsa- prefix:
- Block:
.bdsa-component - Element:
.bdsa-component__element - Modifier:
.bdsa-component--modifier
Example:
.bdsa-button { /* base styles */ }
.bdsa-button--primary { /* variant */ }
.bdsa-button__spinner { /* element */ }Publishing
To publish this library to npm:
- Update version in
package.json - Build the library:
npm run build - Publish:
npm publish
License
Apache-2.0
Support
For issues, questions, or contributions, please refer to the Digital Slide Archive project documentation.
