vs-datatable 0.1.0 → 0.2.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 CHANGED
@@ -1,2 +1,734 @@
1
- # vs-datatable
2
- A lightweight Vue 3 datatable component with sorting, slots, and nested object support.
1
+ # VsDataTable
2
+
3
+ A lightweight, feature-rich Vue 3 data table component with sorting, pagination, search, and row selection capabilities. **Completely library-independent** with extensive customization options and zero external dependencies.
4
+
5
+ ## Features
6
+
7
+ - 🔍 **Search & Filter** - Built-in search functionality with customizable search input
8
+ - 📊 **Sorting** - Multi-column sorting with visual indicators and priority support
9
+ - 📄 **Pagination** - Server-side and client-side pagination with customizable controls
10
+ - ✅ **Row Selection** - Single and multi-row selection with checkbox controls
11
+ - 🎨 **Highly Customizable** - Extensive CSS variables, themes, and slot support
12
+ - 📱 **Responsive** - Mobile-friendly design with no external dependencies
13
+ - 🚀 **Performance** - Optimized for large datasets with server-side support
14
+ - 🎯 **TypeScript** - Full TypeScript support with type definitions
15
+ - 🎭 **Zero Dependencies** - No Bootstrap, FontAwesome, or other external libraries
16
+ - 🎨 **Theme System** - Built-in themes and easy customization via CSS variables
17
+
18
+ ## Key Features
19
+
20
+ ### 🎭 **Zero Dependencies**
21
+ - No Bootstrap, FontAwesome, or other external libraries
22
+ - Completely self-contained with custom CSS
23
+ - Smaller bundle size and faster loading
24
+
25
+ ### 🎨 **Advanced Customization**
26
+ - CSS custom properties for easy theming
27
+ - Built-in theme system with multiple themes
28
+ - Component-level CSS class customization
29
+ - Flexible design system
30
+
31
+ ### 🚀 **Enhanced Performance**
32
+ - Optimized rendering with better key management
33
+ - Improved sorting and pagination
34
+ - Better memory management
35
+ - Faster initial load
36
+
37
+ ### 🛠️ **Developer Experience**
38
+ - Better TypeScript support
39
+ - More intuitive prop names
40
+ - Enhanced slot system
41
+ - Comprehensive documentation
42
+
43
+ ### 🔄 **Flexible Sorting**
44
+ - Client-side and server-side sorting support
45
+ - Multi-column sorting with priority
46
+ - Visual sort indicators with SVG icons
47
+ - v-model:sort support for reactive sorting
48
+
49
+ ## Installation
50
+
51
+ ```bash
52
+ npm install vs-datatable
53
+ # or
54
+ yarn add vs-datatable
55
+ # or
56
+ pnpm add vs-datatable
57
+ ```
58
+
59
+ ## Quick Start
60
+
61
+ ### Basic Usage
62
+
63
+ ```vue
64
+ <template>
65
+ <VsDataTable
66
+ :columns="columns"
67
+ :rows="data"
68
+ :loading="loading"
69
+ @row-click="handleRowClick"
70
+ />
71
+ </template>
72
+
73
+ <script setup lang="ts">
74
+ import { VsDataTable } from 'vs-datatable'
75
+
76
+ const columns = [
77
+ { label: 'Name', field: 'name', sortable: true },
78
+ { label: 'Email', field: 'email', sortable: true },
79
+ { label: 'Role', field: 'role', width: '20%' },
80
+ { label: 'Status', field: 'status', sortable: true }
81
+ ]
82
+
83
+ const data = [
84
+ { id: 1, name: 'John Doe', email: 'john@example.com', role: 'Admin', status: 'Active' },
85
+ { id: 2, name: 'Jane Smith', email: 'jane@example.com', role: 'User', status: 'Inactive' }
86
+ ]
87
+
88
+ const loading = ref(false)
89
+
90
+ const handleRowClick = (row: any, index: number) => {
91
+ console.log('Row clicked:', row, index)
92
+ }
93
+ </script>
94
+ ```
95
+
96
+ ### Global Registration
97
+
98
+ ```typescript
99
+ // main.ts
100
+ import { createApp } from 'vue'
101
+ import VsDataTable from 'vs-datatable'
102
+ import 'vs-datatable/style.css'
103
+
104
+ const app = createApp(App)
105
+ app.use(VsDataTable)
106
+ ```
107
+
108
+ ## Props
109
+
110
+ | Prop | Type | Default | Description |
111
+ |------|------|---------|-------------|
112
+ | `columns` | `Column[]` | **required** | Array of column definitions |
113
+ | `rows` | `any[]` | `[]` | Array of data objects |
114
+ | `loading` | `boolean` | `false` | Shows loading state |
115
+ | `showSearch` | `boolean` | `true` | Enable/disable search functionality |
116
+ | `showRowEntries` | `boolean` | `true` | Show "Showing X to Y of Z entries" |
117
+ | `itemSelected` | `any[] \| null` | `null` | Controlled selection state |
118
+ | `tablename` | `string` | `"default-table"` | Unique identifier for the table |
119
+ | `tableClass` | `string \| string[] \| Record<string, any>` | - | Custom CSS classes for table |
120
+ | `rowClass` | `string \| string[] \| Record<string, any>` | - | Custom CSS classes for rows |
121
+ | `serverOptions` | `ServerOptions \| null` | `null` | Server-side configuration |
122
+ | `serverItemsLength` | `number` | - | Total number of items for server-side pagination |
123
+ | `sort` | `Sort[]` | `[]` | Initial sort configuration |
124
+ | `containerClass` | `string \| string[] \| Record<string, any>` | - | Custom CSS classes for table container |
125
+ | `headerClass` | `string \| string[] \| Record<string, any>` | - | Custom CSS classes for table headers |
126
+ | `cellClass` | `string \| string[] \| Record<string, any>` | - | Custom CSS classes for table cells |
127
+ | `searchClass` | `string \| string[] \| Record<string, any>` | - | Custom CSS classes for search input |
128
+ | `paginationClass` | `string \| string[] \| Record<string, any>` | - | Custom CSS classes for pagination |
129
+ | `searchPlaceholder` | `string` | `'Search...'` | Placeholder text for search input |
130
+ | `loadingText` | `string` | `'Loading...'` | Text shown during loading state |
131
+ | `noDataText` | `string` | `'No data available'` | Text shown when no data |
132
+ | `noDataDescription` | `string` | `'Try adjusting your search criteria'` | Description for no data state |
133
+ | `entriesText` | `string` | `'entries'` | Text for pagination info |
134
+ | `maxVisiblePages` | `number` | `5` | Maximum visible pagination pages |
135
+ | `rowKey` | `string \| ((item: any, index: number) => string \| number)` | `'id'` | Key field for row identification |
136
+
137
+ ### Column Definition
138
+
139
+ ```typescript
140
+ interface Column {
141
+ label: string; // Display name
142
+ field: string; // Data field path (supports nested: 'user.profile.name')
143
+ width?: string; // Column width percentage
144
+ sortable?: boolean; // Enable sorting
145
+ isKey?: boolean; // Primary key field
146
+ }
147
+ ```
148
+
149
+ ### Server Options
150
+
151
+ ```typescript
152
+ interface ServerOptions {
153
+ page: number;
154
+ rowsPerPage: number;
155
+ sort?: Sort[];
156
+ }
157
+
158
+ interface Sort {
159
+ field: string;
160
+ order: 'asc' | 'desc';
161
+ priority?: number;
162
+ }
163
+ ```
164
+
165
+ ## Events
166
+
167
+ | Event | Payload | Description |
168
+ |-------|---------|-------------|
169
+ | `row-click` | `(row: any, index: number)` | Fired when a row is clicked |
170
+ | `input-typed` | `(value: string)` | Fired when search input changes |
171
+ | `page-updated` | `(page: number)` | Fired when page changes |
172
+ | `sort-changed` | `{ sort: Sort[] }` | Fired when sorting changes |
173
+ | `update:itemSelected` | `(items: any[])` | Fired when selection changes |
174
+ | `update:serverOptions` | `(options: ServerOptions)` | Fired when server options change |
175
+ | `update:serverItemsLength` | `(length: number)` | Fired when total items count changes |
176
+ | `update:sort` | `(sort: Sort[])` | v-model:sort support for reactive sorting |
177
+
178
+ ## Slots
179
+
180
+ ### Header Slots
181
+ ```vue
182
+ <template #header-name="{ column }">
183
+ <i class="fa fa-user"></i> {{ column.label }}
184
+ </template>
185
+ ```
186
+
187
+ ### Cell Slots
188
+ ```vue
189
+ <template #cell-status="{ item, value }">
190
+ <span :class="`badge bg-${value === 'Active' ? 'success' : 'danger'}`">
191
+ {{ value }}
192
+ </span>
193
+ </template>
194
+ ```
195
+
196
+ ### Custom Areas
197
+ ```vue
198
+ <template #filterArea>
199
+ <select class="form-select">
200
+ <option>Filter by status</option>
201
+ </select>
202
+ </template>
203
+
204
+ <template #no-data>
205
+ <div class="text-center">
206
+ <h4>No data found</h4>
207
+ <p>Try adjusting your search criteria</p>
208
+ </div>
209
+ </template>
210
+ ```
211
+
212
+ ## Advanced Usage
213
+
214
+ ### Server-Side Pagination & Sorting
215
+
216
+ ```vue
217
+ <template>
218
+ <VsDataTable
219
+ :columns="columns"
220
+ :rows="data"
221
+ :server-options="serverOptions"
222
+ :server-items-length="totalItems"
223
+ :loading="loading"
224
+ @update:server-options="handleServerOptionsChange"
225
+ @sort-changed="handleSortChange"
226
+ />
227
+ </template>
228
+
229
+ <script setup lang="ts">
230
+ const serverOptions = ref({
231
+ page: 1,
232
+ rowsPerPage: 10,
233
+ sort: []
234
+ })
235
+
236
+ const totalItems = ref(0)
237
+ const data = ref([])
238
+ const loading = ref(false)
239
+
240
+ const handleServerOptionsChange = async (options: ServerOptions) => {
241
+ loading.value = true
242
+ try {
243
+ const response = await fetchData(options)
244
+ data.value = response.data
245
+ totalItems.value = response.total
246
+ serverOptions.value = options
247
+ } finally {
248
+ loading.value = false
249
+ }
250
+ }
251
+
252
+ const handleSortChange = ({ sort }) => {
253
+ console.log('Sort changed:', sort)
254
+ }
255
+ </script>
256
+ ```
257
+
258
+ ### Client-Side Sorting with v-model
259
+
260
+ ```vue
261
+ <template>
262
+ <VsDataTable
263
+ :columns="columns"
264
+ :rows="data"
265
+ v-model:sort="sortState"
266
+ @sort-changed="handleSortChange"
267
+ />
268
+ </template>
269
+
270
+ <script setup lang="ts">
271
+ const sortState = ref([
272
+ { field: 'name', order: 'asc', priority: 1 }
273
+ ])
274
+
275
+ const handleSortChange = ({ sort }) => {
276
+ console.log('Sort changed:', sort)
277
+ // sortState is automatically updated via v-model:sort
278
+ }
279
+ </script>
280
+ ```
281
+
282
+ ### Row Selection
283
+
284
+ ```vue
285
+ <template>
286
+ <VsDataTable
287
+ :columns="columns"
288
+ :rows="data"
289
+ v-model:item-selected="selectedItems"
290
+ @update:item-selected="handleSelectionChange"
291
+ />
292
+ </template>
293
+
294
+ <script setup lang="ts">
295
+ const selectedItems = ref([])
296
+
297
+ const handleSelectionChange = (items: any[]) => {
298
+ console.log('Selected items:', items)
299
+ // Handle bulk operations
300
+ }
301
+ </script>
302
+ ```
303
+
304
+ ### Custom Cell Rendering
305
+
306
+ ```vue
307
+ <template>
308
+ <VsDataTable :columns="columns" :rows="data">
309
+ <!-- Custom avatar cell -->
310
+ <template #cell-avatar="{ item }">
311
+ <img :src="item.avatar" :alt="item.name" class="rounded-circle" width="32" height="32">
312
+ </template>
313
+
314
+ <!-- Custom actions cell -->
315
+ <template #cell-actions="{ item }">
316
+ <div class="btn-group btn-group-sm">
317
+ <button class="btn btn-outline-primary" @click="editItem(item)">
318
+ <i class="fa fa-edit"></i>
319
+ </button>
320
+ <button class="btn btn-outline-danger" @click="deleteItem(item)">
321
+ <i class="fa fa-trash"></i>
322
+ </button>
323
+ </div>
324
+ </template>
325
+ </VsDataTable>
326
+ </template>
327
+ ```
328
+
329
+ ### Nested Object Support
330
+
331
+ ```typescript
332
+ const columns = [
333
+ { label: 'Name', field: 'name' },
334
+ { label: 'Company', field: 'company.name' }, // Nested object
335
+ { label: 'Address', field: 'address.street' }, // Deep nesting
336
+ { label: 'Contact', field: 'contact.email' } // Multiple levels
337
+ ]
338
+
339
+ const data = [
340
+ {
341
+ id: 1,
342
+ name: 'John Doe',
343
+ company: { name: 'Acme Corp' },
344
+ address: { street: '123 Main St' },
345
+ contact: { email: 'john@acme.com' }
346
+ }
347
+ ]
348
+ ```
349
+
350
+ ### Multi-Column Sorting
351
+
352
+ ```vue
353
+ <template>
354
+ <VsDataTable
355
+ :columns="columns"
356
+ :rows="data"
357
+ v-model:sort="sortState"
358
+ @sort-changed="handleSortChange"
359
+ />
360
+ </template>
361
+
362
+ <script setup lang="ts">
363
+ const sortState = ref([
364
+ { field: 'name', order: 'asc', priority: 1 },
365
+ { field: 'age', order: 'desc', priority: 2 }
366
+ ])
367
+
368
+ const handleSortChange = ({ sort }) => {
369
+ console.log('Multi-column sort:', sort)
370
+ // Sort by name first (priority 1), then by age (priority 2)
371
+ }
372
+ </script>
373
+ ```
374
+
375
+ ### Sort Icons and Visual Indicators
376
+
377
+ The component includes built-in SVG sort icons that automatically show the current sort state:
378
+
379
+ - **Ascending**: Up arrow icon when column is sorted ascending
380
+ - **Descending**: Down arrow icon when column is sorted descending
381
+ - **Priority Badge**: Shows sort priority number for multi-column sorting
382
+ - **Hover Effects**: Visual feedback on sortable columns
383
+
384
+ ## Styling & Customization
385
+
386
+ ### CSS Variables System
387
+
388
+ VsDataTable uses CSS custom properties for easy customization. Override any variable to change the appearance:
389
+
390
+ ```css
391
+ :root {
392
+ /* Colors */
393
+ --vs-primary: #007bff;
394
+ --vs-secondary: #6c757d;
395
+ --vs-success: #28a745;
396
+ --vs-danger: #dc3545;
397
+ --vs-warning: #ffc107;
398
+ --vs-info: #17a2b8;
399
+
400
+ /* Table Colors */
401
+ --vs-table-bg: #ffffff;
402
+ --vs-table-border: #dee2e6;
403
+ --vs-table-header-bg: #f8f9fa;
404
+ --vs-table-header-color: #495057;
405
+ --vs-table-hover-bg: #f5f5f5;
406
+
407
+ /* Typography */
408
+ --vs-font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, sans-serif;
409
+ --vs-font-size: 14px;
410
+ --vs-font-weight-normal: 400;
411
+ --vs-font-weight-bold: 600;
412
+
413
+ /* Spacing */
414
+ --vs-spacing-xs: 4px;
415
+ --vs-spacing-sm: 8px;
416
+ --vs-spacing-md: 16px;
417
+ --vs-spacing-lg: 24px;
418
+ --vs-spacing-xl: 32px;
419
+
420
+ /* Border Radius */
421
+ --vs-border-radius: 4px;
422
+ --vs-border-radius-sm: 2px;
423
+ --vs-border-radius-lg: 8px;
424
+
425
+ /* Shadows */
426
+ --vs-shadow-sm: 0 1px 3px rgba(0, 0, 0, 0.1);
427
+ --vs-shadow: 0 2px 4px rgba(0, 0, 0, 0.1);
428
+ --vs-shadow-lg: 0 4px 8px rgba(0, 0, 0, 0.15);
429
+
430
+ /* Transitions */
431
+ --vs-transition: all 0.2s ease-in-out;
432
+ --vs-transition-fast: all 0.15s ease-in-out;
433
+ }
434
+ ```
435
+
436
+ ### Built-in Themes
437
+
438
+ Apply themes using CSS classes:
439
+
440
+ ```vue
441
+ <!-- Dark Theme -->
442
+ <VsDataTable class="vs-theme-dark" />
443
+
444
+ <!-- Minimal Theme -->
445
+ <VsDataTable class="vs-theme-minimal" />
446
+
447
+ <!-- Colorful Theme -->
448
+ <VsDataTable class="vs-theme-colorful" />
449
+
450
+ <!-- Corporate Theme -->
451
+ <VsDataTable class="vs-theme-corporate" />
452
+
453
+ <!-- Compact Theme -->
454
+ <VsDataTable class="vs-theme-compact" />
455
+
456
+ <!-- Rounded Theme -->
457
+ <VsDataTable class="vs-theme-rounded" />
458
+ ```
459
+
460
+ ### Custom Theme Creation
461
+
462
+ Create your own theme by extending the base styles:
463
+
464
+ ```scss
465
+ // Custom Brand Theme
466
+ .vs-datatable.vs-theme-brand {
467
+ --vs-primary: #ff6b35;
468
+ --vs-secondary: #004e89;
469
+ --vs-table-bg: #ffffff;
470
+ --vs-table-header-bg: linear-gradient(135deg, #ff6b35, #004e89);
471
+ --vs-table-header-color: #ffffff;
472
+
473
+ .vs-table-container {
474
+ border: 2px solid var(--vs-primary);
475
+ border-radius: 16px;
476
+ box-shadow: 0 8px 32px rgba(255, 107, 53, 0.2);
477
+ }
478
+
479
+ .vs-pagination-button.vs-active {
480
+ background: var(--vs-primary);
481
+ transform: scale(1.05);
482
+ }
483
+ }
484
+ ```
485
+
486
+ ### Component-Level Customization
487
+
488
+ Customize individual components with CSS classes:
489
+
490
+ ```vue
491
+ <VsDataTable
492
+ :columns="columns"
493
+ :rows="data"
494
+ container-class="my-custom-container"
495
+ table-class="my-custom-table"
496
+ header-class="my-custom-header"
497
+ cell-class="my-custom-cell"
498
+ search-class="my-custom-search"
499
+ pagination-class="my-custom-pagination"
500
+ />
501
+ ```
502
+
503
+ ### Advanced Customization
504
+
505
+ ```scss
506
+ // Custom table styling
507
+ .vs-datatable {
508
+ .vs-table {
509
+ border: 2px solid var(--vs-primary);
510
+ border-radius: 12px;
511
+ overflow: hidden;
512
+ }
513
+
514
+ .vs-table thead th {
515
+ background: linear-gradient(135deg, var(--vs-primary), var(--vs-secondary));
516
+ color: white;
517
+ font-weight: 700;
518
+ text-shadow: 0 1px 2px rgba(0, 0, 0, 0.1);
519
+ }
520
+
521
+ .vs-table tbody tr:hover {
522
+ background: linear-gradient(90deg, var(--vs-table-hover-bg), transparent);
523
+ transform: scale(1.01);
524
+ }
525
+
526
+ .vs-pagination-button {
527
+ border-radius: 50%;
528
+ transition: all 0.3s ease;
529
+
530
+ &:hover:not(:disabled) {
531
+ transform: translateY(-2px);
532
+ box-shadow: 0 4px 12px rgba(0, 0, 0, 0.15);
533
+ }
534
+
535
+ &.vs-active {
536
+ background: var(--vs-primary);
537
+ transform: scale(1.1);
538
+ }
539
+ }
540
+ }
541
+ ```
542
+
543
+ ### Import Styles
544
+
545
+ ```typescript
546
+ // Import default styles
547
+ import 'vs-datatable/style.css'
548
+
549
+ // Or import SCSS for advanced customization
550
+ import 'vs-datatable/style.scss'
551
+
552
+ // Import specific theme
553
+ import 'vs-datatable/style.css'
554
+ // Then apply theme class: <VsDataTable class="vs-theme-dark" />
555
+ ```
556
+
557
+ ## Examples
558
+
559
+ ### Complete Example with Server-Side Data
560
+
561
+ ```vue
562
+ <template>
563
+ <div class="container">
564
+ <h2>User Management</h2>
565
+
566
+ <VsDataTable
567
+ :columns="columns"
568
+ :rows="users"
569
+ :server-options="serverOptions"
570
+ :server-items-length="totalUsers"
571
+ :loading="loading"
572
+ v-model:item-selected="selectedUsers"
573
+ @update:server-options="fetchUsers"
574
+ @row-click="viewUser"
575
+ @sort-changed="handleSort"
576
+ >
577
+ <!-- Custom status cell -->
578
+ <template #cell-status="{ item }">
579
+ <span :class="`status-badge status-${getStatusColor(item.status)}`">
580
+ {{ item.status }}
581
+ </span>
582
+ </template>
583
+
584
+ <!-- Custom actions -->
585
+ <template #cell-actions="{ item }">
586
+ <button class="action-btn" @click="editUser(item)">
587
+ Edit
588
+ </button>
589
+ </template>
590
+ </VsDataTable>
591
+
592
+ <!-- Bulk actions -->
593
+ <div v-if="selectedUsers.length" class="bulk-actions">
594
+ <button class="delete-btn" @click="deleteSelected">
595
+ Delete {{ selectedUsers.length }} users
596
+ </button>
597
+ </div>
598
+ </div>
599
+ </template>
600
+
601
+ <script setup lang="ts">
602
+ import { ref, onMounted } from 'vue'
603
+ import { VsDataTable } from 'vs-datatable'
604
+
605
+ const columns = [
606
+ { label: 'ID', field: 'id', width: '10%' },
607
+ { label: 'Name', field: 'name', sortable: true },
608
+ { label: 'Email', field: 'email', sortable: true },
609
+ { label: 'Status', field: 'status', sortable: true },
610
+ { label: 'Actions', field: 'actions', width: '15%' }
611
+ ]
612
+
613
+ const users = ref([])
614
+ const selectedUsers = ref([])
615
+ const loading = ref(false)
616
+ const totalUsers = ref(0)
617
+
618
+ const serverOptions = ref({
619
+ page: 1,
620
+ rowsPerPage: 10,
621
+ sort: []
622
+ })
623
+
624
+ const fetchUsers = async (options) => {
625
+ loading.value = true
626
+ try {
627
+ const response = await api.getUsers({
628
+ page: options.page,
629
+ limit: options.rowsPerPage,
630
+ sort: options.sort
631
+ })
632
+ users.value = response.data
633
+ totalUsers.value = response.total
634
+ } finally {
635
+ loading.value = false
636
+ }
637
+ }
638
+
639
+ const handleSort = ({ sort }) => {
640
+ console.log('Sorting by:', sort)
641
+ }
642
+
643
+ const getStatusColor = (status) => {
644
+ return status === 'Active' ? 'success' : 'danger'
645
+ }
646
+
647
+ const viewUser = (user) => {
648
+ console.log('Viewing user:', user)
649
+ }
650
+
651
+ const editUser = (user) => {
652
+ console.log('Editing user:', user)
653
+ }
654
+
655
+ const deleteSelected = () => {
656
+ console.log('Deleting users:', selectedUsers.value)
657
+ }
658
+
659
+ onMounted(() => {
660
+ fetchUsers(serverOptions.value)
661
+ })
662
+ </script>
663
+
664
+ <style scoped>
665
+ .status-badge {
666
+ padding: 4px 8px;
667
+ border-radius: 4px;
668
+ font-size: 12px;
669
+ font-weight: 500;
670
+ }
671
+
672
+ .status-success {
673
+ background: #d4edda;
674
+ color: #155724;
675
+ }
676
+
677
+ .status-danger {
678
+ background: #f8d7da;
679
+ color: #721c24;
680
+ }
681
+
682
+ .action-btn {
683
+ padding: 4px 8px;
684
+ border: 1px solid #007bff;
685
+ background: transparent;
686
+ color: #007bff;
687
+ border-radius: 4px;
688
+ cursor: pointer;
689
+ }
690
+
691
+ .bulk-actions {
692
+ margin-top: 16px;
693
+ }
694
+
695
+ .delete-btn {
696
+ padding: 8px 16px;
697
+ background: #dc3545;
698
+ color: white;
699
+ border: none;
700
+ border-radius: 4px;
701
+ cursor: pointer;
702
+ }
703
+ </style>
704
+ ```
705
+
706
+ ## Browser Support
707
+
708
+ - Chrome 60+
709
+ - Firefox 60+
710
+ - Safari 12+
711
+ - Edge 79+
712
+
713
+ ## Dependencies
714
+
715
+ - Vue 3.2+ (peer dependency)
716
+ - **Zero external dependencies** - No Bootstrap, FontAwesome, or other libraries required
717
+
718
+ ## License
719
+
720
+ MIT License - see [LICENSE](LICENSE) file for details.
721
+
722
+ ## Contributing
723
+
724
+ 1. Fork the repository
725
+ 2. Create your feature branch (`git checkout -b feature/amazing-feature`)
726
+ 3. Commit your changes (`git commit -m 'Add some amazing feature'`)
727
+ 4. Push to the branch (`git push origin feature/amazing-feature`)
728
+ 5. Open a Pull Request
729
+
730
+ ## Support
731
+
732
+ - 📧 Email: [oregunwasegun@gmail.com]
733
+ - 🐛 Issues: [GitHub Issues](https://github.com/oregs/vs-datatable/issues)
734
+ - 📖 Documentation: [GitHub Wiki](https://github.com/oregs/vs-datatable/wiki)