bdsa-react-components 0.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +23 -0
- package/CURSOR_INTEGRATION.md +290 -0
- package/INTEGRATION.md +189 -0
- package/README.md +370 -0
- package/dist/components/AnnotationManager/AnnotationManager.d.ts +56 -0
- package/dist/components/AnnotationManager/AnnotationManager.d.ts.map +1 -0
- package/dist/components/Button/Button.d.ts +25 -0
- package/dist/components/Button/Button.d.ts.map +1 -0
- package/dist/components/Card/Card.d.ts +33 -0
- package/dist/components/Card/Card.d.ts.map +1 -0
- package/dist/components/FolderBrowser/FolderBrowser.d.ts +73 -0
- package/dist/components/FolderBrowser/FolderBrowser.d.ts.map +1 -0
- package/dist/components/SlideViewer/SlideViewer.d.ts +132 -0
- package/dist/components/SlideViewer/SlideViewer.d.ts.map +1 -0
- package/dist/index.cjs +1709 -0
- package/dist/index.cjs.map +1 -0
- package/dist/index.d.ts +11 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +23940 -0
- package/dist/index.js.map +1 -0
- package/dist/style.css +1 -0
- package/package.json +95 -0
package/README.md
ADDED
|
@@ -0,0 +1,370 @@
|
|
|
1
|
+
# BDSA React Components
|
|
2
|
+
|
|
3
|
+
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.
|
|
4
|
+
|
|
5
|
+
## Features
|
|
6
|
+
|
|
7
|
+
- 🎨 **Modern UI Components** - Beautiful, accessible components built with React
|
|
8
|
+
- 📦 **Tree-shakeable** - Import only what you need
|
|
9
|
+
- 🔧 **TypeScript Support** - Full type definitions included
|
|
10
|
+
- ✅ **Well-tested** - Comprehensive test coverage with Vitest
|
|
11
|
+
- 📚 **Storybook Documentation** - Interactive component demos and documentation
|
|
12
|
+
- 🎯 **Flexible** - Customizable through props and CSS
|
|
13
|
+
|
|
14
|
+
## Installation
|
|
15
|
+
|
|
16
|
+
### In Your Project
|
|
17
|
+
|
|
18
|
+
Once published, you can install this library using npm or yarn:
|
|
19
|
+
|
|
20
|
+
```bash
|
|
21
|
+
npm install bdsa-react-components
|
|
22
|
+
# or
|
|
23
|
+
yarn add bdsa-react-components
|
|
24
|
+
```
|
|
25
|
+
|
|
26
|
+
### For Development
|
|
27
|
+
|
|
28
|
+
Clone this repository and install dependencies:
|
|
29
|
+
|
|
30
|
+
```bash
|
|
31
|
+
git clone <repository-url>
|
|
32
|
+
cd bdsaReactComponents
|
|
33
|
+
npm install
|
|
34
|
+
```
|
|
35
|
+
|
|
36
|
+
## Usage
|
|
37
|
+
|
|
38
|
+
### Basic Import
|
|
39
|
+
|
|
40
|
+
```tsx
|
|
41
|
+
import { Button, Card } from 'bdsa-react-components'
|
|
42
|
+
import 'bdsa-react-components/styles.css'
|
|
43
|
+
|
|
44
|
+
function App() {
|
|
45
|
+
return (
|
|
46
|
+
<Card header="Welcome">
|
|
47
|
+
<p>Digital Slide Archive</p>
|
|
48
|
+
<Button variant="primary">Get Started</Button>
|
|
49
|
+
</Card>
|
|
50
|
+
)
|
|
51
|
+
}
|
|
52
|
+
```
|
|
53
|
+
|
|
54
|
+
### Individual Component Import
|
|
55
|
+
|
|
56
|
+
```tsx
|
|
57
|
+
import { Button } from 'bdsa-react-components'
|
|
58
|
+
import 'bdsa-react-components/styles.css'
|
|
59
|
+
|
|
60
|
+
function MyComponent() {
|
|
61
|
+
return (
|
|
62
|
+
<Button
|
|
63
|
+
variant="primary"
|
|
64
|
+
size="large"
|
|
65
|
+
onClick={() => console.log('Clicked!')}
|
|
66
|
+
>
|
|
67
|
+
Click Me
|
|
68
|
+
</Button>
|
|
69
|
+
)
|
|
70
|
+
}
|
|
71
|
+
```
|
|
72
|
+
|
|
73
|
+
## Available Components
|
|
74
|
+
|
|
75
|
+
### Button
|
|
76
|
+
|
|
77
|
+
A versatile button component with multiple variants and states.
|
|
78
|
+
|
|
79
|
+
```tsx
|
|
80
|
+
<Button variant="primary" size="medium" loading={false}>
|
|
81
|
+
Click Me
|
|
82
|
+
</Button>
|
|
83
|
+
```
|
|
84
|
+
|
|
85
|
+
**Props:**
|
|
86
|
+
- `variant`: 'primary' | 'secondary' | 'danger' | 'success'
|
|
87
|
+
- `size`: 'small' | 'medium' | 'large'
|
|
88
|
+
- `loading`: boolean
|
|
89
|
+
- `fullWidth`: boolean
|
|
90
|
+
- Plus all standard HTML button attributes
|
|
91
|
+
|
|
92
|
+
### Card
|
|
93
|
+
|
|
94
|
+
A flexible card component for displaying content in a contained format.
|
|
95
|
+
|
|
96
|
+
```tsx
|
|
97
|
+
<Card
|
|
98
|
+
header="Card Title"
|
|
99
|
+
footer="Footer text"
|
|
100
|
+
shadow="medium"
|
|
101
|
+
hoverable
|
|
102
|
+
>
|
|
103
|
+
Card content goes here
|
|
104
|
+
</Card>
|
|
105
|
+
```
|
|
106
|
+
|
|
107
|
+
**Props:**
|
|
108
|
+
- `header`: ReactNode
|
|
109
|
+
- `footer`: ReactNode
|
|
110
|
+
- `shadow`: 'none' | 'small' | 'medium' | 'large'
|
|
111
|
+
- `bordered`: boolean
|
|
112
|
+
- `hoverable`: boolean
|
|
113
|
+
- `padding`: 'none' | 'small' | 'medium' | 'large'
|
|
114
|
+
- Plus all standard HTML div attributes
|
|
115
|
+
|
|
116
|
+
### SlideViewer
|
|
117
|
+
|
|
118
|
+
A powerful slide viewer component that integrates OpenSeadragon with Paper.js annotations for viewing Digital Slide Archive images with annotation overlays.
|
|
119
|
+
|
|
120
|
+
```tsx
|
|
121
|
+
import { SlideViewer } from 'bdsa-react-components'
|
|
122
|
+
import 'bdsa-react-components/styles.css'
|
|
123
|
+
|
|
124
|
+
function SlideApp() {
|
|
125
|
+
const imageInfo = {
|
|
126
|
+
imageId: 'slide-123',
|
|
127
|
+
width: 40000,
|
|
128
|
+
height: 30000,
|
|
129
|
+
tileWidth: 256,
|
|
130
|
+
levels: 8,
|
|
131
|
+
baseUrl: 'http://localhost:5000', // Your DSA base URL
|
|
132
|
+
}
|
|
133
|
+
|
|
134
|
+
const annotations = [
|
|
135
|
+
{
|
|
136
|
+
id: 'annotation-1',
|
|
137
|
+
left: 5000,
|
|
138
|
+
top: 6000,
|
|
139
|
+
width: 2000,
|
|
140
|
+
height: 1500,
|
|
141
|
+
color: '#ff0000',
|
|
142
|
+
label: 'Region of Interest',
|
|
143
|
+
},
|
|
144
|
+
]
|
|
145
|
+
|
|
146
|
+
return (
|
|
147
|
+
<div style={{ width: '100%', height: '600px' }}>
|
|
148
|
+
<SlideViewer
|
|
149
|
+
imageInfo={imageInfo}
|
|
150
|
+
annotations={annotations}
|
|
151
|
+
onAnnotationClick={(annotation) => {
|
|
152
|
+
console.log('Clicked:', annotation)
|
|
153
|
+
}}
|
|
154
|
+
/>
|
|
155
|
+
</div>
|
|
156
|
+
)
|
|
157
|
+
}
|
|
158
|
+
```
|
|
159
|
+
|
|
160
|
+
**Props:**
|
|
161
|
+
- `imageInfo`: Object containing image metadata (imageId, width, height, tileWidth, levels, baseUrl)
|
|
162
|
+
- `annotations`: Array of annotation objects or GeoJSON FeatureCollection
|
|
163
|
+
- `onViewerReady`: Callback when OpenSeadragon viewer is ready
|
|
164
|
+
- `onAnnotationClick`: Callback when an annotation is clicked
|
|
165
|
+
- `defaultAnnotationColor`: Default stroke color for annotations (default: '#ff0000')
|
|
166
|
+
- `strokeWidth`: Stroke width for annotations (default: 2)
|
|
167
|
+
- `osdOptions`: Additional OpenSeadragon configuration options
|
|
168
|
+
- `className`: Custom CSS class name
|
|
169
|
+
|
|
170
|
+
**Annotation Format:**
|
|
171
|
+
|
|
172
|
+
You can provide annotations in two formats:
|
|
173
|
+
|
|
174
|
+
1. **Array of annotation objects:**
|
|
175
|
+
```tsx
|
|
176
|
+
[
|
|
177
|
+
{
|
|
178
|
+
id: 'ann-1',
|
|
179
|
+
left: 100,
|
|
180
|
+
top: 200,
|
|
181
|
+
width: 150,
|
|
182
|
+
height: 100,
|
|
183
|
+
color: '#ff0000',
|
|
184
|
+
label: 'My annotation',
|
|
185
|
+
}
|
|
186
|
+
]
|
|
187
|
+
```
|
|
188
|
+
|
|
189
|
+
2. **GeoJSON FeatureCollection:**
|
|
190
|
+
```tsx
|
|
191
|
+
{
|
|
192
|
+
type: 'FeatureCollection',
|
|
193
|
+
features: [
|
|
194
|
+
{
|
|
195
|
+
type: 'Feature',
|
|
196
|
+
id: 'geo-ann-1',
|
|
197
|
+
properties: {
|
|
198
|
+
color: '#00ff00',
|
|
199
|
+
label: 'GeoJSON annotation',
|
|
200
|
+
},
|
|
201
|
+
geometry: {
|
|
202
|
+
type: 'Polygon',
|
|
203
|
+
coordinates: [
|
|
204
|
+
[
|
|
205
|
+
[100, 200],
|
|
206
|
+
[250, 200],
|
|
207
|
+
[250, 300],
|
|
208
|
+
[100, 300],
|
|
209
|
+
[100, 200],
|
|
210
|
+
],
|
|
211
|
+
],
|
|
212
|
+
},
|
|
213
|
+
},
|
|
214
|
+
],
|
|
215
|
+
}
|
|
216
|
+
```
|
|
217
|
+
|
|
218
|
+
## Development
|
|
219
|
+
|
|
220
|
+
### Running Storybook
|
|
221
|
+
|
|
222
|
+
View and interact with all components:
|
|
223
|
+
|
|
224
|
+
```bash
|
|
225
|
+
npm run storybook
|
|
226
|
+
```
|
|
227
|
+
|
|
228
|
+
This will open Storybook at `http://localhost:6006` where you can see all components, their variants, and interactive documentation.
|
|
229
|
+
|
|
230
|
+
### Running Tests
|
|
231
|
+
|
|
232
|
+
```bash
|
|
233
|
+
# Run tests in watch mode
|
|
234
|
+
npm test
|
|
235
|
+
|
|
236
|
+
# Run tests with coverage
|
|
237
|
+
npm run test:coverage
|
|
238
|
+
|
|
239
|
+
# Run tests with UI
|
|
240
|
+
npm run test:ui
|
|
241
|
+
```
|
|
242
|
+
|
|
243
|
+
### Building the Library
|
|
244
|
+
|
|
245
|
+
```bash
|
|
246
|
+
npm run build
|
|
247
|
+
```
|
|
248
|
+
|
|
249
|
+
This creates optimized production builds in the `dist` folder with:
|
|
250
|
+
- ESM format (`index.js`)
|
|
251
|
+
- CommonJS format (`index.cjs`)
|
|
252
|
+
- TypeScript definitions (`index.d.ts`)
|
|
253
|
+
- Bundled CSS (`style.css`)
|
|
254
|
+
|
|
255
|
+
## Project Structure
|
|
256
|
+
|
|
257
|
+
```
|
|
258
|
+
bdsaReactComponents/
|
|
259
|
+
├── src/
|
|
260
|
+
│ ├── components/
|
|
261
|
+
│ │ ├── Button/
|
|
262
|
+
│ │ │ ├── Button.tsx # Component implementation
|
|
263
|
+
│ │ │ ├── Button.css # Component styles
|
|
264
|
+
│ │ │ ├── Button.test.tsx # Unit tests
|
|
265
|
+
│ │ │ └── Button.stories.tsx # Storybook stories
|
|
266
|
+
│ │ └── Card/
|
|
267
|
+
│ │ ├── Card.tsx
|
|
268
|
+
│ │ ├── Card.css
|
|
269
|
+
│ │ ├── Card.test.tsx
|
|
270
|
+
│ │ └── Card.stories.tsx
|
|
271
|
+
│ ├── test/
|
|
272
|
+
│ │ └── setup.ts # Test setup and configuration
|
|
273
|
+
│ └── index.ts # Main export file
|
|
274
|
+
├── .storybook/ # Storybook configuration
|
|
275
|
+
├── dist/ # Build output (generated)
|
|
276
|
+
├── package.json
|
|
277
|
+
├── tsconfig.json
|
|
278
|
+
├── vite.config.ts
|
|
279
|
+
└── vitest.config.ts
|
|
280
|
+
```
|
|
281
|
+
|
|
282
|
+
## Adding New Components
|
|
283
|
+
|
|
284
|
+
Follow this pattern when creating new components:
|
|
285
|
+
|
|
286
|
+
1. **Create component folder**: `src/components/YourComponent/`
|
|
287
|
+
2. **Create component file**: `YourComponent.tsx` with TypeScript types
|
|
288
|
+
3. **Create styles**: `YourComponent.css`
|
|
289
|
+
4. **Create tests**: `YourComponent.test.tsx`
|
|
290
|
+
5. **Create stories**: `YourComponent.stories.tsx`
|
|
291
|
+
6. **Export component**: Add to `src/index.ts`
|
|
292
|
+
|
|
293
|
+
### Example Component Template
|
|
294
|
+
|
|
295
|
+
```tsx
|
|
296
|
+
// YourComponent.tsx
|
|
297
|
+
import React from 'react'
|
|
298
|
+
import './YourComponent.css'
|
|
299
|
+
|
|
300
|
+
export interface YourComponentProps {
|
|
301
|
+
/** Component props */
|
|
302
|
+
variant?: 'primary' | 'secondary'
|
|
303
|
+
children: React.ReactNode
|
|
304
|
+
}
|
|
305
|
+
|
|
306
|
+
export const YourComponent = React.forwardRef<HTMLDivElement, YourComponentProps>(
|
|
307
|
+
({ variant = 'primary', children, ...props }, ref) => {
|
|
308
|
+
return (
|
|
309
|
+
<div ref={ref} className={`bdsa-your-component bdsa-your-component--${variant}`} {...props}>
|
|
310
|
+
{children}
|
|
311
|
+
</div>
|
|
312
|
+
)
|
|
313
|
+
}
|
|
314
|
+
)
|
|
315
|
+
|
|
316
|
+
YourComponent.displayName = 'YourComponent'
|
|
317
|
+
```
|
|
318
|
+
|
|
319
|
+
## Design Principles
|
|
320
|
+
|
|
321
|
+
- **Consistency**: All components follow similar naming and prop conventions
|
|
322
|
+
- **Accessibility**: Components are built with a11y best practices
|
|
323
|
+
- **Flexibility**: Components accept standard HTML attributes
|
|
324
|
+
- **Ref Forwarding**: All components support ref forwarding
|
|
325
|
+
- **TypeScript**: Full type safety with exported type definitions
|
|
326
|
+
- **Testing**: Every component has comprehensive test coverage
|
|
327
|
+
- **Documentation**: Storybook stories demonstrate all use cases
|
|
328
|
+
|
|
329
|
+
## Contributing
|
|
330
|
+
|
|
331
|
+
When contributing to this library:
|
|
332
|
+
|
|
333
|
+
1. Follow the existing component structure
|
|
334
|
+
2. Write tests for all new components
|
|
335
|
+
3. Create Storybook stories for documentation
|
|
336
|
+
4. Use TypeScript for type safety
|
|
337
|
+
5. Follow naming conventions (prefix classes with `bdsa-`)
|
|
338
|
+
6. Keep components focused and composable
|
|
339
|
+
|
|
340
|
+
## CSS Naming Convention
|
|
341
|
+
|
|
342
|
+
Use the BEM-like naming convention with the `bdsa-` prefix:
|
|
343
|
+
|
|
344
|
+
- Block: `.bdsa-component`
|
|
345
|
+
- Element: `.bdsa-component__element`
|
|
346
|
+
- Modifier: `.bdsa-component--modifier`
|
|
347
|
+
|
|
348
|
+
Example:
|
|
349
|
+
```css
|
|
350
|
+
.bdsa-button { /* base styles */ }
|
|
351
|
+
.bdsa-button--primary { /* variant */ }
|
|
352
|
+
.bdsa-button__spinner { /* element */ }
|
|
353
|
+
```
|
|
354
|
+
|
|
355
|
+
## Publishing
|
|
356
|
+
|
|
357
|
+
To publish this library to npm:
|
|
358
|
+
|
|
359
|
+
1. Update version in `package.json`
|
|
360
|
+
2. Build the library: `npm run build`
|
|
361
|
+
3. Publish: `npm publish`
|
|
362
|
+
|
|
363
|
+
## License
|
|
364
|
+
|
|
365
|
+
Apache-2.0
|
|
366
|
+
|
|
367
|
+
## Support
|
|
368
|
+
|
|
369
|
+
For issues, questions, or contributions, please refer to the Digital Slide Archive project documentation.
|
|
370
|
+
|
|
@@ -0,0 +1,56 @@
|
|
|
1
|
+
import { default as React } from 'react';
|
|
2
|
+
|
|
3
|
+
export interface AnnotationSearchResult {
|
|
4
|
+
_id: string;
|
|
5
|
+
_modelType: string;
|
|
6
|
+
_elementCount?: number;
|
|
7
|
+
_detailsCount?: number;
|
|
8
|
+
_version?: number;
|
|
9
|
+
_accessLevel?: number;
|
|
10
|
+
itemId?: string;
|
|
11
|
+
public?: boolean;
|
|
12
|
+
created?: string;
|
|
13
|
+
updated?: string;
|
|
14
|
+
creatorId?: string;
|
|
15
|
+
updatedId?: string;
|
|
16
|
+
groups?: (string | null)[];
|
|
17
|
+
annotation?: {
|
|
18
|
+
name?: string;
|
|
19
|
+
description?: string;
|
|
20
|
+
attributes?: Record<string, unknown>;
|
|
21
|
+
display?: Record<string, unknown>;
|
|
22
|
+
};
|
|
23
|
+
[key: string]: unknown;
|
|
24
|
+
}
|
|
25
|
+
export interface AnnotationManagerProps {
|
|
26
|
+
/** Image/Item ID to search annotations for */
|
|
27
|
+
imageId?: string;
|
|
28
|
+
/** Base URL for DSA API (e.g., http://bdsa.pathology.emory.edu:8080/api/v1) */
|
|
29
|
+
apiBaseUrl?: string;
|
|
30
|
+
/** Maximum number of annotations to fetch per request (default: 50) */
|
|
31
|
+
limit?: number;
|
|
32
|
+
/** Custom fetch function for API requests. Useful for adding authentication headers. */
|
|
33
|
+
fetchFn?: (url: string, options?: RequestInit) => Promise<Response>;
|
|
34
|
+
/** Custom headers to add to all API requests. Merged with fetchFn headers if both are provided. */
|
|
35
|
+
apiHeaders?: HeadersInit;
|
|
36
|
+
/** Callback when annotations are loaded */
|
|
37
|
+
onAnnotationsLoaded?: (annotations: AnnotationSearchResult[]) => void;
|
|
38
|
+
/** Callback when annotation loading fails */
|
|
39
|
+
onError?: (error: Error) => void;
|
|
40
|
+
/** Show debug panel with raw API response (default: false, hidden in production) */
|
|
41
|
+
showDebugPanel?: boolean;
|
|
42
|
+
className?: string;
|
|
43
|
+
children?: React.ReactNode;
|
|
44
|
+
}
|
|
45
|
+
/**
|
|
46
|
+
* AnnotationManager component for managing annotation loading, visibility, and state.
|
|
47
|
+
* This component handles the business logic for annotations while keeping SlideViewer
|
|
48
|
+
* focused on rendering.
|
|
49
|
+
*
|
|
50
|
+
* Supports fetching annotations by itemId using the DSA API search endpoint.
|
|
51
|
+
*
|
|
52
|
+
* Note: By default, the API may only return public annotations. To access private
|
|
53
|
+
* annotations, provide authentication via `fetchFn` or `apiHeaders` props.
|
|
54
|
+
*/
|
|
55
|
+
export declare const AnnotationManager: React.ForwardRefExoticComponent<AnnotationManagerProps & React.RefAttributes<HTMLDivElement>>;
|
|
56
|
+
//# sourceMappingURL=AnnotationManager.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"AnnotationManager.d.ts","sourceRoot":"","sources":["../../../src/components/AnnotationManager/AnnotationManager.tsx"],"names":[],"mappings":"AAAA,OAAO,KAAuC,MAAM,OAAO,CAAA;AAC3D,OAAO,yBAAyB,CAAA;AAEhC,MAAM,WAAW,sBAAsB;IACnC,GAAG,EAAE,MAAM,CAAA;IACX,UAAU,EAAE,MAAM,CAAA;IAClB,aAAa,CAAC,EAAE,MAAM,CAAA;IACtB,aAAa,CAAC,EAAE,MAAM,CAAA;IACtB,QAAQ,CAAC,EAAE,MAAM,CAAA;IACjB,YAAY,CAAC,EAAE,MAAM,CAAA;IACrB,MAAM,CAAC,EAAE,MAAM,CAAA;IACf,MAAM,CAAC,EAAE,OAAO,CAAA;IAChB,OAAO,CAAC,EAAE,MAAM,CAAA;IAChB,OAAO,CAAC,EAAE,MAAM,CAAA;IAChB,SAAS,CAAC,EAAE,MAAM,CAAA;IAClB,SAAS,CAAC,EAAE,MAAM,CAAA;IAClB,MAAM,CAAC,EAAE,CAAC,MAAM,GAAG,IAAI,CAAC,EAAE,CAAA;IAC1B,UAAU,CAAC,EAAE;QACT,IAAI,CAAC,EAAE,MAAM,CAAA;QACb,WAAW,CAAC,EAAE,MAAM,CAAA;QACpB,UAAU,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAA;QACpC,OAAO,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAA;KACpC,CAAA;IACD,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO,CAAA;CACzB;AAED,MAAM,WAAW,sBAAsB;IACnC,8CAA8C;IAC9C,OAAO,CAAC,EAAE,MAAM,CAAA;IAChB,+EAA+E;IAC/E,UAAU,CAAC,EAAE,MAAM,CAAA;IACnB,uEAAuE;IACvE,KAAK,CAAC,EAAE,MAAM,CAAA;IACd,wFAAwF;IACxF,OAAO,CAAC,EAAE,CAAC,GAAG,EAAE,MAAM,EAAE,OAAO,CAAC,EAAE,WAAW,KAAK,OAAO,CAAC,QAAQ,CAAC,CAAA;IACnE,mGAAmG;IACnG,UAAU,CAAC,EAAE,WAAW,CAAA;IACxB,2CAA2C;IAC3C,mBAAmB,CAAC,EAAE,CAAC,WAAW,EAAE,sBAAsB,EAAE,KAAK,IAAI,CAAA;IACrE,6CAA6C;IAC7C,OAAO,CAAC,EAAE,CAAC,KAAK,EAAE,KAAK,KAAK,IAAI,CAAA;IAChC,oFAAoF;IACpF,cAAc,CAAC,EAAE,OAAO,CAAA;IACxB,SAAS,CAAC,EAAE,MAAM,CAAA;IAClB,QAAQ,CAAC,EAAE,KAAK,CAAC,SAAS,CAAA;CAC7B;AAED;;;;;;;;;GASG;AACH,eAAO,MAAM,iBAAiB,+FA4I7B,CAAA"}
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
import { default as React } from 'react';
|
|
2
|
+
|
|
3
|
+
export interface ButtonProps extends React.ButtonHTMLAttributes<HTMLButtonElement> {
|
|
4
|
+
/**
|
|
5
|
+
* The variant style of the button
|
|
6
|
+
*/
|
|
7
|
+
variant?: 'primary' | 'secondary' | 'danger' | 'success';
|
|
8
|
+
/**
|
|
9
|
+
* The size of the button
|
|
10
|
+
*/
|
|
11
|
+
size?: 'small' | 'medium' | 'large';
|
|
12
|
+
/**
|
|
13
|
+
* Whether the button should take the full width of its container
|
|
14
|
+
*/
|
|
15
|
+
fullWidth?: boolean;
|
|
16
|
+
/**
|
|
17
|
+
* Whether the button is in a loading state
|
|
18
|
+
*/
|
|
19
|
+
loading?: boolean;
|
|
20
|
+
}
|
|
21
|
+
/**
|
|
22
|
+
* A versatile button component for the BDSA project
|
|
23
|
+
*/
|
|
24
|
+
export declare const Button: React.ForwardRefExoticComponent<ButtonProps & React.RefAttributes<HTMLButtonElement>>;
|
|
25
|
+
//# sourceMappingURL=Button.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"Button.d.ts","sourceRoot":"","sources":["../../../src/components/Button/Button.tsx"],"names":[],"mappings":"AAAA,OAAO,KAAK,MAAM,OAAO,CAAA;AACzB,OAAO,cAAc,CAAA;AAErB,MAAM,WAAW,WAAY,SAAQ,KAAK,CAAC,oBAAoB,CAAC,iBAAiB,CAAC;IAC9E;;OAEG;IACH,OAAO,CAAC,EAAE,SAAS,GAAG,WAAW,GAAG,QAAQ,GAAG,SAAS,CAAA;IACxD;;OAEG;IACH,IAAI,CAAC,EAAE,OAAO,GAAG,QAAQ,GAAG,OAAO,CAAA;IACnC;;OAEG;IACH,SAAS,CAAC,EAAE,OAAO,CAAA;IACnB;;OAEG;IACH,OAAO,CAAC,EAAE,OAAO,CAAA;CACpB;AAED;;GAEG;AACH,eAAO,MAAM,MAAM,uFA2ClB,CAAA"}
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
import { default as React } from 'react';
|
|
2
|
+
|
|
3
|
+
export interface CardProps extends React.HTMLAttributes<HTMLDivElement> {
|
|
4
|
+
/**
|
|
5
|
+
* Optional header content
|
|
6
|
+
*/
|
|
7
|
+
header?: React.ReactNode;
|
|
8
|
+
/**
|
|
9
|
+
* Optional footer content
|
|
10
|
+
*/
|
|
11
|
+
footer?: React.ReactNode;
|
|
12
|
+
/**
|
|
13
|
+
* Whether the card has a shadow
|
|
14
|
+
*/
|
|
15
|
+
shadow?: 'none' | 'small' | 'medium' | 'large';
|
|
16
|
+
/**
|
|
17
|
+
* Whether the card has a border
|
|
18
|
+
*/
|
|
19
|
+
bordered?: boolean;
|
|
20
|
+
/**
|
|
21
|
+
* Whether the card is hoverable (shows hover effect)
|
|
22
|
+
*/
|
|
23
|
+
hoverable?: boolean;
|
|
24
|
+
/**
|
|
25
|
+
* Padding size
|
|
26
|
+
*/
|
|
27
|
+
padding?: 'none' | 'small' | 'medium' | 'large';
|
|
28
|
+
}
|
|
29
|
+
/**
|
|
30
|
+
* A flexible card component for the BDSA project
|
|
31
|
+
*/
|
|
32
|
+
export declare const Card: React.ForwardRefExoticComponent<CardProps & React.RefAttributes<HTMLDivElement>>;
|
|
33
|
+
//# sourceMappingURL=Card.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"Card.d.ts","sourceRoot":"","sources":["../../../src/components/Card/Card.tsx"],"names":[],"mappings":"AAAA,OAAO,KAAK,MAAM,OAAO,CAAA;AACzB,OAAO,YAAY,CAAA;AAEnB,MAAM,WAAW,SAAU,SAAQ,KAAK,CAAC,cAAc,CAAC,cAAc,CAAC;IACnE;;OAEG;IACH,MAAM,CAAC,EAAE,KAAK,CAAC,SAAS,CAAA;IACxB;;OAEG;IACH,MAAM,CAAC,EAAE,KAAK,CAAC,SAAS,CAAA;IACxB;;OAEG;IACH,MAAM,CAAC,EAAE,MAAM,GAAG,OAAO,GAAG,QAAQ,GAAG,OAAO,CAAA;IAC9C;;OAEG;IACH,QAAQ,CAAC,EAAE,OAAO,CAAA;IAClB;;OAEG;IACH,SAAS,CAAC,EAAE,OAAO,CAAA;IACnB;;OAEG;IACH,OAAO,CAAC,EAAE,MAAM,GAAG,OAAO,GAAG,QAAQ,GAAG,OAAO,CAAA;CAClD;AAED;;GAEG;AACH,eAAO,MAAM,IAAI,kFAsChB,CAAA"}
|
|
@@ -0,0 +1,73 @@
|
|
|
1
|
+
import { default as React } from 'react';
|
|
2
|
+
|
|
3
|
+
export interface Collection {
|
|
4
|
+
_id: string;
|
|
5
|
+
name: string;
|
|
6
|
+
description?: string;
|
|
7
|
+
public?: boolean;
|
|
8
|
+
created?: string;
|
|
9
|
+
updated?: string;
|
|
10
|
+
[key: string]: unknown;
|
|
11
|
+
}
|
|
12
|
+
export interface Folder {
|
|
13
|
+
_id: string;
|
|
14
|
+
name: string;
|
|
15
|
+
description?: string;
|
|
16
|
+
public?: boolean;
|
|
17
|
+
created?: string;
|
|
18
|
+
updated?: string;
|
|
19
|
+
parentId?: string;
|
|
20
|
+
parentType?: 'collection' | 'folder';
|
|
21
|
+
[key: string]: unknown;
|
|
22
|
+
}
|
|
23
|
+
export type Resource = (Collection | Folder) & {
|
|
24
|
+
type: 'collection' | 'folder';
|
|
25
|
+
};
|
|
26
|
+
export interface FolderBrowserProps {
|
|
27
|
+
/** Base URL for DSA API (e.g., http://bdsa.pathology.emory.edu:8080/api/v1) */
|
|
28
|
+
apiBaseUrl?: string;
|
|
29
|
+
/** Custom fetch function for API requests. Useful for adding authentication headers. */
|
|
30
|
+
fetchFn?: (url: string, options?: RequestInit) => Promise<Response>;
|
|
31
|
+
/** Custom headers to add to all API requests. Merged with fetchFn headers if both are provided. */
|
|
32
|
+
apiHeaders?: HeadersInit;
|
|
33
|
+
/** Callback when a resource (collection or folder) is selected */
|
|
34
|
+
onResourceSelect?: (resource: Resource) => void;
|
|
35
|
+
/** Callback when resource selection changes */
|
|
36
|
+
onSelectionChange?: (resource: Resource | null) => void;
|
|
37
|
+
/** Show collections at the root level (default: true, ignored if rootId is provided) */
|
|
38
|
+
showCollections?: boolean;
|
|
39
|
+
/** Root directory ID to start from (if provided, only shows this collection/folder and its children) */
|
|
40
|
+
rootId?: string;
|
|
41
|
+
/** Type of root directory - 'collection' or 'folder' (required if rootId is provided) */
|
|
42
|
+
rootType?: 'collection' | 'folder';
|
|
43
|
+
/** Number of folders to load per page (default: 50, set to 0 to load all) */
|
|
44
|
+
foldersPerPage?: number;
|
|
45
|
+
/** Start at a specific collection ID instead of showing all collections (deprecated: use rootId and rootType) */
|
|
46
|
+
startCollectionId?: string;
|
|
47
|
+
/** Start at a specific folder ID (requires startCollectionId or parentFolderId) (deprecated: use rootId and rootType) */
|
|
48
|
+
startFolderId?: string;
|
|
49
|
+
/** Start at a folder's subfolder (requires parentFolderId) (deprecated: use rootId and rootType) */
|
|
50
|
+
parentFolderId?: string;
|
|
51
|
+
className?: string;
|
|
52
|
+
/** Custom render for collections */
|
|
53
|
+
renderCollection?: (collection: Collection, isExpanded: boolean, onToggle: () => void) => React.ReactNode;
|
|
54
|
+
/** Custom render for folders */
|
|
55
|
+
renderFolder?: (folder: Folder, depth: number, isExpanded: boolean, onToggle: () => void) => React.ReactNode;
|
|
56
|
+
}
|
|
57
|
+
/**
|
|
58
|
+
* FolderBrowser component for browsing DSA collections and folders.
|
|
59
|
+
*
|
|
60
|
+
* This component provides a tree view of collections and folders in the DSA.
|
|
61
|
+
* It supports:
|
|
62
|
+
* - Listing collections at the root
|
|
63
|
+
* - Expanding collections to show folders
|
|
64
|
+
* - Expanding folders to show subfolders recursively
|
|
65
|
+
* - Selecting collections and folders
|
|
66
|
+
*
|
|
67
|
+
* API Endpoints:
|
|
68
|
+
* - Collections: GET /api/v1/collection
|
|
69
|
+
* - Folders in collection: GET /api/v1/folder?parentType=collection&parentId={collectionId}
|
|
70
|
+
* - Subfolders: GET /api/v1/folder?parentType=folder&parentId={folderId}
|
|
71
|
+
*/
|
|
72
|
+
export declare const FolderBrowser: React.ForwardRefExoticComponent<FolderBrowserProps & React.RefAttributes<HTMLDivElement>>;
|
|
73
|
+
//# sourceMappingURL=FolderBrowser.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"FolderBrowser.d.ts","sourceRoot":"","sources":["../../../src/components/FolderBrowser/FolderBrowser.tsx"],"names":[],"mappings":"AAAA,OAAO,KAA2C,MAAM,OAAO,CAAA;AAC/D,OAAO,qBAAqB,CAAA;AAE5B,MAAM,WAAW,UAAU;IACvB,GAAG,EAAE,MAAM,CAAA;IACX,IAAI,EAAE,MAAM,CAAA;IACZ,WAAW,CAAC,EAAE,MAAM,CAAA;IACpB,MAAM,CAAC,EAAE,OAAO,CAAA;IAChB,OAAO,CAAC,EAAE,MAAM,CAAA;IAChB,OAAO,CAAC,EAAE,MAAM,CAAA;IAChB,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO,CAAA;CACzB;AAED,MAAM,WAAW,MAAM;IACnB,GAAG,EAAE,MAAM,CAAA;IACX,IAAI,EAAE,MAAM,CAAA;IACZ,WAAW,CAAC,EAAE,MAAM,CAAA;IACpB,MAAM,CAAC,EAAE,OAAO,CAAA;IAChB,OAAO,CAAC,EAAE,MAAM,CAAA;IAChB,OAAO,CAAC,EAAE,MAAM,CAAA;IAChB,QAAQ,CAAC,EAAE,MAAM,CAAA;IACjB,UAAU,CAAC,EAAE,YAAY,GAAG,QAAQ,CAAA;IACpC,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO,CAAA;CACzB;AAED,MAAM,MAAM,QAAQ,GAAG,CAAC,UAAU,GAAG,MAAM,CAAC,GAAG;IAAE,IAAI,EAAE,YAAY,GAAG,QAAQ,CAAA;CAAE,CAAA;AAEhF,MAAM,WAAW,kBAAkB;IAC/B,+EAA+E;IAC/E,UAAU,CAAC,EAAE,MAAM,CAAA;IACnB,wFAAwF;IACxF,OAAO,CAAC,EAAE,CAAC,GAAG,EAAE,MAAM,EAAE,OAAO,CAAC,EAAE,WAAW,KAAK,OAAO,CAAC,QAAQ,CAAC,CAAA;IACnE,mGAAmG;IACnG,UAAU,CAAC,EAAE,WAAW,CAAA;IACxB,kEAAkE;IAClE,gBAAgB,CAAC,EAAE,CAAC,QAAQ,EAAE,QAAQ,KAAK,IAAI,CAAA;IAC/C,+CAA+C;IAC/C,iBAAiB,CAAC,EAAE,CAAC,QAAQ,EAAE,QAAQ,GAAG,IAAI,KAAK,IAAI,CAAA;IACvD,wFAAwF;IACxF,eAAe,CAAC,EAAE,OAAO,CAAA;IACzB,wGAAwG;IACxG,MAAM,CAAC,EAAE,MAAM,CAAA;IACf,yFAAyF;IACzF,QAAQ,CAAC,EAAE,YAAY,GAAG,QAAQ,CAAA;IAClC,6EAA6E;IAC7E,cAAc,CAAC,EAAE,MAAM,CAAA;IACvB,iHAAiH;IACjH,iBAAiB,CAAC,EAAE,MAAM,CAAA;IAC1B,yHAAyH;IACzH,aAAa,CAAC,EAAE,MAAM,CAAA;IACtB,oGAAoG;IACpG,cAAc,CAAC,EAAE,MAAM,CAAA;IACvB,SAAS,CAAC,EAAE,MAAM,CAAA;IAClB,oCAAoC;IACpC,gBAAgB,CAAC,EAAE,CAAC,UAAU,EAAE,UAAU,EAAE,UAAU,EAAE,OAAO,EAAE,QAAQ,EAAE,MAAM,IAAI,KAAK,KAAK,CAAC,SAAS,CAAA;IACzG,gCAAgC;IAChC,YAAY,CAAC,EAAE,CAAC,MAAM,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,EAAE,UAAU,EAAE,OAAO,EAAE,QAAQ,EAAE,MAAM,IAAI,KAAK,KAAK,CAAC,SAAS,CAAA;CAC/G;AAED;;;;;;;;;;;;;;GAcG;AACH,eAAO,MAAM,aAAa,2FAoezB,CAAA"}
|