@timlassiter11/yatl 0.3.21 → 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 +243 -90
- package/dist/index.d.mts +632 -0
- package/dist/index.d.ts +632 -0
- package/dist/index.js +1903 -0
- package/dist/index.js.map +1 -0
- package/dist/index.mjs +1868 -0
- package/dist/index.mjs.map +1 -0
- package/dist/yatl.min.global.js +455 -0
- package/dist/yatl.min.global.js.map +1 -0
- package/package.json +32 -21
- package/dist/data-table.css +0 -2
- package/dist/data-table.css.map +0 -1
- package/dist/data-table.d.mts +0 -624
- package/dist/data-table.d.ts +0 -624
- package/dist/data-table.global.js +0 -4
- package/dist/data-table.global.js.map +0 -1
- package/dist/data-table.js +0 -4
- package/dist/data-table.js.map +0 -1
- package/dist/data-table.mjs +0 -4
- package/dist/data-table.mjs.map +0 -1
package/README.md
CHANGED
|
@@ -1,144 +1,297 @@
|
|
|
1
1
|
# YATL
|
|
2
|
+
|
|
2
3
|
**Yet Another Table Library**
|
|
3
4
|
|
|
4
|
-
YATL is a
|
|
5
|
+
YATL is a powerful, feature-rich, and lightweight Web Component data table built with Lit. It handles large datasets with ease using virtual scrolling, offers advanced fuzzy search capabilities, supports state persistence, and works in any framework (React, Vue, Angular, or Vanilla JS).
|
|
5
6
|
|
|
6
7
|
## Why?!?
|
|
7
|
-
|
|
8
|
+
|
|
9
|
+
I needed a free and simple table library for vanilla JS that was easy to customize and could handle large datasets... so I created YATL. As the project that I wrote this for grew, so did this library. Now it is a web component built using Lit that is fairly feature rich for simple use cases. There are many other great table libraries out there but if you want something simple to just drop in but with all of the major features already included, YATL might be for you.
|
|
8
10
|
|
|
9
11
|
## Features
|
|
10
|
-
|
|
11
|
-
- **
|
|
12
|
-
- **
|
|
13
|
-
- **
|
|
14
|
-
- **Customizable
|
|
15
|
-
- **
|
|
12
|
+
|
|
13
|
+
- **Virtual Scrolling**: Render 100,000+ rows smoothly with virtual scrolling.
|
|
14
|
+
- **Smart Search**: Tokenized fuzzy search with relevance scoring and highlighting.
|
|
15
|
+
- **State Persistence**: Automatically save and restore column order, visibility, sort, and widths to LocalStorage.
|
|
16
|
+
- **Highly Customizable**: Slot support, CSS Shadow Parts, and custom cell renderers.
|
|
17
|
+
- **Interactive**: Drag-and-drop column reordering, multi-column sorting (`SHIFT+CLICK`), and resizeable headers.
|
|
18
|
+
- **Export**: Built-in CSV export for visible or all data.
|
|
19
|
+
- **Type Safe**: Generic component with full type hint support.
|
|
16
20
|
|
|
17
21
|
## Installation
|
|
18
22
|
|
|
19
23
|
The recommend method is to use npm.
|
|
24
|
+
|
|
20
25
|
```bash
|
|
21
26
|
npm install @timlassiter11/yatl
|
|
22
27
|
```
|
|
23
28
|
|
|
24
29
|
Alternatively you can manually download the source files from the [releases](https://github.com/timlassiter11/YATL/releases) section.
|
|
25
30
|
|
|
26
|
-
###
|
|
31
|
+
### Lit
|
|
27
32
|
```ts
|
|
28
|
-
import {
|
|
33
|
+
import { html, LitElement } from 'lit';
|
|
34
|
+
|
|
35
|
+
import '@timlassiter11/yatl';
|
|
36
|
+
|
|
37
|
+
class MyComponent extends LitElement {
|
|
38
|
+
@state()
|
|
39
|
+
private _tableData: User[] = [];
|
|
29
40
|
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
41
|
+
private _tableColums: ColumnOptions<User>[] = [
|
|
42
|
+
{
|
|
43
|
+
field: 'id',
|
|
44
|
+
title: 'ID',
|
|
45
|
+
resizeable: true,
|
|
46
|
+
sortable: true,
|
|
47
|
+
searchable: false,
|
|
48
|
+
},
|
|
49
|
+
{
|
|
50
|
+
field: 'name',
|
|
51
|
+
resizeable: true,
|
|
52
|
+
sortable: true,
|
|
53
|
+
searchable: true,
|
|
54
|
+
tokenize: true,
|
|
55
|
+
},
|
|
56
|
+
{
|
|
57
|
+
field: 'status',
|
|
58
|
+
resizeable: true,
|
|
59
|
+
sortable: true,
|
|
60
|
+
searchable: false,
|
|
61
|
+
}
|
|
62
|
+
];
|
|
33
63
|
|
|
64
|
+
protected override render() {
|
|
65
|
+
return html`<yatl-table
|
|
66
|
+
.columns=${this._columns}
|
|
67
|
+
.data=${this._tableData}
|
|
68
|
+
enable-virtual-scroll
|
|
69
|
+
@dt.row.clicked=${(event) => console.log(event.detail.row)}></yatl-table>`
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
private handleRowClicked = (event) => {
|
|
73
|
+
console.log(event.detail)
|
|
74
|
+
}
|
|
75
|
+
}
|
|
34
76
|
```
|
|
35
77
|
|
|
36
|
-
###
|
|
37
|
-
|
|
38
|
-
|
|
78
|
+
### npm
|
|
79
|
+
|
|
80
|
+
```ts
|
|
81
|
+
import '@timlassiter11/yatl';
|
|
82
|
+
|
|
83
|
+
const table = document.querySelector('yatl-table');
|
|
84
|
+
|
|
85
|
+
table.columns = [
|
|
86
|
+
{ field: 'id', title: 'ID', sortable: true, width: 60 },
|
|
87
|
+
{ field: 'name', title: 'Name', sortable: true, searchable: true },
|
|
88
|
+
{ field: 'role', title: 'Role', sortable: true },
|
|
89
|
+
{
|
|
90
|
+
field: 'status',
|
|
91
|
+
title: 'Status',
|
|
92
|
+
// Custom renderer example
|
|
93
|
+
cellRenderer: value => (value === 'Active' ? '🟢' : '🔴'),
|
|
94
|
+
},
|
|
95
|
+
];
|
|
39
96
|
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
}
|
|
97
|
+
table.data = [
|
|
98
|
+
{ id: 1, name: 'Alice', role: 'Admin', status: 'Active' },
|
|
99
|
+
{ id: 2, name: 'Bob', role: 'User', status: 'Inactive' },
|
|
100
|
+
// ... more data
|
|
101
|
+
];
|
|
43
102
|
```
|
|
44
103
|
|
|
45
|
-
###
|
|
104
|
+
### Vanilla JS
|
|
105
|
+
|
|
46
106
|
```html
|
|
47
|
-
|
|
48
|
-
<
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
107
|
+
<!DOCTYPE html>
|
|
108
|
+
<html lang="en">
|
|
109
|
+
<head>
|
|
110
|
+
<meta charset="UTF-8" />
|
|
111
|
+
<title>YATL Demo</title>
|
|
112
|
+
<script src="yatl.min.global.js"></script>
|
|
113
|
+
|
|
114
|
+
<style>
|
|
115
|
+
yatl-table {
|
|
116
|
+
height: 500px;
|
|
117
|
+
display: block;
|
|
118
|
+
border: 1px solid #ddd;
|
|
119
|
+
}
|
|
120
|
+
</style>
|
|
121
|
+
</head>
|
|
122
|
+
<body>
|
|
123
|
+
<yatl-table id="my-table" enable-footer enable-column-reorder></yatl-table>
|
|
124
|
+
|
|
125
|
+
<script>
|
|
126
|
+
const table = document.getElementById('my-table');
|
|
127
|
+
|
|
128
|
+
// Define Columns
|
|
129
|
+
table.columns = [
|
|
130
|
+
{ field: 'id', title: 'ID', width: 50 },
|
|
131
|
+
{ field: 'firstName', title: 'First Name', sortable: true },
|
|
132
|
+
{ field: 'lastName', title: 'Last Name', sortable: true },
|
|
133
|
+
{ field: 'email', title: 'Email', width: 200 },
|
|
134
|
+
];
|
|
135
|
+
|
|
136
|
+
// Load some data
|
|
137
|
+
table.data = Array.from({ length: 1000 }, (_, i) => ({
|
|
138
|
+
id: i + 1,
|
|
139
|
+
firstName: `User ${i}`,
|
|
140
|
+
lastName: `Doe`,
|
|
141
|
+
email: `user${i}@example.com`,
|
|
142
|
+
}));
|
|
143
|
+
</script>
|
|
144
|
+
</body>
|
|
145
|
+
</html>
|
|
53
146
|
```
|
|
54
147
|
|
|
55
148
|
## Styling
|
|
56
|
-
Some optional styling is included which adds sorting indicators and sticky headers. To use them simply include the stylesheet.
|
|
57
149
|
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
150
|
+
`yatl-table` uses the native Web Component Shadow DOM to encapsulate its styles. This prevents your global CSS from accidentally breaking the table, and prevents the table's styles from leaking out.
|
|
151
|
+
|
|
152
|
+
To customize the table, you use the standard CSS ::part() pseudo-element.
|
|
153
|
+
### The Basics
|
|
154
|
+
|
|
155
|
+
To style a specific part of the table, select the element and use ::part(name).
|
|
156
|
+
|
|
157
|
+
```css
|
|
158
|
+
/* Target the main table container */
|
|
159
|
+
yatl-table::part(table) {
|
|
160
|
+
border: 1px solid #e2e8f0;
|
|
161
|
+
border-radius: 8px;
|
|
162
|
+
font-family: 'Inter', sans-serif;
|
|
163
|
+
}
|
|
164
|
+
|
|
165
|
+
/* Target the header row */
|
|
166
|
+
yatl-table::part(header) {
|
|
167
|
+
background-color: #f8fafc;
|
|
168
|
+
font-weight: 700;
|
|
169
|
+
text-transform: uppercase;
|
|
170
|
+
font-size: 0.75rem;
|
|
171
|
+
}
|
|
61
172
|
```
|
|
62
173
|
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
174
|
+
|
|
175
|
+
### Part Reference
|
|
176
|
+
|
|
177
|
+
Here is a list of all exposed parts you can target:
|
|
178
|
+
|
|
179
|
+
| Part Name | Description |
|
|
180
|
+
|-------------------|---------------------------------------------------|
|
|
181
|
+
| table | The main container grid. |
|
|
182
|
+
| header | The container for the header row. |
|
|
183
|
+
| header-cell | Individual header cells. |
|
|
184
|
+
| header-title | The text span inside a header cell. |
|
|
185
|
+
| header-sort-icon | The sorting arrow icon. |
|
|
186
|
+
| header-resizer | The drag handle for resizing columns. |
|
|
187
|
+
| row | The container for a data row. |
|
|
188
|
+
| cell | Targets all cells (both header and body). |
|
|
189
|
+
| body-cell | Targets only data cells (not headers). |
|
|
190
|
+
| footer | The footer container. |
|
|
191
|
+
| message | The empty state / no results message container. |
|
|
192
|
+
|
|
193
|
+
### Common Recipes
|
|
194
|
+
#### Zebra Striping
|
|
195
|
+
You can use standard pseudo-classes like :nth-child combined with ::part.
|
|
196
|
+
|
|
197
|
+
```css
|
|
198
|
+
/* Stripe every even row */
|
|
199
|
+
yatl-table::part(row):nth-child(even) {
|
|
200
|
+
background-color: #f9f9f9;
|
|
201
|
+
}
|
|
202
|
+
|
|
203
|
+
/* Add a hover effect to rows */
|
|
204
|
+
yatl-table::part(row):hover {
|
|
205
|
+
background-color: #e0f2fe;
|
|
206
|
+
cursor: pointer;
|
|
207
|
+
}
|
|
66
208
|
```
|
|
67
209
|
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
dataTable.sort("age", "asc");
|
|
87
|
-
|
|
88
|
-
// Filter rows to only people aged 25
|
|
89
|
-
dataTable.filter({ age: 25 });
|
|
90
|
-
|
|
91
|
-
// Filter rows to only people over 25
|
|
92
|
-
dataTable.filter((row) => row.age > 25);
|
|
93
|
-
|
|
94
|
-
// Search for Bob
|
|
95
|
-
dataTable.search("bob");
|
|
96
|
-
|
|
97
|
-
// Export table data to CSV
|
|
98
|
-
dataTable.export("my-table-data");
|
|
210
|
+
#### Targeting Specific Columns
|
|
211
|
+
Every cell automatically gets a part name based on its field property in the format cell-{field}.
|
|
212
|
+
|
|
213
|
+
For example, if you have a column defined as `{ field: 'status' }`:
|
|
214
|
+
|
|
215
|
+
```css
|
|
216
|
+
/* Center the 'status' column and make it bold */
|
|
217
|
+
yatl-table::part(cell-status) {
|
|
218
|
+
justify-content: center; /* Flex alignment */
|
|
219
|
+
font-weight: bold;
|
|
220
|
+
text-align: center;
|
|
221
|
+
}
|
|
222
|
+
|
|
223
|
+
/* Set a specific width or background for the ID column */
|
|
224
|
+
yatl-table::part(cell-id) {
|
|
225
|
+
background-color: #f1f5f9;
|
|
226
|
+
font-family: monospace;
|
|
227
|
+
}
|
|
99
228
|
```
|
|
100
229
|
|
|
101
|
-
|
|
102
|
-
Virtual scrolling is used to render only the rows that are visible (with some extras before and after). This allows the library to support tables with hundreads of thousands of rows without issue. This is done using some magic (*simple math...*) but requires it's parent enforce a height. To do this you can simply add a height to the table.
|
|
230
|
+
#### Conditional Row Styling
|
|
103
231
|
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
232
|
+
You can style rows based on their data using the rowParts property in JavaScript combined with CSS.
|
|
233
|
+
|
|
234
|
+
```js
|
|
235
|
+
const table = document.querySelector('yatl-table');
|
|
236
|
+
|
|
237
|
+
// Return a string (or array of strings) to add to the row's parts
|
|
238
|
+
table.rowParts = (row) => {
|
|
239
|
+
const parts = [];
|
|
240
|
+
if (row.stock < 5) parts.push('low-stock');
|
|
241
|
+
if (row.price > 1000) parts.push('expensive');
|
|
242
|
+
return parts;
|
|
243
|
+
};
|
|
244
|
+
```
|
|
245
|
+
|
|
246
|
+
```css
|
|
247
|
+
/* Style rows tagged as 'low-stock' */
|
|
248
|
+
yatl-table::part(low-stock) {
|
|
249
|
+
background-color: #fef2f2; /* Light red */
|
|
250
|
+
border-left: 4px solid #ef4444;
|
|
251
|
+
}
|
|
252
|
+
|
|
253
|
+
/* Style rows tagged as 'expensive' */
|
|
254
|
+
yatl-table::part(expensive) {
|
|
255
|
+
color: #0f172a;
|
|
256
|
+
font-weight: 600;
|
|
257
|
+
}
|
|
108
258
|
```
|
|
109
259
|
|
|
110
|
-
|
|
260
|
+
#### Customizing the Footer
|
|
261
|
+
```css
|
|
262
|
+
yatl-table::part(footer) {
|
|
263
|
+
background-color: #1e293b;
|
|
264
|
+
color: white;
|
|
265
|
+
padding: 1rem;
|
|
266
|
+
}
|
|
267
|
+
```
|
|
268
|
+
|
|
269
|
+
### Virtual Scroll
|
|
270
|
+
|
|
271
|
+
Virtual scrolling is used to render only the rows that are visible (with some extras before and after). This allows the library to support tables with hundreads of thousands of rows without issue. This is done using `lit-virtualizer` and requires it's parent enforce a height. To do this you can simply add a height to the table.
|
|
272
|
+
|
|
111
273
|
```html
|
|
112
274
|
<body>
|
|
113
|
-
|
|
114
|
-
<table></table>
|
|
115
|
-
</div>
|
|
275
|
+
<yatl-table style="height: 500px;"></yatl-table>
|
|
116
276
|
</body>
|
|
117
277
|
```
|
|
118
278
|
|
|
119
|
-
Most of the time this isn't ideal though and instead we'd like to let the layout work it's magic
|
|
279
|
+
Most of the time this isn't ideal though and instead we'd like to let the layout work it's magic. To do this, it's best to wrap the table in an element that can enforce a height.
|
|
120
280
|
|
|
121
281
|
```html
|
|
122
282
|
<body style="height: 100vh;">
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
<div>
|
|
129
|
-
... Some boring footer info or something
|
|
130
|
-
</div>
|
|
131
|
-
</div>
|
|
283
|
+
<div style="display: flex;">
|
|
284
|
+
<div>... Lot's of cool table controls or filters</div>
|
|
285
|
+
<yatl-table style="flex-grow: 1;"></yatl-table>
|
|
286
|
+
<div>... Some boring footer info or something</div>
|
|
287
|
+
</div>
|
|
132
288
|
</body>
|
|
133
289
|
```
|
|
134
290
|
|
|
135
|
-
Since the `dt-scroller` wrapper listens to scroll and resize events, this allows the table to be responsive and update what is rendered as the layout changes.
|
|
136
|
-
|
|
137
291
|
### Docs
|
|
138
|
-
Full API docs can be found [here](https://timlassiter11.github.io/YATL/docs/index.html).
|
|
139
292
|
|
|
140
|
-
|
|
141
|
-
There are some limitations to virtual scrolling. For one, rows need to be a uniform height to accurately calculate the table height. Also, there seems to be a maximum element size that once exceeded, the contents are no longer rendered. I've found this to occur with datasets approaching 1 million rows in Chrome and unfortunately I have no workaround for it. If you have that many rows you definitely need some server side pagination and this is probably not the library for you.
|
|
293
|
+
Full API docs can be found [here](https://timlassiter11.github.io/YATL/docs/index.html).
|
|
142
294
|
|
|
143
295
|
# Examples
|
|
144
|
-
|
|
296
|
+
|
|
297
|
+
Examples can be found in the examples directoy and are also hosted [here](https://timlassiter11.github.io/YATL/examples/index.html) to view live.
|