Skip to content

Commit af9f83d

Browse files
authored
Merge pull request #1 from Matdata-eu/001-advanced-table
001 advanced table
2 parents 3592ab9 + d5318d8 commit af9f83d

File tree

6 files changed

+96
-56
lines changed

6 files changed

+96
-56
lines changed

README.md

Lines changed: 21 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -7,11 +7,14 @@ High-performance YASGUI plugin for rendering SPARQL SELECT results in an interac
77
- 🚀 **Virtual Scrolling** - Efficiently handles 10,000+ rows
88
- 🔍 **Search & Filter** - Real-time search with highlighting
99
- 📊 **Interactive Columns** - Sort and resize columns
10-
- 🎨 **Theme Support** - Integrates with YASGUI themes
10+
- 🎨 **Dynamic Theme Support** - Automatically adapts to YASGUI light/dark theme changes
1111
- 📋 **Selection & Copy** - Select cells/rows and copy to clipboard
12-
- 💾 **Export** - Export to Markdown, CSV, or TSV formats
12+
- 💾 **Copy** - Copy to clipboard as Markdown, CSV, or TSV (tab-delimited) formats
13+
- 📥 **YASR Integration** - Integrated with YASR's download interface for CSV export
14+
- 💬 **Tooltips** - Hover over any cell to view full content
15+
- 🔔 **Notifications** - Visual feedback for copy operations
1316
-**Accessible** - WCAG AA compliant with keyboard navigation
14-
- 🎯 **SPARQL-Aware** - Proper rendering of URIs, literals, datatypes, and blank nodes
17+
- 🎯 **SPARQL-Aware** - Proper rendering of URIs, literals, datatypes, and blank nodes with prefix support from YASR
1518

1619
## Installation
1720

@@ -87,15 +90,15 @@ tablePlugin.on('selectionChange', (data) => {
8790
console.log('Selection:', data.range);
8891
});
8992

90-
// Listen for export events
91-
tablePlugin.on('export', (data) => {
92-
console.log(`Exported as ${data.format}`);
93+
// Listen for copy events
94+
tablePlugin.on('copy', (data) => {
95+
console.log(`Copied as ${data.format}`);
9396
});
9497

9598
// Available events:
9699
// - ready, search, columnSort, columnResize, cellDoubleClick
97100
// - selectionChange, selectionCleared, clipboardCopy
98-
// - export, layoutChange, error, destroy
101+
// - copy, layoutChange, error, destroy
99102
```
100103

101104
## Public Methods
@@ -139,7 +142,7 @@ npm install
139142
# Start development server with Vite (http://localhost:3000)
140143
npm run dev
141144

142-
# Build for production
145+
# Build for production with esbuild
143146
npm run build
144147

145148
# Run tests
@@ -162,6 +165,16 @@ The `npm run dev` command starts a Vite development server at `http://localhost:
162165

163166
The demo automatically loads the plugin from source during development for live reload.
164167

168+
### Build System
169+
170+
The project uses **esbuild** for production builds with:
171+
- UMD and ESM module formats
172+
- PostCSS for CSS processing
173+
- TypeScript type declarations
174+
- Watch mode for development (`npm run dev:build`)
175+
176+
Build outputs are generated in `dist/` with both `.umd.js` and `.esm.js` formats.
177+
165178
## License
166179

167180
MIT

package.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
{
22
"name": "@matdata/yasgui-table-plugin",
3-
"version": "1.0.0",
3+
"version": "0.1.0",
44
"description": "High-performance YASGUI plugin for rendering SPARQL SELECT results with interactive table features",
55
"type": "module",
66
"main": "dist/yasgui-table-plugin.umd.js",

specs/001-advanced-table/contracts/config-schema.md

Lines changed: 7 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -28,14 +28,16 @@ interface TabulatorPluginConfig {
2828
persistenceKey?: string;
2929
persistenceEnabled?: boolean;
3030

31-
// Export Configuration (FR-031, FR-032, FR-033)
31+
// Export Configuration (FR-029, FR-030, FR-030a)
32+
// Note: CSV download integrated with YASR's download interface (FR-031)
3233
exportFormat?: 'tsv' | 'csv' | 'markdown';
3334

3435
// Theme Configuration
3536
themeIntegration?: boolean;
3637
customTheme?: string;
3738

3839
// Prefix Configuration (for URI abbreviation)
40+
// Fetched from YASR's getPrefixes() method and merged with common prefixes
3941
prefixMap?: PrefixMap;
4042
}
4143
```
@@ -50,7 +52,7 @@ interface TabulatorPluginConfig {
5052
exportFormat: 'tsv',
5153
themeIntegration: true,
5254
customTheme: undefined,
53-
prefixMap: {} // Populated from YASQE if available
55+
prefixMap: {} // Populated from YASR's getPrefixes() merged with COMMON_PREFIXES
5456
}
5557
```
5658

@@ -318,14 +320,16 @@ if (sortState.direction && !['asc', 'desc'].includes(sortState.direction)) {
318320
```javascript
319321
{
320322
layout: 'fitData',
321-
height: '100%',
323+
height: '100%', // Not maxHeight to avoid resize loops
322324
renderVertical: 'virtual',
323325
virtualDomBuffer: 300,
324326
headerSort: true,
325327
pagination: false
326328
}
327329
```
328330

331+
**Note**: Using `maxHeight: '100%'` with virtual scrolling causes infinite resize loops. Always use `height: '100%'` instead.
332+
329333
**Validation**: Delegated to Tabulator library (will throw if invalid)
330334

331335
**Override Warning**: Setting `pagination: true` will disable virtual scrolling and may violate performance requirements (FR-004, FR-006).

specs/001-advanced-table/contracts/events.md

Lines changed: 25 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -369,31 +369,36 @@ plugin.on('configChange', (e) => {
369369
370370
---
371371
372-
## Export Events
372+
## Copy Events
373373
374-
### `export`
374+
### `copy`
375375
376-
**Fired**: When user exports table data (FR-031, FR-032, FR-033).
376+
**Fired**: When user copies table data to clipboard (FR-029, FR-030, FR-030a).
377377
378378
**Event Object**:
379379
```typescript
380-
interface ExportEvent extends BaseEvent {
381-
type: 'export';
380+
interface CopyEvent extends BaseEvent {
381+
type: 'copy';
382382
format: 'tsv' | 'csv' | 'markdown';
383-
rowCount: number; // Number of exported rows
384-
columnCount: number; // Number of exported columns
385-
dataSize: number; // Size of exported data (bytes)
383+
rowCount: number; // Number of copied rows
384+
columnCount: number; // Number of copied columns
385+
dataSize: number; // Size of copied data (bytes)
386+
success: boolean; // Whether copy succeeded
386387
}
387388
```
388389
389390
**Example**:
390391
```javascript
391-
plugin.on('export', (e) => {
392-
console.log(`Exported ${e.rowCount} rows as ${e.format} (${e.dataSize} bytes)`);
392+
plugin.on('copy', (e) => {
393+
if (e.success) {
394+
console.log(`Copied ${e.rowCount} rows as ${e.format} (${e.dataSize} bytes)`);
395+
}
393396
});
394397
```
395398
396-
**Timing**: Fired after export data generated, before download initiated
399+
**Timing**: Fired after copy operation completes
400+
401+
**Notifications**: Visual notification shown to user on success/failure
397402
398403
---
399404
@@ -427,7 +432,9 @@ plugin.on('clipboard', (e) => {
427432
- Ctrl+C / Cmd+C with selection (FR-027)
428433
- Click "Copy" button (if implemented)
429434
430-
**Browser Compatibility**: May fail in insecure contexts (non-HTTPS)
435+
**Browser Compatibility**: May fail in insecure contexts (non-HTTPS). Fallback to execCommand provided.
436+
437+
**Notifications**: Visual notification shown to user on success/failure
431438
432439
---
433440
@@ -549,10 +556,11 @@ plugin.on('search', (e) => {
549556
});
550557
});
551558

552-
plugin.on('export', (e) => {
553-
analytics.track('Table Export', {
559+
plugin.on('copy', (e) => {
560+
analytics.track('Table Copy', {
554561
format: e.format,
555-
rows: e.rowCount
562+
rows: e.rowCount,
563+
success: e.success
556564
});
557565
});
558566
```
@@ -648,8 +656,8 @@ interface SearchHighlightEvent extends BaseEvent { searchTerm, highlightedCells
648656
// Configuration events
649657
interface ConfigChangeEvent extends BaseEvent { changes, config, previousConfig }
650658

651-
// Export events
652-
interface ExportEvent extends BaseEvent { format, rowCount, columnCount, dataSize }
659+
// Copy/Export events
660+
interface CopyEvent extends BaseEvent { format, rowCount, columnCount, dataSize, success }
653661
interface ClipboardEvent extends BaseEvent { selection, format, dataSize, success }
654662

655663
// Lifecycle events

specs/001-advanced-table/quickstart.md

Lines changed: 24 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,7 @@ This guide demonstrates how to integrate the advanced table plugin with YASGUI t
1414

1515
- **YASGUI**: Version 4.x or higher
1616
- **Browser**: Chrome, Firefox, Safari, or Edge (latest 2 versions)
17-
- **Build Tool**: Webpack, Rollup, or module bundler with ES6 support
17+
- **Build Tool**: esbuild (used internally), or any module bundler with ES6 support
1818
- **Node.js**: 16+ (for development)
1919

2020
---
@@ -269,9 +269,11 @@ yasr.on('drawn', () => {
269269
console.log('Clicked:', e.value);
270270
});
271271

272-
// Monitor exports
273-
tablePlugin.on('export', (e) => {
274-
console.log(`Exported ${e.rowCount} rows as ${e.format}`);
272+
// Monitor copy operations
273+
tablePlugin.on('copy', (e) => {
274+
if (e.success) {
275+
console.log(`Copied ${e.rowCount} rows as ${e.format}`);
276+
}
275277
});
276278
});
277279
```
@@ -324,7 +326,9 @@ LIMIT 100`
324326
- Abbreviated URIs (dbr:London instead of http://dbpedia.org/resource/London)
325327
- Sortable columns (click "population" to sort)
326328
- Searchable (search for "London")
327-
- Exportable (download as CSV/TSV)
329+
- Copy to clipboard as Markdown, CSV, or TSV (tab-delimited)
330+
- Tooltips showing full cell content on hover
331+
- CSV download via YASR's download interface
328332

329333
---
330334

@@ -405,8 +409,9 @@ const yasgui = new Yasgui(document.getElementById('yasgui'), {
405409
**Features**:
406410
- Custom authentication headers
407411
- Isolated localStorage (won't conflict with other instances)
408-
- Markdown export format
412+
- Markdown export format (also supports CSV and TSV)
409413
- Full URI display
414+
- Visual notifications for copy operations
410415

411416
---
412417

@@ -487,11 +492,12 @@ yasr.on('drawn', () => {
487492
});
488493
});
489494

490-
// Track exports
491-
tablePlugin.on('export', (e) => {
492-
analytics.track('Table Export', {
495+
// Track copy operations
496+
tablePlugin.on('copy', (e) => {
497+
analytics.track('Table Copy', {
493498
format: e.format,
494-
rows: e.rowCount
499+
rows: e.rowCount,
500+
success: e.success
495501
});
496502
});
497503
});
@@ -595,11 +601,14 @@ console.log('Persistence enabled:', config.persistenceEnabled);
595601
// Check HTTPS context (Clipboard API requires secure context)
596602
console.log('Secure context:', window.isSecureContext);
597603

598-
// Fallback to execCommand on HTTP
604+
// Automatic fallback to execCommand on HTTP or when Clipboard API fails
599605
if (!window.isSecureContext) {
600-
console.warn('Clipboard API unavailable. Using legacy execCommand.');
606+
console.warn('Clipboard API unavailable. Using legacy execCommand fallback.');
601607
}
602608

609+
// Plugin automatically handles focus issues and fallbacks
610+
// Visual notifications will indicate success or failure
611+
603612
// Check browser permissions
604613
navigator.permissions.query({ name: 'clipboard-write' })
605614
.then(result => {
@@ -631,9 +640,10 @@ navigator.permissions.query({ name: 'clipboard-write' })
631640
632641
1. **Clone repository**: `git clone https://github.com/yasgui/table-plugin.git`
633642
2. **Install dependencies**: `npm install`
634-
3. **Run dev server**: `npm run dev` (opens demo at http://localhost:3000)
643+
3. **Run dev server**: `npm run dev` (opens demo at http://localhost:3000 with Vite)
635644
4. **Run tests**: `npm test`
636-
5. **Build**: `npm run build` (outputs to `dist/`)
645+
5. **Build**: `npm run build` (uses esbuild, outputs UMD and ESM to `dist/`)
646+
6. **Watch mode**: `npm run dev:build` (esbuild watch mode for incremental builds)
637647

638648
### Further Reading
639649

specs/001-advanced-table/spec.md

Lines changed: 18 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@
1111

1212
- Q: Search Highlight Color - Should search term highlighting use a hardcoded yellow color or adapt to themes? → A: Use theme-responsive highlight color (via CSS variable) that adapts to light/dark mode
1313
- Q: Ellipsized Cell Expansion Behavior - Should full content appear in overlay, inline expansion, or side panel? → A: Modal/tooltip overlay that appears above the table (preserves table layout)
14+
- Q: Theme Change Detection - How should plugin respond to YASGUI theme changes? → A: Use MutationObserver to watch data-theme attribute changes with 500ms polling fallback for dynamic theme adaptation
1415
- Q: Visual Guides During Column Resize - What type of visual guides should appear (column highlight, vertical line, measurements)? → A: Standard behavior of the library that we are going to use to implement the table
1516
- Q: Infinite Scroll Implementation Strategy - Should infinite scroll load all rows, use virtual scrolling, or batch loading? → A: Virtual scrolling (windowing) - render only visible rows plus buffer
1617
- Q: Row Number Column Behavior During Horizontal Scroll - Should row numbers be fixed/sticky, scroll with content, or use floating overlay? → A: Whatever is used by the library that we are going to implement
@@ -121,18 +122,19 @@ Users can select individual cells, ranges of cells, or entire rows, and copy sel
121122

122123
### User Story 7 - Export Functionality (Priority: P3)
123124

124-
Users can export the complete table (or filtered results) to clipboard as Markdown or CSV, and download results as CSV file.
125+
Users can export the complete table (or filtered results) to clipboard as Markdown, CSV, or TSV (tab-delimited) formats, and download results as CSV file through YASR's download interface.
125126

126-
**Why this priority**: While cell selection handles small data extraction, full table export is valuable for documentation (Markdown) and data analysis in external tools (CSV). Lower priority than core viewing and interaction features.
127+
**Why this priority**: While cell selection handles small data extraction, full table export is valuable for documentation (Markdown) and data analysis in external tools (CSV/TSV). Lower priority than core viewing and interaction features.
127128

128-
**Independent Test**: Can be fully tested by clicking export controls and verifying that clipboard receives properly formatted Markdown or CSV, and that CSV download produces a valid file.
129+
**Independent Test**: Can be fully tested by clicking export controls and verifying that clipboard receives properly formatted Markdown, CSV, or TSV, and that CSV download through YASR produces a valid file.
129130

130131
**Acceptance Scenarios**:
131132

132-
1. **Given** a table with data is displayed, **When** user clicks "Copy as Markdown", **Then** clipboard contains properly formatted Markdown table with headers and alignment
133-
2. **Given** a table with data is displayed, **When** user clicks "Copy as CSV", **Then** clipboard contains CSV format with headers and quoted fields where necessary
134-
3. **Given** a table is displayed, **When** user clicks "Download CSV", **Then** browser downloads a `.csv` file with all visible data (respecting active filters)
135-
4. **Given** a search filter is active showing 50 of 500 rows, **When** user exports or downloads, **Then** only the 50 filtered rows are included
133+
1. **Given** a table with data is displayed, **When** user clicks "Copy as Markdown", **Then** clipboard contains properly formatted Markdown table with headers and alignment, and visual notification confirms success
134+
2. **Given** a table with data is displayed, **When** user clicks "Copy as CSV", **Then** clipboard contains CSV format with headers and quoted fields where necessary, and visual notification confirms success
135+
3. **Given** a table with data is displayed, **When** user clicks "Copy as TSV", **Then** clipboard contains tab-delimited format with headers, and visual notification confirms success
136+
4. **Given** a table is displayed, **When** user uses YASR's download interface, **Then** browser downloads a `.csv` file with all visible data (respecting active filters)
137+
5. **Given** a search filter is active showing 50 of 500 rows, **When** user exports or downloads, **Then** only the 50 filtered rows are included
136138

137139
---
138140

@@ -168,6 +170,7 @@ Users can export the complete table (or filtered results) to clipboard as Markdo
168170
- **FR-010**: Plugin MUST provide a toggle control to show or hide datatype annotations on literals
169171
- **FR-011**: Plugin MUST provide an ellipsis mode control that truncates cell content with "..." when enabled
170172
- **FR-012**: Plugin MUST display full cell content in a modal or tooltip overlay when user clicks on an ellipsized cell, preserving table layout
173+
- **FR-012a**: Plugin MUST display full cell content as tooltip when user hovers over any cell
171174

172175
#### Sorting
173176
- **FR-013**: Plugin MUST allow users to sort rows by clicking on column headers
@@ -194,13 +197,14 @@ Users can export the complete table (or filtered results) to clipboard as Markdo
194197
- **FR-028**: Plugin MUST format copied data as tab-separated values (rows separated by newlines)
195198

196199
#### Export and Download
197-
- **FR-029**: Plugin MUST provide a control to copy entire table to clipboard as Markdown format
198-
- **FR-030**: Plugin MUST provide a control to copy entire table to clipboard as CSV format
199-
- **FR-031**: Plugin MUST provide a control to download table as CSV file
200+
- **FR-029**: Plugin MUST provide a control to copy entire table to clipboard as Markdown format with visual notification
201+
- **FR-030**: Plugin MUST provide a control to copy entire table to clipboard as CSV format with visual notification
202+
- **FR-030a**: Plugin MUST provide a control to copy entire table to clipboard as TSV (tab-delimited) format with visual notification
203+
- **FR-031**: Plugin MUST integrate with YASR's download interface to provide CSV download capability
200204
- **FR-032**: Plugin MUST respect active search filters when exporting or downloading
201205

202206
#### Theming
203-
- **FR-033**: Plugin MUST respond to YASGUI theme changes (light/dark mode)
207+
- **FR-033**: Plugin MUST respond to YASGUI theme changes (light/dark mode) dynamically using MutationObserver with polling fallback
204208
- **FR-034**: Plugin MUST use YASGUI CSS variables for colors, borders, and backgrounds
205209
- **FR-035**: Plugin MUST ensure text contrast meets WCAG AA standards in both themes
206210

@@ -238,8 +242,9 @@ Users can export the complete table (or filtered results) to clipboard as Markdo
238242
1. SPARQL results are provided in standard YASGUI result format (JSON bindings)
239243
2. Browser supports modern JavaScript features (ES2018) and CSS features required by YASGUI
240244
3. Users have basic familiarity with SPARQL query results and table interfaces
241-
4. Prefix definitions are available from YASQE or query context for URI abbreviation
245+
4. Prefix definitions are fetched from YASR's getPrefixes() method and merged with common prefixes for URI abbreviation
242246
5. LocalStorage is available for persisting user preferences
243-
6. Clipboard API is available for copy operations (with appropriate fallbacks)
247+
6. Clipboard API is available for copy operations (with execCommand fallback for older browsers)
244248
7. Result sets are finite (not streaming) and fit in browser memory
245249
8. The plugin is used within YASGUI/YASR environment with standard plugin lifecycle
250+
9. Build system uses esbuild for UMD and ESM module generation

0 commit comments

Comments
 (0)