vanilla-table 0.1.0 → 0.3.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
@@ -2,21 +2,21 @@
2
2
 
3
3
  > Lightweight vanilla JavaScript table library with sorting, pagination, filtering, and export capabilities
4
4
 
5
- ## 🚧 Under Active Development
5
+ [![npm version](https://badge.fury.io/js/vanilla-table.svg)](https://www.npmjs.com/package/vanilla-table)
6
+ [![License: MIT](https://img.shields.io/badge/License-MIT-yellow.svg)](https://opensource.org/licenses/MIT)
6
7
 
7
- This package is currently under active development. The full implementation is being refactored and will be available soon.
8
-
9
- ## ✨ Planned Features
8
+ ## Features
10
9
 
11
10
  - **Zero Dependencies** - Pure vanilla JavaScript, no jQuery or other libraries required
12
- - **Sorting** - Multi-column sorting with customizable sort functions
11
+ - **Sorting** - Column sorting with customizable sort functions
13
12
  - **Pagination** - Client-side pagination with configurable page sizes
14
13
  - **Filtering** - Column-based filtering with multiple filter types
15
14
  - **Search** - Global search across all columns
16
- - **Export** - Export to CSV, JSON, and Excel formats
15
+ - **Export** - Export to CSV and JSON formats
17
16
  - **Zebra Striping** - Alternating row colors for better readability
18
17
  - **Responsive** - Mobile-friendly table design
19
- - **Lightweight** - Minimal footprint, inspired by DataTables but much lighter
18
+ - **Lightweight** - Minimal footprint (~15KB minified)
19
+ - **Customizable** - Extensive configuration options and custom render functions
20
20
 
21
21
  ## 📦 Installation
22
22
 
@@ -24,30 +24,264 @@ This package is currently under active development. The full implementation is b
24
24
  npm install vanilla-table
25
25
  ```
26
26
 
27
- ## 🚀 Usage
27
+ Or use directly in the browser:
28
+
29
+ ```html
30
+ <!-- Include CSS -->
31
+ <link rel="stylesheet" href="path/to/vanilla-table/src/table.css" />
32
+
33
+ <!-- Include all JavaScript modules -->
34
+ <script src="path/to/vanilla-table/src/core.js"></script>
35
+ <script src="path/to/vanilla-table/src/render.js"></script>
36
+ <script src="path/to/vanilla-table/src/sort.js"></script>
37
+ <script src="path/to/vanilla-table/src/filters.js"></script>
38
+ <script src="path/to/vanilla-table/src/pagination.js"></script>
39
+ <script src="path/to/vanilla-table/src/exports.js"></script>
40
+ <script src="path/to/vanilla-table/index.js"></script>
41
+ ```
42
+
43
+ ## 🚀 Quick Start
44
+
45
+ ### Basic Usage
46
+
47
+ ```html
48
+ <table id="my-table">
49
+ <thead>
50
+ <tr>
51
+ <th data-field="name">Name</th>
52
+ <th data-field="email">Email</th>
53
+ <th data-field="age">Age</th>
54
+ </tr>
55
+ </thead>
56
+ <tbody></tbody>
57
+ </table>
58
+
59
+ <script>
60
+ const data = [
61
+ { name: "John Doe", email: "john@example.com", age: 30 },
62
+ { name: "Jane Smith", email: "jane@example.com", age: 25 },
63
+ { name: "Bob Johnson", email: "bob@example.com", age: 35 },
64
+ ];
65
+
66
+ const table = new VanillaTable("#my-table", {
67
+ data: data,
68
+ sorting: true,
69
+ pagination: true,
70
+ perPage: 10,
71
+ });
72
+ </script>
73
+ ```
74
+
75
+ ### With Pagination Controls
76
+
77
+ ```html
78
+ <div id="table-info"></div>
79
+ <table id="my-table">
80
+ ...
81
+ </table>
82
+ <div id="pagination"></div>
83
+
84
+ <script>
85
+ const table = new VanillaTable("#my-table", {
86
+ data: data,
87
+ pagination: true,
88
+ perPage: 10,
89
+ paginationInfo: "#table-info",
90
+ paginationControls: "#pagination",
91
+ });
92
+ </script>
93
+ ```
94
+
95
+ ### With Search
96
+
97
+ ```html
98
+ <input type="text" id="search" placeholder="Search..." />
99
+ <table id="my-table">
100
+ ...
101
+ </table>
102
+
103
+ <script>
104
+ const table = new VanillaTable("#my-table", {
105
+ data: data,
106
+ search: true,
107
+ searchInput: "#search",
108
+ });
109
+ </script>
110
+ ```
111
+
112
+ ## 📖 Configuration Options
113
+
114
+ | Option | Type | Default | Description |
115
+ | -------------------- | -------------- | --------------------- | ---------------------------------------------------- |
116
+ | `data` | Array | `[]` | Array of row objects |
117
+ | `columns` | Array | `[]` | Column configuration (optional, can infer from HTML) |
118
+ | `pagination` | Boolean | `false` | Enable pagination |
119
+ | `perPage` | Number | `25` | Rows per page |
120
+ | `paginationInfo` | String/Element | `null` | Element for pagination info text |
121
+ | `paginationControls` | String/Element | `null` | Element for pagination buttons |
122
+ | `sorting` | Boolean | `true` | Enable sorting |
123
+ | `search` | Boolean | `false` | Enable search |
124
+ | `searchInput` | String/Element | `null` | Search input element |
125
+ | `filters` | Object | `{}` | Initial filters |
126
+ | `zebra` | Boolean | `true` | Enable zebra striping |
127
+ | `noResultsText` | String | `'No results found.'` | Text when no results |
128
+
129
+ ## 🎨 Column Configuration
130
+
131
+ Columns can be configured for custom rendering and behavior:
132
+
133
+ ```javascript
134
+ const table = new VanillaTable("#my-table", {
135
+ data: data,
136
+ columns: [
137
+ {
138
+ data: "name",
139
+ title: "Full Name",
140
+ },
141
+ {
142
+ data: "salary",
143
+ title: "Salary",
144
+ render: (value) => `$${value.toLocaleString()}`,
145
+ },
146
+ {
147
+ data: "status",
148
+ title: "Status",
149
+ sortable: false, // Disable sorting for this column
150
+ },
151
+ {
152
+ data: "user.email", // Nested property access
153
+ title: "Email",
154
+ },
155
+ ],
156
+ });
157
+ ```
158
+
159
+ ## 🔧 API Methods
160
+
161
+ ### Data Management
28
162
 
29
163
  ```javascript
30
- const VanillaTable = require('vanilla-table');
164
+ // Load new data
165
+ table.loadData(newData);
166
+
167
+ // Get all data
168
+ const allData = table.getAllData();
169
+
170
+ // Get visible data (after filters/search)
171
+ const visibleData = table.getVisibleData();
172
+ ```
173
+
174
+ ### Search & Filtering
31
175
 
32
- // Full implementation coming soon
33
- const table = new VanillaTable('#my-table', {
34
- pagination: true,
35
- pageSize: 10,
36
- sorting: true,
37
- filtering: true,
38
- search: true,
39
- export: ['csv', 'json', 'excel']
176
+ ```javascript
177
+ // Search
178
+ table.search("query");
179
+
180
+ // Apply filters
181
+ table.applyFilters({
182
+ department: "Engineering",
183
+ status: ["active", "pending"], // Array of allowed values
40
184
  });
41
185
 
42
- table.init();
186
+ // Clear all filters and search
187
+ table.clearFilters();
43
188
  ```
44
189
 
45
- ## 📝 License
190
+ ### Pagination
46
191
 
47
- MIT © matejkadlec
192
+ ```javascript
193
+ // Go to specific page
194
+ table.goToPage(3);
195
+
196
+ // Set page size
197
+ table.setPageSize(50);
198
+ ```
199
+
200
+ ### Export
201
+
202
+ ```javascript
203
+ // Export to CSV
204
+ table.exportCSV("data.csv");
205
+
206
+ // Export to JSON
207
+ table.exportJSON("data.json");
208
+
209
+ // Get as string (without downloading)
210
+ const csvString = table.toCSV();
211
+ const jsonString = table.toJSON();
212
+
213
+ // Include filtered rows in export
214
+ table.exportCSV("all-data.csv", true);
215
+ ```
216
+
217
+ ### Cleanup
218
+
219
+ ```javascript
220
+ // Destroy table instance
221
+ table.destroy();
222
+ ```
223
+
224
+ ## 🎯 Advanced Examples
225
+
226
+ ### Custom Render Functions
227
+
228
+ ```javascript
229
+ const table = new VanillaTable("#my-table", {
230
+ data: data,
231
+ columns: [
232
+ {
233
+ data: "avatar",
234
+ title: "Avatar",
235
+ render: (value, row) => {
236
+ return `<img src="${value}" alt="${row.name}" style="width: 40px; border-radius: 50%;">`;
237
+ },
238
+ },
239
+ {
240
+ data: "status",
241
+ title: "Status",
242
+ render: (value) => {
243
+ const color = value === "active" ? "green" : "red";
244
+ return `<span style="color: ${color}">${value}</span>`;
245
+ },
246
+ },
247
+ ],
248
+ });
249
+ ```
250
+
251
+ ### Custom Filtering
252
+
253
+ ```javascript
254
+ // Filter with custom function
255
+ table.applyFilters({
256
+ age: (value) => value >= 18 && value <= 65,
257
+ });
258
+ ```
259
+
260
+ ### Multi-Column Sorting
261
+
262
+ Users can:
263
+
264
+ - **Click** a column header to sort by that column
265
+ - **Shift+Click** to add additional sort columns (priority indicated by numbers)
266
+
267
+ ## 📝 Example
268
+
269
+ See `example.html` for a complete working demo with all features.
48
270
 
49
271
  ## 🤝 Contributing
50
272
 
273
+ Contributions are welcome! Please feel free to submit a Pull Request.
274
+
275
+ ## 📄 License
276
+
277
+ MIT © matejkadlec
278
+
279
+ ## 🔗 Links
280
+
281
+ - [npm Package](https://www.npmjs.com/package/vanilla-table)
282
+ - [GitHub Repository](https://github.com/matejkadlec/vanilla-table)
283
+ - [Report Issues](https://github.com/matejkadlec/vanilla-table/issues)
284
+
51
285
  Contributions, issues, and feature requests are welcome once the initial implementation is complete.
52
286
 
53
287
  ## 📧 Contact
package/index.js CHANGED
@@ -1,20 +1,236 @@
1
1
  /**
2
- * vanilla-table
3
- * Lightweight vanilla JavaScript table library
4
- *
5
- * 🚧 Full implementation coming soon
2
+ * VanillaTable - Lightweight vanilla JavaScript table library
3
+ * Features: sorting, pagination, filtering, search, and export capabilities
6
4
  */
7
5
 
6
+ // Load all modules (in browser, these will be included via script tags)
7
+ // In Node.js/bundler environments, you would use actual imports
8
+
9
+ /**
10
+ * Main VanillaTable class
11
+ */
8
12
  class VanillaTable {
13
+ /**
14
+ * Create a new VanillaTable instance
15
+ * @param {string|HTMLElement} selector - CSS selector or DOM element for the table
16
+ * @param {Object} options - Configuration options
17
+ */
9
18
  constructor(selector, options = {}) {
10
- this.selector = selector;
11
- this.options = options;
12
- console.warn('vanilla-table: Full implementation coming soon. This is a placeholder release.');
19
+ // Find the table element
20
+ this.tableElement = typeof selector === 'string'
21
+ ? document.querySelector(selector)
22
+ : selector;
23
+
24
+ if (!this.tableElement) {
25
+ throw new Error('Table element not found');
26
+ }
27
+
28
+ // Default options
29
+ this.options = {
30
+ data: [], // Array of row objects
31
+ columns: [], // Column configuration
32
+ pagination: false, // Enable pagination
33
+ perPage: 25, // Rows per page
34
+ paginationInfo: null, // Element or selector for pagination info
35
+ paginationControls: null, // Element or selector for pagination controls
36
+ sorting: true, // Enable sorting
37
+ search: false, // Enable search
38
+ searchInput: null, // Element or selector for search input
39
+ filters: {}, // Initial filters
40
+ zebra: true, // Enable zebra striping
41
+ noResultsText: 'No results found.',
42
+ ...options
43
+ };
44
+
45
+ // Add vanilla-table class to the table
46
+ this.tableElement.classList.add('vanilla-table');
47
+
48
+ // Initialize core
49
+ this.core = new VanillaTableCore(this.tableElement, this.options);
50
+
51
+ // Initialize modules
52
+ this.renderer = new VanillaTableRenderer(this.core);
53
+ this.sorter = this.options.sorting ? new VanillaTableSorter(this.core, this.renderer) : null;
54
+ this.paginator = this.options.pagination ? new VanillaTablePaginator(this.core) : null;
55
+ this.filter = new VanillaTableFilter(this.core, this.renderer);
56
+ this.exporter = new VanillaTableExporter(this.core, this.renderer);
57
+
58
+ // Setup callbacks
59
+ if (this.sorter) {
60
+ this.core.onSort = () => {
61
+ if (this.paginator) this.paginator.update();
62
+ };
63
+ }
64
+
65
+ // Initialize search if enabled
66
+ if (this.options.search && this.options.searchInput) {
67
+ this.initSearch();
68
+ }
69
+
70
+ // Load initial data if provided
71
+ if (this.options.data && this.options.data.length > 0) {
72
+ this.loadData(this.options.data);
73
+ }
74
+ }
75
+
76
+ /**
77
+ * Load data into the table
78
+ * @param {Array} data - Array of row objects
79
+ */
80
+ loadData(data) {
81
+ this.renderer.renderTable(data);
82
+
83
+ if (this.sorter) {
84
+ this.sorter.init();
85
+ }
86
+
87
+ if (this.paginator) {
88
+ this.paginator.update();
89
+ }
90
+
91
+ return this;
92
+ }
93
+
94
+ /**
95
+ * Initialize search functionality
96
+ */
97
+ initSearch() {
98
+ const searchInput = typeof this.options.searchInput === 'string'
99
+ ? document.querySelector(this.options.searchInput)
100
+ : this.options.searchInput;
101
+
102
+ if (!searchInput) return;
103
+
104
+ searchInput.addEventListener('input', (e) => {
105
+ this.search(e.target.value);
106
+ });
107
+ }
108
+
109
+ /**
110
+ * Search the table
111
+ * @param {string} query - Search query
112
+ */
113
+ search(query) {
114
+ this.filter.applySearch(query);
115
+ if (this.paginator) {
116
+ this.core.state.currentPage = 1; // Reset to first page
117
+ this.paginator.update();
118
+ }
119
+ return this;
120
+ }
121
+
122
+ /**
123
+ * Apply filters to the table
124
+ * @param {Object} filters - Filter configuration
125
+ */
126
+ applyFilters(filters) {
127
+ this.filter.applyFilters(filters);
128
+ if (this.paginator) {
129
+ this.core.state.currentPage = 1; // Reset to first page
130
+ this.paginator.update();
131
+ }
132
+ return this;
13
133
  }
14
134
 
15
- init() {
16
- throw new Error('vanilla-table: Full implementation coming soon');
135
+ /**
136
+ * Clear all filters and search
137
+ */
138
+ clearFilters() {
139
+ this.filter.clearAll();
140
+ if (this.paginator) {
141
+ this.paginator.update();
142
+ }
143
+ return this;
144
+ }
145
+
146
+ /**
147
+ * Go to a specific page
148
+ * @param {number} page - Page number
149
+ */
150
+ goToPage(page) {
151
+ if (this.paginator) {
152
+ this.paginator.goToPage(page);
153
+ }
154
+ return this;
155
+ }
156
+
157
+ /**
158
+ * Set page size
159
+ * @param {number} size - Number of rows per page
160
+ */
161
+ setPageSize(size) {
162
+ this.core.state.perPage = size;
163
+ if (this.paginator) {
164
+ this.paginator.update();
165
+ }
166
+ return this;
167
+ }
168
+
169
+ /**
170
+ * Export table data to CSV
171
+ * @param {string} filename - Output filename
172
+ * @param {boolean} includeFiltered - Include filtered rows
173
+ */
174
+ exportCSV(filename = 'table.csv', includeFiltered = false) {
175
+ this.exporter.downloadCSV(filename, includeFiltered);
176
+ return this;
177
+ }
178
+
179
+ /**
180
+ * Export table data to JSON
181
+ * @param {string} filename - Output filename
182
+ * @param {boolean} includeFiltered - Include filtered rows
183
+ */
184
+ exportJSON(filename = 'table.json', includeFiltered = false) {
185
+ this.exporter.downloadJSON(filename, includeFiltered);
186
+ return this;
187
+ }
188
+
189
+ /**
190
+ * Get current table data as CSV string
191
+ * @param {boolean} includeFiltered - Include filtered rows
192
+ */
193
+ toCSV(includeFiltered = false) {
194
+ return this.exporter.toCSV(includeFiltered);
195
+ }
196
+
197
+ /**
198
+ * Get current table data as JSON string
199
+ * @param {boolean} includeFiltered - Include filtered rows
200
+ */
201
+ toJSON(includeFiltered = false) {
202
+ return this.exporter.toJSON(includeFiltered);
203
+ }
204
+
205
+ /**
206
+ * Get visible data
207
+ */
208
+ getVisibleData() {
209
+ return this.exporter.getVisibleData();
210
+ }
211
+
212
+ /**
213
+ * Get all data
214
+ */
215
+ getAllData() {
216
+ return this.exporter.getAllData();
217
+ }
218
+
219
+ /**
220
+ * Destroy the table instance
221
+ */
222
+ destroy() {
223
+ // Remove event listeners and clean up
224
+ this.tableElement.classList.remove('vanilla-table', 'vanilla-table-zebra', 'sorting-enabled');
225
+ // Note: In a full implementation, you'd want to track and remove all event listeners
17
226
  }
18
227
  }
19
228
 
20
- module.exports = VanillaTable;
229
+ // Export for different module systems
230
+ if (typeof module !== 'undefined' && module.exports) {
231
+ module.exports = VanillaTable;
232
+ }
233
+
234
+ if (typeof window !== 'undefined') {
235
+ window.VanillaTable = VanillaTable;
236
+ }
package/package.json CHANGED
@@ -1,8 +1,12 @@
1
1
  {
2
2
  "name": "vanilla-table",
3
- "version": "0.1.0",
3
+ "version": "0.3.0",
4
4
  "description": "Lightweight vanilla JavaScript table library with sorting, pagination, filtering, and export capabilities",
5
5
  "main": "index.js",
6
+ "files": [
7
+ "index.js",
8
+ "src/"
9
+ ],
6
10
  "scripts": {
7
11
  "test": "echo \"Error: no test specified\" && exit 1"
8
12
  },
package/src/core.js ADDED
@@ -0,0 +1,84 @@
1
+ /**
2
+ * Core utilities for VanillaTable
3
+ */
4
+
5
+ class VanillaTableCore {
6
+ constructor(table, options = {}) {
7
+ this.table = table;
8
+ this.tbody = table.querySelector("tbody");
9
+ this.thead = table.querySelector("thead");
10
+ this.options = options;
11
+ this.data = [];
12
+ this.rows = [];
13
+ this.state = {
14
+ currentPage: 1,
15
+ perPage: options.perPage || 25,
16
+ sortState: [],
17
+ filters: {},
18
+ searchQuery: "",
19
+ };
20
+
21
+ // Add zebra striping class if enabled
22
+ if (options.zebra !== false) {
23
+ this.table.classList.add("vanilla-table-zebra");
24
+ }
25
+ }
26
+
27
+ /**
28
+ * Recompute zebra striping for currently visible rows
29
+ */
30
+ recomputeZebra() {
31
+ if (this.options.zebra === false) return;
32
+
33
+ let visibleIndex = 0;
34
+ this.rows.forEach((row) => {
35
+ if (row.classList.contains("vanilla-table-no-results")) return;
36
+ if (row.style.display === "none") return;
37
+
38
+ row.classList.remove("odd", "even");
39
+ row.classList.add(visibleIndex % 2 === 0 ? "odd" : "even");
40
+ visibleIndex++;
41
+ });
42
+ }
43
+
44
+ /**
45
+ * Run a function with transitions temporarily disabled
46
+ */
47
+ withTransitionSuspended(fn) {
48
+ this.table.classList.add("suspend-transitions");
49
+ try {
50
+ fn();
51
+ } finally {
52
+ requestAnimationFrame(() =>
53
+ this.table.classList.remove("suspend-transitions")
54
+ );
55
+ }
56
+ }
57
+
58
+ /**
59
+ * Get visible rows (not hidden by filters/search)
60
+ */
61
+ getVisibleRows() {
62
+ return this.rows.filter(
63
+ (row) =>
64
+ !row.classList.contains("vanilla-table-no-results") &&
65
+ row.style.display !== "none"
66
+ );
67
+ }
68
+
69
+ /**
70
+ * Update the no-results row visibility
71
+ */
72
+ updateNoResults() {
73
+ const noResultsRow = this.tbody.querySelector(".vanilla-table-no-results");
74
+ if (!noResultsRow) return;
75
+
76
+ const hasVisibleRows = this.rows.some(
77
+ (row) =>
78
+ !row.classList.contains("vanilla-table-no-results") &&
79
+ row.style.display !== "none"
80
+ );
81
+
82
+ noResultsRow.style.display = hasVisibleRows ? "none" : "";
83
+ }
84
+ }