table-minimap 1.0.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/README.md ADDED
@@ -0,0 +1,668 @@
1
+ # Table Minimap
2
+
3
+ A framework-agnostic minimap component for navigating large HTML tables. Inspired by VS Code's minimap, this library provides a visual overview of wide tables and enables drag-to-scroll navigation.
4
+
5
+ ![npm version](https://img.shields.io/npm/v/table-minimap)
6
+ ![bundle size](https://img.shields.io/bundlephobia/minzip/table-minimap)
7
+ ![license](https://img.shields.io/npm/l/table-minimap)
8
+
9
+ ## Features
10
+
11
+ - 🎯 **Framework Agnostic** - Works with vanilla JS, React, Vue, Angular, or any framework
12
+ - 📦 **Zero Dependencies** - No external runtime dependencies
13
+ - 🌳 **Tree Shakable** - ESM + CommonJS outputs
14
+ - 🎨 **Two Render Modes** - Simple columns or VS Code-like canvas preview
15
+ - 📱 **Touch Support** - Mouse, touch, and pointer events
16
+ - 🔄 **Auto Updates** - Responds to resize, scroll, and DOM mutations
17
+ - ♿ **Accessible** - ARIA attributes and keyboard navigation support
18
+ - 🎭 **Themeable** - CSS custom properties for easy customization
19
+ - 🎨 **shadcn/ui Ready** - Dedicated theme using shadcn CSS variables
20
+ - 📏 **TypeScript** - Fully typed with declaration files
21
+
22
+ ## Installation
23
+
24
+ ```bash
25
+ npm install table-minimap
26
+ ```
27
+
28
+ ```bash
29
+ yarn add table-minimap
30
+ ```
31
+
32
+ ```bash
33
+ pnpm add table-minimap
34
+ ```
35
+
36
+ ## Quick Start
37
+
38
+ ```typescript
39
+ import { TableMinimap } from 'table-minimap';
40
+ import 'table-minimap/style.css';
41
+
42
+ // Using a CSS selector
43
+ const minimap = new TableMinimap('#my-table');
44
+
45
+ // Or using a DOM element
46
+ const table = document.querySelector('table');
47
+ const minimap = new TableMinimap(table);
48
+
49
+ // Don't forget to cleanup when done
50
+ minimap.destroy();
51
+ ```
52
+
53
+ ## Usage
54
+
55
+ ### Basic Usage
56
+
57
+ ```html
58
+ <div class="table-container" style="overflow-x: auto;">
59
+ <table id="my-table">
60
+ <thead>
61
+ <tr>
62
+ <th>Column 1</th>
63
+ <th>Column 2</th>
64
+ <!-- ... more columns ... -->
65
+ </tr>
66
+ </thead>
67
+ <tbody>
68
+ <!-- ... rows ... -->
69
+ </tbody>
70
+ </table>
71
+ </div>
72
+ <!-- Minimap will be inserted after the container -->
73
+ ```
74
+
75
+ ```typescript
76
+ import { TableMinimap } from 'table-minimap';
77
+ import 'table-minimap/style.css';
78
+
79
+ const minimap = new TableMinimap('#my-table');
80
+ ```
81
+
82
+ ### With Configuration
83
+
84
+ ```typescript
85
+ const minimap = new TableMinimap('#my-table', {
86
+ mode: 'canvas', // 'columns' | 'canvas'
87
+ height: 50, // Height in pixels
88
+ position: 'bottom', // 'top' | 'bottom'
89
+ draggable: true, // Enable drag navigation
90
+ showViewport: true, // Show viewport indicator
91
+ });
92
+ ```
93
+
94
+ ### Canvas Mode (VS Code-like)
95
+
96
+ Canvas mode renders a compressed pixel preview of the entire table:
97
+
98
+ ```typescript
99
+ const minimap = new TableMinimap('#data-table', {
100
+ mode: 'canvas',
101
+ height: 60,
102
+ });
103
+ ```
104
+
105
+ - Darker pixels indicate cells with more content
106
+ - Empty cells appear lighter
107
+ - Provides a visual "density map" of your data
108
+
109
+ ### Canvas Mode with Zoom
110
+
111
+ Enable zoom functionality in canvas mode for detailed inspection:
112
+
113
+ ```typescript
114
+ const minimap = new TableMinimap('#data-table', {
115
+ mode: 'canvas',
116
+ height: 80,
117
+ zoomable: true,
118
+ minZoom: 1,
119
+ maxZoom: 10,
120
+ zoomSpeed: 0.1,
121
+ });
122
+
123
+ // Programmatic zoom control
124
+ minimap.setZoom(3, 0.5); // Zoom to 3x at center
125
+ minimap.zoomToColumns(5, 15); // Zoom to columns 5-15
126
+ minimap.resetZoom(); // Reset to full view
127
+ ```
128
+
129
+ **Zoom Controls:**
130
+ - **Scroll wheel** on minimap to zoom in/out
131
+ - **Drag** the canvas when zoomed to pan
132
+ - A position indicator appears at the bottom when zoomed
133
+
134
+ ### Position Options
135
+
136
+ ```typescript
137
+ // Minimap above the table
138
+ const minimap = new TableMinimap('#my-table', {
139
+ position: 'top',
140
+ });
141
+
142
+ // Minimap below the table (default)
143
+ const minimap = new TableMinimap('#my-table', {
144
+ position: 'bottom',
145
+ });
146
+ ```
147
+
148
+ ## Configuration
149
+
150
+ ### Options Interface
151
+
152
+ ```typescript
153
+ interface TableMinimapOptions {
154
+ /**
155
+ * Rendering mode
156
+ * - "columns": Simple column segments (default)
157
+ * - "canvas": VS Code-like pixel preview
158
+ */
159
+ mode?: 'columns' | 'canvas';
160
+
161
+ /**
162
+ * Height of the minimap in pixels
163
+ * @default 40
164
+ */
165
+ height?: number;
166
+
167
+ /**
168
+ * Position relative to the table
169
+ * @default "bottom"
170
+ */
171
+ position?: 'top' | 'bottom';
172
+
173
+ /**
174
+ * Enable drag navigation
175
+ * @default true
176
+ */
177
+ draggable?: boolean;
178
+
179
+ /**
180
+ * Show viewport indicator
181
+ * @default true
182
+ */
183
+ showViewport?: boolean;
184
+
185
+ /**
186
+ * Enable zoom in canvas mode (scroll wheel)
187
+ * @default false
188
+ */
189
+ zoomable?: boolean;
190
+
191
+ /**
192
+ * Minimum zoom level
193
+ * @default 1
194
+ */
195
+ minZoom?: number;
196
+
197
+ /**
198
+ * Maximum zoom level
199
+ * @default 10
200
+ */
201
+ maxZoom?: number;
202
+
203
+ /**
204
+ * Zoom speed multiplier
205
+ * @default 0.1
206
+ */
207
+ zoomSpeed?: number;
208
+ }
209
+ ```
210
+
211
+ ### Default Values
212
+
213
+ | Option | Default |
214
+ |--------|---------|
215
+ | `mode` | `'columns'` |
216
+ | `height` | `40` |
217
+ | `position` | `'bottom'` |
218
+ | `draggable` | `true` |
219
+ | `showViewport` | `true` |
220
+ | `zoomable` | `false` |
221
+ | `minZoom` | `1` |
222
+ | `maxZoom` | `10` |
223
+ | `zoomSpeed` | `0.1` |
224
+
225
+ ## API Reference
226
+
227
+ ### Constructor
228
+
229
+ ```typescript
230
+ new TableMinimap(selector: string | HTMLTableElement, options?: TableMinimapOptions)
231
+ ```
232
+
233
+ **Parameters:**
234
+ - `selector` - CSS selector string or HTMLTableElement
235
+ - `options` - Optional configuration object
236
+
237
+ **Throws:**
238
+ - Error if element is not found
239
+ - Error if element is not a `<table>`
240
+
241
+ ### Methods
242
+
243
+ #### `destroy(): void`
244
+
245
+ Removes the minimap and cleans up all event listeners, observers, and DOM elements. Always call this when the table is removed from the DOM.
246
+
247
+ ```typescript
248
+ minimap.destroy();
249
+ ```
250
+
251
+ #### `refresh(): void`
252
+
253
+ Forces a refresh of the minimap. Useful after programmatic table modifications.
254
+
255
+ ```typescript
256
+ // After dynamically updating table content
257
+ minimap.refresh();
258
+ ```
259
+
260
+ #### `getScrollState(): ScrollState`
261
+
262
+ Returns the current scroll state.
263
+
264
+ ```typescript
265
+ const state = minimap.getScrollState();
266
+ console.log(state);
267
+ // {
268
+ // scrollLeft: 200,
269
+ // scrollWidth: 2000,
270
+ // clientWidth: 500,
271
+ // viewportRatio: 0.25,
272
+ // positionRatio: 0.13
273
+ // }
274
+ ```
275
+
276
+ #### `getColumns(): ColumnInfo[]`
277
+
278
+ Returns information about detected columns.
279
+
280
+ ```typescript
281
+ const columns = minimap.getColumns();
282
+ console.log(columns);
283
+ // [
284
+ // { index: 0, width: 120, widthPercent: 6 },
285
+ // { index: 1, width: 80, widthPercent: 4 },
286
+ // ...
287
+ // ]
288
+ ```
289
+
290
+ #### `scrollToColumn(columnIndex: number, smooth?: boolean): void`
291
+
292
+ Scrolls the table to bring a specific column into view.
293
+
294
+ ```typescript
295
+ // Scroll to column 10 with smooth animation
296
+ minimap.scrollToColumn(10, true);
297
+
298
+ // Instant scroll
299
+ minimap.scrollToColumn(10, false);
300
+ ```
301
+
302
+ #### `getZoomState(): ZoomState`
303
+
304
+ Returns the current zoom state (canvas mode only).
305
+
306
+ ```typescript
307
+ const zoom = minimap.getZoomState();
308
+ console.log(zoom);
309
+ // {
310
+ // level: 2.5,
311
+ // panX: 0.3,
312
+ // isMinZoom: false,
313
+ // isMaxZoom: false
314
+ // }
315
+ ```
316
+
317
+ #### `setZoom(level: number, panX?: number): void`
318
+
319
+ Sets the zoom level programmatically (canvas mode only).
320
+
321
+ ```typescript
322
+ // Zoom to 3x at current position
323
+ minimap.setZoom(3);
324
+
325
+ // Zoom to 5x centered at 50% of table width
326
+ minimap.setZoom(5, 0.5);
327
+ ```
328
+
329
+ #### `resetZoom(): void`
330
+
331
+ Resets zoom to show the full table overview.
332
+
333
+ ```typescript
334
+ minimap.resetZoom();
335
+ ```
336
+
337
+ #### `zoomToColumns(startCol: number, endCol: number): void`
338
+
339
+ Zooms to show a specific column range (canvas mode only).
340
+
341
+ ```typescript
342
+ // Zoom to show columns 10-20
343
+ minimap.zoomToColumns(10, 20);
344
+ ```
345
+
346
+ ## Styling
347
+
348
+ ### CSS Custom Properties
349
+
350
+ Override these CSS variables to customize the minimap appearance:
351
+
352
+ ```css
353
+ :root {
354
+ --tm-background: #f5f5f5;
355
+ --tm-border: #e0e0e0;
356
+ --tm-viewport-color: rgba(0, 120, 212, 0.3);
357
+ --tm-viewport-border: rgba(0, 120, 212, 0.8);
358
+ --tm-height: 40px;
359
+ --tm-column-color: #d0d0d0;
360
+ --tm-column-gap: 1px;
361
+ --tm-border-radius: 4px;
362
+ --tm-canvas-empty: #f0f0f0;
363
+ --tm-canvas-filled: #606060;
364
+ }
365
+ ```
366
+
367
+ ### Dark Mode
368
+
369
+ The library automatically supports `prefers-color-scheme: dark`:
370
+
371
+ ```css
372
+ @media (prefers-color-scheme: dark) {
373
+ :root {
374
+ --tm-background: #2d2d2d;
375
+ --tm-border: #404040;
376
+ --tm-viewport-color: rgba(100, 180, 255, 0.25);
377
+ --tm-viewport-border: rgba(100, 180, 255, 0.7);
378
+ --tm-column-color: #505050;
379
+ --tm-canvas-empty: #3a3a3a;
380
+ --tm-canvas-filled: #a0a0a0;
381
+ }
382
+ }
383
+ ```
384
+
385
+ ### CSS Classes
386
+
387
+ | Class | Description |
388
+ |-------|-------------|
389
+ | `.tm-minimap` | Main container |
390
+ | `.tm-minimap--top` | Applied when position is 'top' |
391
+ | `.tm-minimap--bottom` | Applied when position is 'bottom' |
392
+ | `.tm-columns` | Columns container (columns mode) |
393
+ | `.tm-column` | Individual column segment |
394
+ | `.tm-canvas` | Canvas element (canvas mode) |
395
+ | `.tm-viewport` | Viewport indicator |
396
+ | `.tm-viewport--dragging` | Applied during drag |
397
+ | `.tm-viewport--disabled` | Applied when draggable is false |
398
+
399
+ ### Custom Theme Example
400
+
401
+ ```css
402
+ /* Blue theme */
403
+ .tm-minimap {
404
+ --tm-background: #e3f2fd;
405
+ --tm-border: #bbdefb;
406
+ --tm-viewport-color: rgba(25, 118, 210, 0.3);
407
+ --tm-viewport-border: #1976d2;
408
+ --tm-column-color: #90caf9;
409
+ }
410
+ ```
411
+
412
+ ### shadcn/ui Integration
413
+
414
+ For projects using [shadcn/ui](https://ui.shadcn.com/), import the dedicated stylesheet that uses shadcn's CSS variables:
415
+
416
+ ```typescript
417
+ import { TableMinimap } from 'table-minimap';
418
+ import 'table-minimap/shadcn.css'; // Use shadcn theme instead of style.css
419
+
420
+ const minimap = new TableMinimap('#my-table');
421
+ ```
422
+
423
+ The shadcn theme automatically uses your project's color scheme:
424
+
425
+ | Minimap Variable | shadcn Variable |
426
+ |------------------|-----------------|
427
+ | `--tm-background` | `--muted` |
428
+ | `--tm-border` | `--border` |
429
+ | `--tm-viewport-color` | `--primary` (with opacity) |
430
+ | `--tm-viewport-border` | `--primary` |
431
+ | `--tm-column-color` | `--muted-foreground` |
432
+ | `--tm-border-radius` | `--radius` |
433
+
434
+ This ensures the minimap matches your shadcn/ui theme including dark mode support.
435
+
436
+ #### shadcn/ui + React Example
437
+
438
+ ```tsx
439
+ 'use client';
440
+
441
+ import { useEffect, useRef } from 'react';
442
+ import { TableMinimap } from 'table-minimap';
443
+ import 'table-minimap/shadcn.css';
444
+
445
+ import {
446
+ Table,
447
+ TableBody,
448
+ TableCell,
449
+ TableHead,
450
+ TableHeader,
451
+ TableRow,
452
+ } from '@/components/ui/table';
453
+
454
+ export function DataTableWithMinimap({ data }: { data: any[] }) {
455
+ const containerRef = useRef<HTMLDivElement>(null);
456
+ const minimapRef = useRef<TableMinimap | null>(null);
457
+
458
+ useEffect(() => {
459
+ const table = containerRef.current?.querySelector('table');
460
+ if (table) {
461
+ minimapRef.current = new TableMinimap(table as HTMLTableElement, {
462
+ mode: 'columns',
463
+ height: 36,
464
+ });
465
+ }
466
+
467
+ return () => {
468
+ minimapRef.current?.destroy();
469
+ };
470
+ }, []);
471
+
472
+ return (
473
+ <div ref={containerRef} className="overflow-x-auto rounded-md border">
474
+ <Table>
475
+ <TableHeader>
476
+ <TableRow>
477
+ {/* Your headers */}
478
+ </TableRow>
479
+ </TableHeader>
480
+ <TableBody>
481
+ {/* Your rows */}
482
+ </TableBody>
483
+ </Table>
484
+ </div>
485
+ );
486
+ }
487
+ ```
488
+
489
+ ## Framework Integration
490
+
491
+ ### React
492
+
493
+ ```tsx
494
+ import { useEffect, useRef } from 'react';
495
+ import { TableMinimap } from 'table-minimap';
496
+ import 'table-minimap/style.css';
497
+
498
+ function DataTable() {
499
+ const tableRef = useRef<HTMLTableElement>(null);
500
+ const minimapRef = useRef<TableMinimap | null>(null);
501
+
502
+ useEffect(() => {
503
+ if (tableRef.current) {
504
+ minimapRef.current = new TableMinimap(tableRef.current);
505
+ }
506
+
507
+ return () => {
508
+ minimapRef.current?.destroy();
509
+ };
510
+ }, []);
511
+
512
+ return (
513
+ <div style={{ overflowX: 'auto' }}>
514
+ <table ref={tableRef}>
515
+ {/* ... */}
516
+ </table>
517
+ </div>
518
+ );
519
+ }
520
+ ```
521
+
522
+ ### Vue 3
523
+
524
+ ```vue
525
+ <script setup lang="ts">
526
+ import { ref, onMounted, onUnmounted } from 'vue';
527
+ import { TableMinimap } from 'table-minimap';
528
+ import 'table-minimap/style.css';
529
+
530
+ const tableRef = ref<HTMLTableElement | null>(null);
531
+ let minimap: TableMinimap | null = null;
532
+
533
+ onMounted(() => {
534
+ if (tableRef.value) {
535
+ minimap = new TableMinimap(tableRef.value);
536
+ }
537
+ });
538
+
539
+ onUnmounted(() => {
540
+ minimap?.destroy();
541
+ });
542
+ </script>
543
+
544
+ <template>
545
+ <div style="overflow-x: auto;">
546
+ <table ref="tableRef">
547
+ <!-- ... -->
548
+ </table>
549
+ </div>
550
+ </template>
551
+ ```
552
+
553
+ ### Angular
554
+
555
+ ```typescript
556
+ import { Component, ElementRef, ViewChild, AfterViewInit, OnDestroy } from '@angular/core';
557
+ import { TableMinimap } from 'table-minimap';
558
+ import 'table-minimap/style.css';
559
+
560
+ @Component({
561
+ selector: 'app-data-table',
562
+ template: `
563
+ <div style="overflow-x: auto;">
564
+ <table #tableElement>
565
+ <!-- ... -->
566
+ </table>
567
+ </div>
568
+ `
569
+ })
570
+ export class DataTableComponent implements AfterViewInit, OnDestroy {
571
+ @ViewChild('tableElement') tableRef!: ElementRef<HTMLTableElement>;
572
+ private minimap: TableMinimap | null = null;
573
+
574
+ ngAfterViewInit() {
575
+ this.minimap = new TableMinimap(this.tableRef.nativeElement);
576
+ }
577
+
578
+ ngOnDestroy() {
579
+ this.minimap?.destroy();
580
+ }
581
+ }
582
+ ```
583
+
584
+ ## Development
585
+
586
+ ### Setup
587
+
588
+ ```bash
589
+ git clone https://github.com/your-username/table-minimap.git
590
+ cd table-minimap
591
+ npm install
592
+ ```
593
+
594
+ ### Development Server
595
+
596
+ ```bash
597
+ npm run dev
598
+ ```
599
+
600
+ Opens the demo at `http://localhost:5173`
601
+
602
+ ### Build
603
+
604
+ ```bash
605
+ npm run build
606
+ ```
607
+
608
+ Outputs to `dist/`:
609
+ - `table-minimap.js` (ESM)
610
+ - `table-minimap.cjs` (CommonJS)
611
+ - `style.css`
612
+ - `index.d.ts` (TypeScript declarations)
613
+
614
+ ### Project Structure
615
+
616
+ ```
617
+ table-minimap/
618
+ ├── src/
619
+ │ ├── TableMinimap.ts # Main component class
620
+ │ ├── styles.css # Default styles
621
+ │ ├── types.ts # TypeScript interfaces
622
+ │ └── index.ts # Public exports
623
+ ├── demo/
624
+ │ ├── index.html # Demo page
625
+ │ └── main.ts # Demo script
626
+ ├── dist/ # Build output
627
+ ├── package.json
628
+ ├── tsconfig.json
629
+ ├── vite.config.ts
630
+ └── README.md
631
+ ```
632
+
633
+ ## Publishing
634
+
635
+ ```bash
636
+ # Ensure build is up to date
637
+ npm run build
638
+
639
+ # Publish to npm
640
+ npm publish
641
+ ```
642
+
643
+ ## Browser Support
644
+
645
+ - Chrome (latest)
646
+ - Firefox (latest)
647
+ - Safari (latest)
648
+ - Edge (latest)
649
+
650
+ Requires:
651
+ - `ResizeObserver`
652
+ - `MutationObserver`
653
+ - `PointerEvents`
654
+
655
+ ## License
656
+
657
+ MIT © [Your Name]
658
+
659
+ ## Contributing
660
+
661
+ Contributions are welcome! Please open an issue or submit a pull request.
662
+
663
+ 1. Fork the repository
664
+ 2. Create your feature branch (`git checkout -b feature/amazing-feature`)
665
+ 3. Commit your changes (`git commit -m 'Add amazing feature'`)
666
+ 4. Push to the branch (`git push origin feature/amazing-feature`)
667
+ 5. Open a Pull Request
668
+