@toniel/laravel-tanstack-datatable 0.1.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/LICENSE +21 -0
- package/README.md +386 -0
- package/dist/components/DataTable.vue.d.ts +97 -0
- package/dist/components/DataTable.vue.d.ts.map +1 -0
- package/dist/components/DataTablePagination.vue.d.ts +21 -0
- package/dist/components/DataTablePagination.vue.d.ts.map +1 -0
- package/dist/index.d.ts +4 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +1 -0
- package/dist/index.mjs +393 -0
- package/dist/lib/utils.d.ts +3 -0
- package/dist/lib/utils.d.ts.map +1 -0
- package/package.json +77 -0
package/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2025 Toniel
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
package/README.md
ADDED
|
@@ -0,0 +1,386 @@
|
|
|
1
|
+
# Laravel TanStack DataTable
|
|
2
|
+
|
|
3
|
+
[](https://www.npmjs.com/package/@toniel/laravel-tanstack-datatable)
|
|
4
|
+
[](https://www.npmjs.com/package/@toniel/laravel-tanstack-datatable)
|
|
5
|
+
[](https://github.com/toniel/laravel-tanstack-datatable/blob/main/LICENSE)
|
|
6
|
+
[](https://github.com/toniel/laravel-tanstack-datatable)
|
|
7
|
+
|
|
8
|
+
Vue 3 DataTable components for Laravel pagination with TanStack Query and TanStack Table.
|
|
9
|
+
|
|
10
|
+
> 🔗 **Companion Package**: This package works together with [`@toniel/laravel-tanstack-pagination`](https://github.com/toniel/laravel-tanstack-pagination) - the core composables library.
|
|
11
|
+
|
|
12
|
+
## 📦 Installation
|
|
13
|
+
|
|
14
|
+
```bash
|
|
15
|
+
npm install @toniel/laravel-tanstack-datatable @toniel/laravel-tanstack-pagination
|
|
16
|
+
# or
|
|
17
|
+
yarn add @toniel/laravel-tanstack-datatable @toniel/laravel-tanstack-pagination
|
|
18
|
+
# or
|
|
19
|
+
pnpm add @toniel/laravel-tanstack-datatable @toniel/laravel-tanstack-pagination
|
|
20
|
+
# or
|
|
21
|
+
bun add @toniel/laravel-tanstack-datatable @toniel/laravel-tanstack-pagination
|
|
22
|
+
```
|
|
23
|
+
|
|
24
|
+
### Peer Dependencies
|
|
25
|
+
|
|
26
|
+
This package requires the following peer dependencies:
|
|
27
|
+
|
|
28
|
+
```bash
|
|
29
|
+
npm install vue @tanstack/vue-query @tanstack/vue-table
|
|
30
|
+
```
|
|
31
|
+
|
|
32
|
+
## 🚀 Quick Start
|
|
33
|
+
|
|
34
|
+
### Basic Usage
|
|
35
|
+
|
|
36
|
+
```vue
|
|
37
|
+
<script setup lang="ts">
|
|
38
|
+
import { usePagination } from '@toniel/laravel-tanstack-pagination'
|
|
39
|
+
import { DataTable } from '@toniel/laravel-tanstack-datatable'
|
|
40
|
+
import { createColumnHelper } from '@tanstack/vue-table'
|
|
41
|
+
import axios from 'axios'
|
|
42
|
+
|
|
43
|
+
// Define your data type
|
|
44
|
+
interface User {
|
|
45
|
+
id: number
|
|
46
|
+
name: string
|
|
47
|
+
email: string
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
// Create columns
|
|
51
|
+
const columnHelper = createColumnHelper<User>()
|
|
52
|
+
|
|
53
|
+
const columns = [
|
|
54
|
+
columnHelper.accessor('id', {
|
|
55
|
+
header: 'ID',
|
|
56
|
+
}),
|
|
57
|
+
columnHelper.accessor('name', {
|
|
58
|
+
header: 'Name',
|
|
59
|
+
}),
|
|
60
|
+
columnHelper.accessor('email', {
|
|
61
|
+
header: 'Email',
|
|
62
|
+
}),
|
|
63
|
+
]
|
|
64
|
+
|
|
65
|
+
// Use pagination composable
|
|
66
|
+
const {
|
|
67
|
+
tableData,
|
|
68
|
+
pagination,
|
|
69
|
+
search,
|
|
70
|
+
currentPerPage,
|
|
71
|
+
sortBy,
|
|
72
|
+
sortDirection,
|
|
73
|
+
isLoading,
|
|
74
|
+
error,
|
|
75
|
+
handlePageChange,
|
|
76
|
+
handlePerPageChange,
|
|
77
|
+
handleSearchChange,
|
|
78
|
+
handleSortChange,
|
|
79
|
+
refetch,
|
|
80
|
+
} = usePagination(
|
|
81
|
+
(filters) => axios.get('/api/users', { params: filters }),
|
|
82
|
+
{ queryKey: 'users', defaultPerPage: 10 }
|
|
83
|
+
)
|
|
84
|
+
</script>
|
|
85
|
+
|
|
86
|
+
<template>
|
|
87
|
+
<DataTable
|
|
88
|
+
:data="tableData"
|
|
89
|
+
:columns="columns"
|
|
90
|
+
:pagination="pagination"
|
|
91
|
+
:is-loading="isLoading"
|
|
92
|
+
:error="error"
|
|
93
|
+
:search="search"
|
|
94
|
+
:current-per-page="currentPerPage"
|
|
95
|
+
:sort-by="sortBy"
|
|
96
|
+
:sort-direction="sortDirection"
|
|
97
|
+
title="Users"
|
|
98
|
+
item-name="users"
|
|
99
|
+
@page-change="handlePageChange"
|
|
100
|
+
@per-page-change="handlePerPageChange"
|
|
101
|
+
@search-change="handleSearchChange"
|
|
102
|
+
@sort-change="handleSortChange"
|
|
103
|
+
@retry="refetch"
|
|
104
|
+
/>
|
|
105
|
+
</template>
|
|
106
|
+
```
|
|
107
|
+
|
|
108
|
+
## 🎯 Features
|
|
109
|
+
|
|
110
|
+
### ✅ Core Features
|
|
111
|
+
- 🔍 **Search** with debounce
|
|
112
|
+
- 📄 **Pagination** with Laravel meta
|
|
113
|
+
- 🔄 **Sorting** (client & server-side)
|
|
114
|
+
- 📊 **Row selection** with bulk actions
|
|
115
|
+
- 🎨 **Dark mode** support
|
|
116
|
+
- ⚡ **Loading states** & error handling
|
|
117
|
+
- 🔧 **Fully customizable** via slots
|
|
118
|
+
|
|
119
|
+
### 🎨 Component Props
|
|
120
|
+
|
|
121
|
+
#### DataTable Props
|
|
122
|
+
|
|
123
|
+
| Prop | Type | Default | Description |
|
|
124
|
+
|------|------|---------|-------------|
|
|
125
|
+
| `data` | `Array` | `[]` | Table data array |
|
|
126
|
+
| `columns` | `ColumnDef[]` | required | TanStack Table column definitions |
|
|
127
|
+
| `pagination` | `LaravelPaginationResponse` | `null` | Laravel pagination response |
|
|
128
|
+
| `isLoading` | `boolean` | `false` | Loading state |
|
|
129
|
+
| `error` | `Error` | `null` | Error object |
|
|
130
|
+
| `search` | `string` | `''` | Search query |
|
|
131
|
+
| `currentPerPage` | `number` | `10` | Current items per page |
|
|
132
|
+
| `perPageOptions` | `number[]` | `[10,15,25,50,100]` | Per page options |
|
|
133
|
+
| `sortBy` | `string` | `null` | Current sort column |
|
|
134
|
+
| `sortDirection` | `'asc'\|'desc'` | `'asc'` | Sort direction |
|
|
135
|
+
| `enableRowSelection` | `boolean` | `false` | Enable row selection |
|
|
136
|
+
| `rowSelection` | `RowSelectionState` | `{}` | Selected rows state |
|
|
137
|
+
| `getRowId` | `Function` | `(row) => row.id` | Get unique row ID |
|
|
138
|
+
| `showSearch` | `boolean` | `true` | Show search input |
|
|
139
|
+
| `showCaption` | `boolean` | `true` | Show table caption |
|
|
140
|
+
| `showPerPageSelector` | `boolean` | `true` | Show per page selector |
|
|
141
|
+
| `title` | `string` | `'Items'` | Table title |
|
|
142
|
+
| `itemName` | `string` | `'items'` | Item name for pluralization |
|
|
143
|
+
| `loadingText` | `string` | `'Loading...'` | Loading text |
|
|
144
|
+
| `errorTitle` | `string` | `'Error loading data'` | Error title |
|
|
145
|
+
| `emptyStateText` | `string` | `'📭 No items found'` | Empty state text |
|
|
146
|
+
|
|
147
|
+
#### DataTable Events
|
|
148
|
+
|
|
149
|
+
| Event | Payload | Description |
|
|
150
|
+
|-------|---------|-------------|
|
|
151
|
+
| `pageChange` | `number` | Emitted when page changes |
|
|
152
|
+
| `perPageChange` | `number` | Emitted when per page changes |
|
|
153
|
+
| `searchChange` | `string` | Emitted when search input changes |
|
|
154
|
+
| `sortChange` | `string` | Emitted when sort column changes |
|
|
155
|
+
| `retry` | - | Emitted when retry button clicked |
|
|
156
|
+
| `update:rowSelection` | `RowSelectionState` | Emitted when row selection changes |
|
|
157
|
+
|
|
158
|
+
### 🎨 Slots
|
|
159
|
+
|
|
160
|
+
#### `filters` Slot
|
|
161
|
+
Add custom filters next to search input:
|
|
162
|
+
|
|
163
|
+
```vue
|
|
164
|
+
<DataTable ...>
|
|
165
|
+
<template #filters>
|
|
166
|
+
<select v-model="status" class="...">
|
|
167
|
+
<option value="">All Status</option>
|
|
168
|
+
<option value="active">Active</option>
|
|
169
|
+
<option value="inactive">Inactive</option>
|
|
170
|
+
</select>
|
|
171
|
+
</template>
|
|
172
|
+
</DataTable>
|
|
173
|
+
```
|
|
174
|
+
|
|
175
|
+
#### `header` Slot
|
|
176
|
+
Add action buttons (e.g., Create button):
|
|
177
|
+
|
|
178
|
+
```vue
|
|
179
|
+
<DataTable ...>
|
|
180
|
+
<template #header>
|
|
181
|
+
<button @click="openCreateModal" class="...">
|
|
182
|
+
➕ Add User
|
|
183
|
+
</button>
|
|
184
|
+
</template>
|
|
185
|
+
</DataTable>
|
|
186
|
+
```
|
|
187
|
+
|
|
188
|
+
#### `bulk-actions` Slot
|
|
189
|
+
Add bulk action buttons when rows are selected:
|
|
190
|
+
|
|
191
|
+
```vue
|
|
192
|
+
<DataTable
|
|
193
|
+
:enable-row-selection="true"
|
|
194
|
+
v-model:row-selection="selectedRows"
|
|
195
|
+
...
|
|
196
|
+
>
|
|
197
|
+
<template #bulk-actions="{ selectedIds, selectedData, clearSelection }">
|
|
198
|
+
<button @click="bulkDelete(selectedIds)" class="...">
|
|
199
|
+
🗑️ Delete Selected
|
|
200
|
+
</button>
|
|
201
|
+
<button @click="clearSelection" class="...">
|
|
202
|
+
Clear
|
|
203
|
+
</button>
|
|
204
|
+
</template>
|
|
205
|
+
</DataTable>
|
|
206
|
+
```
|
|
207
|
+
|
|
208
|
+
## 📖 Advanced Examples
|
|
209
|
+
|
|
210
|
+
### With Row Selection
|
|
211
|
+
|
|
212
|
+
```vue
|
|
213
|
+
<script setup lang="ts">
|
|
214
|
+
import { ref } from 'vue'
|
|
215
|
+
import type { RowSelectionState } from '@tanstack/vue-table'
|
|
216
|
+
|
|
217
|
+
const selectedRows = ref<RowSelectionState>({})
|
|
218
|
+
|
|
219
|
+
const bulkDelete = async (ids: string[]) => {
|
|
220
|
+
await axios.delete('/api/users/bulk', { data: { ids } })
|
|
221
|
+
selectedRows.value = {}
|
|
222
|
+
}
|
|
223
|
+
</script>
|
|
224
|
+
|
|
225
|
+
<template>
|
|
226
|
+
<DataTable
|
|
227
|
+
:enable-row-selection="true"
|
|
228
|
+
v-model:row-selection="selectedRows"
|
|
229
|
+
...
|
|
230
|
+
>
|
|
231
|
+
<template #bulk-actions="{ selectedIds, clearSelection }">
|
|
232
|
+
<button @click="bulkDelete(selectedIds)">Delete</button>
|
|
233
|
+
<button @click="clearSelection">Clear</button>
|
|
234
|
+
</template>
|
|
235
|
+
</DataTable>
|
|
236
|
+
</template>
|
|
237
|
+
```
|
|
238
|
+
|
|
239
|
+
### With Custom Columns (Actions)
|
|
240
|
+
|
|
241
|
+
```vue
|
|
242
|
+
<script setup lang="ts">
|
|
243
|
+
const columns = [
|
|
244
|
+
columnHelper.accessor('id', { header: 'ID' }),
|
|
245
|
+
columnHelper.accessor('name', { header: 'Name' }),
|
|
246
|
+
columnHelper.display({
|
|
247
|
+
id: 'actions',
|
|
248
|
+
header: 'Actions',
|
|
249
|
+
cell: ({ row }) => h('div', { class: 'flex gap-2' }, [
|
|
250
|
+
h('button', { onClick: () => edit(row.original) }, 'Edit'),
|
|
251
|
+
h('button', { onClick: () => remove(row.original) }, 'Delete'),
|
|
252
|
+
]),
|
|
253
|
+
}),
|
|
254
|
+
]
|
|
255
|
+
</script>
|
|
256
|
+
```
|
|
257
|
+
|
|
258
|
+
### With Checkbox Column
|
|
259
|
+
|
|
260
|
+
```vue
|
|
261
|
+
<script setup lang="ts">
|
|
262
|
+
import { Checkbox } from 'your-ui-library' // or native input
|
|
263
|
+
|
|
264
|
+
const columns = [
|
|
265
|
+
columnHelper.display({
|
|
266
|
+
id: 'select',
|
|
267
|
+
header: ({ table }) => h(Checkbox, {
|
|
268
|
+
checked: table.getIsAllPageRowsSelected(),
|
|
269
|
+
onUpdate: (val) => table.toggleAllPageRowsSelected(!!val),
|
|
270
|
+
}),
|
|
271
|
+
cell: ({ row }) => h(Checkbox, {
|
|
272
|
+
checked: row.getIsSelected(),
|
|
273
|
+
onUpdate: (val) => row.toggleSelected(!!val),
|
|
274
|
+
}),
|
|
275
|
+
}),
|
|
276
|
+
// ... other columns
|
|
277
|
+
]
|
|
278
|
+
</script>
|
|
279
|
+
```
|
|
280
|
+
|
|
281
|
+
## 🎨 Styling
|
|
282
|
+
|
|
283
|
+
This package uses Tailwind CSS utility classes. Make sure Tailwind is configured in your project.
|
|
284
|
+
|
|
285
|
+
### Dark Mode
|
|
286
|
+
|
|
287
|
+
Dark mode is automatically supported via Tailwind's `dark:` classes. Configure dark mode in your `tailwind.config.js`:
|
|
288
|
+
|
|
289
|
+
```js
|
|
290
|
+
module.exports = {
|
|
291
|
+
darkMode: 'class', // or 'media'
|
|
292
|
+
// ...
|
|
293
|
+
}
|
|
294
|
+
```
|
|
295
|
+
|
|
296
|
+
### Custom Styling
|
|
297
|
+
|
|
298
|
+
You can override styles using Tailwind classes or custom CSS:
|
|
299
|
+
|
|
300
|
+
```css
|
|
301
|
+
/* Custom table styles */
|
|
302
|
+
.data-table {
|
|
303
|
+
/* Your custom styles */
|
|
304
|
+
}
|
|
305
|
+
```
|
|
306
|
+
|
|
307
|
+
## 🎨 Theming
|
|
308
|
+
|
|
309
|
+
The components use Tailwind CSS and support dark mode out of the box. You can customize colors by:
|
|
310
|
+
|
|
311
|
+
1. **Using Tailwind Config:**
|
|
312
|
+
```js
|
|
313
|
+
// tailwind.config.js
|
|
314
|
+
module.exports = {
|
|
315
|
+
theme: {
|
|
316
|
+
extend: {
|
|
317
|
+
colors: {
|
|
318
|
+
// Customize colors here
|
|
319
|
+
}
|
|
320
|
+
}
|
|
321
|
+
}
|
|
322
|
+
}
|
|
323
|
+
```
|
|
324
|
+
|
|
325
|
+
2. **CSS Variables:**
|
|
326
|
+
```css
|
|
327
|
+
:root {
|
|
328
|
+
--color-primary: ...;
|
|
329
|
+
--color-border: ...;
|
|
330
|
+
}
|
|
331
|
+
```
|
|
332
|
+
|
|
333
|
+
## 🔗 Related Packages
|
|
334
|
+
|
|
335
|
+
- [`@toniel/laravel-tanstack-pagination`](https://github.com/toniel/laravel-tanstack-pagination) - Core composables (required)
|
|
336
|
+
- [`@tanstack/vue-query`](https://tanstack.com/query/latest/docs/vue/overview) - Data fetching & caching
|
|
337
|
+
- [`@tanstack/vue-table`](https://tanstack.com/table/latest/docs/framework/vue/vue-table) - Table state management
|
|
338
|
+
|
|
339
|
+
## 🌟 Show Your Support
|
|
340
|
+
|
|
341
|
+
If this package helped you, please consider:
|
|
342
|
+
- ⭐ Starring the [GitHub repository](https://github.com/toniel/laravel-tanstack-datatable)
|
|
343
|
+
- 🐛 [Reporting bugs](https://github.com/toniel/laravel-tanstack-datatable/issues)
|
|
344
|
+
- 💡 [Suggesting new features](https://github.com/toniel/laravel-tanstack-datatable/issues)
|
|
345
|
+
- 🔧 [Contributing code](https://github.com/toniel/laravel-tanstack-datatable/pulls)
|
|
346
|
+
|
|
347
|
+
## 📄 License
|
|
348
|
+
|
|
349
|
+
[MIT](https://github.com/toniel/laravel-tanstack-datatable/blob/main/LICENSE) © [Toniel](https://github.com/toniel)
|
|
350
|
+
|
|
351
|
+
## 🤝 Contributing
|
|
352
|
+
|
|
353
|
+
Contributions, issues and feature requests are welcome!
|
|
354
|
+
|
|
355
|
+
1. Fork the repository
|
|
356
|
+
2. Create your feature branch (`git checkout -b feature/amazing-feature`)
|
|
357
|
+
3. Commit your changes (`git commit -m 'Add some amazing feature'`)
|
|
358
|
+
4. Push to the branch (`git push origin feature/amazing-feature`)
|
|
359
|
+
5. Open a Pull Request
|
|
360
|
+
|
|
361
|
+
See [CONTRIBUTING.md](CONTRIBUTING.md) for more details.
|
|
362
|
+
|
|
363
|
+
## 🐛 Known Issues
|
|
364
|
+
|
|
365
|
+
Check the [GitHub Issues](https://github.com/toniel/laravel-tanstack-datatable/issues) page for known issues and feature requests.
|
|
366
|
+
|
|
367
|
+
## 📮 Contact
|
|
368
|
+
|
|
369
|
+
- GitHub: [@toniel](https://github.com/toniel)
|
|
370
|
+
- NPM: [@toniel](https://www.npmjs.com/~toniel)
|
|
371
|
+
|
|
372
|
+
## 🙏 Acknowledgments
|
|
373
|
+
|
|
374
|
+
Built with these amazing libraries:
|
|
375
|
+
- [Vue 3](https://vuejs.org/)
|
|
376
|
+
- [TanStack Query](https://tanstack.com/query/latest)
|
|
377
|
+
- [TanStack Table](https://tanstack.com/table/latest)
|
|
378
|
+
- [Tailwind CSS](https://tailwindcss.com/)
|
|
379
|
+
- [Lucide Icons](https://lucide.dev/)
|
|
380
|
+
|
|
381
|
+
---
|
|
382
|
+
|
|
383
|
+
<div align="center">
|
|
384
|
+
Made with ❤️ by <a href="https://github.com/toniel">Toniel</a>
|
|
385
|
+
</div>
|
|
386
|
+
|
|
@@ -0,0 +1,97 @@
|
|
|
1
|
+
import { LaravelPaginationResponse } from '@toniel/laravel-tanstack-pagination';
|
|
2
|
+
import { ColumnDef, RowSelectionState } from '@tanstack/vue-table';
|
|
3
|
+
interface Props {
|
|
4
|
+
data?: any[];
|
|
5
|
+
columns: ColumnDef<any>[];
|
|
6
|
+
pagination?: LaravelPaginationResponse | null;
|
|
7
|
+
isLoading?: boolean;
|
|
8
|
+
error?: Error | null;
|
|
9
|
+
search?: string;
|
|
10
|
+
currentPerPage?: number;
|
|
11
|
+
perPageOptions?: number[];
|
|
12
|
+
sortBy?: string | null;
|
|
13
|
+
sortDirection?: 'asc' | 'desc';
|
|
14
|
+
rowSelection?: RowSelectionState;
|
|
15
|
+
enableRowSelection?: boolean;
|
|
16
|
+
getRowId?: (row: any) => string;
|
|
17
|
+
showSearch?: boolean;
|
|
18
|
+
showCaption?: boolean;
|
|
19
|
+
showPerPageSelector?: boolean;
|
|
20
|
+
title?: string;
|
|
21
|
+
itemName?: string;
|
|
22
|
+
loadingText?: string;
|
|
23
|
+
errorTitle?: string;
|
|
24
|
+
emptyStateText?: string;
|
|
25
|
+
}
|
|
26
|
+
declare function __VLS_template(): {
|
|
27
|
+
attrs: Partial<{}>;
|
|
28
|
+
slots: {
|
|
29
|
+
filters?(_: {}): any;
|
|
30
|
+
header?(_: {}): any;
|
|
31
|
+
'bulk-actions'?(_: {
|
|
32
|
+
selectedIds: string[];
|
|
33
|
+
selectedData: any[];
|
|
34
|
+
selectedCount: number;
|
|
35
|
+
clearSelection: () => void;
|
|
36
|
+
selectAllCurrentPage: () => void;
|
|
37
|
+
deselectAllCurrentPage: () => void;
|
|
38
|
+
}): any;
|
|
39
|
+
};
|
|
40
|
+
refs: {};
|
|
41
|
+
rootEl: HTMLDivElement;
|
|
42
|
+
};
|
|
43
|
+
type __VLS_TemplateResult = ReturnType<typeof __VLS_template>;
|
|
44
|
+
declare const __VLS_component: import('vue').DefineComponent<Props, {
|
|
45
|
+
getSelectedRowIds: () => string[];
|
|
46
|
+
getSelectedRowData: () => any[];
|
|
47
|
+
clearSelection: () => void;
|
|
48
|
+
selectAllCurrentPage: () => void;
|
|
49
|
+
deselectAllCurrentPage: () => void;
|
|
50
|
+
selectedRowCount: import('vue').ComputedRef<number>;
|
|
51
|
+
selectedRowIds: import('vue').ComputedRef<string[]>;
|
|
52
|
+
selectedRowData: import('vue').ComputedRef<any[]>;
|
|
53
|
+
table: import('@tanstack/table-core').Table<any>;
|
|
54
|
+
}, {}, {}, {}, import('vue').ComponentOptionsMixin, import('vue').ComponentOptionsMixin, {
|
|
55
|
+
pageChange: (page: number) => any;
|
|
56
|
+
perPageChange: (perPage: number) => any;
|
|
57
|
+
searchChange: (search: string) => any;
|
|
58
|
+
sortChange: (column: string) => any;
|
|
59
|
+
retry: () => any;
|
|
60
|
+
"update:rowSelection": (selection: RowSelectionState) => any;
|
|
61
|
+
}, string, import('vue').PublicProps, Readonly<Props> & Readonly<{
|
|
62
|
+
onPageChange?: ((page: number) => any) | undefined;
|
|
63
|
+
onPerPageChange?: ((perPage: number) => any) | undefined;
|
|
64
|
+
onSearchChange?: ((search: string) => any) | undefined;
|
|
65
|
+
onSortChange?: ((column: string) => any) | undefined;
|
|
66
|
+
onRetry?: (() => any) | undefined;
|
|
67
|
+
"onUpdate:rowSelection"?: ((selection: RowSelectionState) => any) | undefined;
|
|
68
|
+
}>, {
|
|
69
|
+
pagination: LaravelPaginationResponse | null;
|
|
70
|
+
perPageOptions: number[];
|
|
71
|
+
currentPerPage: number;
|
|
72
|
+
showPerPageSelector: boolean;
|
|
73
|
+
search: string;
|
|
74
|
+
data: any[];
|
|
75
|
+
title: string;
|
|
76
|
+
isLoading: boolean;
|
|
77
|
+
error: Error | null;
|
|
78
|
+
sortBy: string | null;
|
|
79
|
+
sortDirection: "asc" | "desc";
|
|
80
|
+
rowSelection: RowSelectionState;
|
|
81
|
+
enableRowSelection: boolean;
|
|
82
|
+
getRowId: (row: any) => string;
|
|
83
|
+
showSearch: boolean;
|
|
84
|
+
showCaption: boolean;
|
|
85
|
+
itemName: string;
|
|
86
|
+
loadingText: string;
|
|
87
|
+
errorTitle: string;
|
|
88
|
+
emptyStateText: string;
|
|
89
|
+
}, {}, {}, {}, string, import('vue').ComponentProvideOptions, false, {}, HTMLDivElement>;
|
|
90
|
+
declare const _default: __VLS_WithTemplateSlots<typeof __VLS_component, __VLS_TemplateResult["slots"]>;
|
|
91
|
+
export default _default;
|
|
92
|
+
type __VLS_WithTemplateSlots<T, S> = T & {
|
|
93
|
+
new (): {
|
|
94
|
+
$slots: S;
|
|
95
|
+
};
|
|
96
|
+
};
|
|
97
|
+
//# sourceMappingURL=DataTable.vue.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"DataTable.vue.d.ts","sourceRoot":"","sources":["../../src/components/DataTable.vue"],"names":[],"mappings":"AA4WA,OAAO,KAAK,EAAE,yBAAyB,EAAE,MAAM,qCAAqC,CAAA;AACpF,OAAO,EAIL,KAAK,SAAS,EACd,KAAK,iBAAiB,EACvB,MAAM,qBAAqB,CAAA;AAK5B,UAAU,KAAK;IACb,IAAI,CAAC,EAAE,GAAG,EAAE,CAAA;IACZ,OAAO,EAAE,SAAS,CAAC,GAAG,CAAC,EAAE,CAAA;IACzB,UAAU,CAAC,EAAE,yBAAyB,GAAG,IAAI,CAAA;IAC7C,SAAS,CAAC,EAAE,OAAO,CAAA;IACnB,KAAK,CAAC,EAAE,KAAK,GAAG,IAAI,CAAA;IACpB,MAAM,CAAC,EAAE,MAAM,CAAA;IACf,cAAc,CAAC,EAAE,MAAM,CAAA;IACvB,cAAc,CAAC,EAAE,MAAM,EAAE,CAAA;IACzB,MAAM,CAAC,EAAE,MAAM,GAAG,IAAI,CAAA;IACtB,aAAa,CAAC,EAAE,KAAK,GAAG,MAAM,CAAA;IAG9B,YAAY,CAAC,EAAE,iBAAiB,CAAA;IAChC,kBAAkB,CAAC,EAAE,OAAO,CAAA;IAC5B,QAAQ,CAAC,EAAE,CAAC,GAAG,EAAE,GAAG,KAAK,MAAM,CAAA;IAG/B,UAAU,CAAC,EAAE,OAAO,CAAA;IACpB,WAAW,CAAC,EAAE,OAAO,CAAA;IACrB,mBAAmB,CAAC,EAAE,OAAO,CAAA;IAG7B,KAAK,CAAC,EAAE,MAAM,CAAA;IACd,QAAQ,CAAC,EAAE,MAAM,CAAA;IACjB,WAAW,CAAC,EAAE,MAAM,CAAA;IACpB,UAAU,CAAC,EAAE,MAAM,CAAA;IACnB,cAAc,CAAC,EAAE,MAAM,CAAA;CACxB;AA8ID,iBAAS,cAAc;WA0UT,OAAO,IAA6B;;yBAZrB,GAAG;wBACJ,GAAG;;;;;;;;YACK,GAAG;;;;EAetC;AAuBD,KAAK,oBAAoB,GAAG,UAAU,CAAC,OAAO,cAAc,CAAC,CAAC;AAC9D,QAAA,MAAM,eAAe;;;;;;;;;;;;;;;;;;;;;;;;;gBA9gBN,yBAAyB,GAAG,IAAI;oBAK5B,MAAM,EAAE;oBADR,MAAM;yBAaD,OAAO;YAdpB,MAAM;UALR,GAAG,EAAE;WAsBJ,MAAM;eAnBF,OAAO;WACX,KAAK,GAAG,IAAI;YAIX,MAAM,GAAG,IAAI;mBACN,KAAK,GAAG,MAAM;kBAGf,iBAAiB;wBACX,OAAO;cACjB,CAAC,GAAG,EAAE,GAAG,KAAK,MAAM;gBAGlB,OAAO;iBACN,OAAO;cAKV,MAAM;iBACH,MAAM;gBACP,MAAM;oBACF,MAAM;wFAggBvB,CAAC;wBACkB,uBAAuB,CAAC,OAAO,eAAe,EAAE,oBAAoB,CAAC,OAAO,CAAC,CAAC;AAAnG,wBAAoG;AAapG,KAAK,uBAAuB,CAAC,CAAC,EAAE,CAAC,IAAI,CAAC,GAAG;IACxC,QAAO;QACN,MAAM,EAAE,CAAC,CAAC;KAEV,CAAA;CACD,CAAC"}
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
import { LaravelPaginationResponse } from '@toniel/laravel-tanstack-pagination';
|
|
2
|
+
interface Props {
|
|
3
|
+
pagination?: LaravelPaginationResponse | null;
|
|
4
|
+
perPageOptions?: number[];
|
|
5
|
+
currentPerPage?: number;
|
|
6
|
+
showPerPageSelector?: boolean;
|
|
7
|
+
}
|
|
8
|
+
declare const _default: import('vue').DefineComponent<Props, {}, {}, {}, {}, import('vue').ComponentOptionsMixin, import('vue').ComponentOptionsMixin, {
|
|
9
|
+
pageChange: (page: number) => any;
|
|
10
|
+
perPageChange: (perPage: number) => any;
|
|
11
|
+
}, string, import('vue').PublicProps, Readonly<Props> & Readonly<{
|
|
12
|
+
onPageChange?: ((page: number) => any) | undefined;
|
|
13
|
+
onPerPageChange?: ((perPage: number) => any) | undefined;
|
|
14
|
+
}>, {
|
|
15
|
+
pagination: LaravelPaginationResponse | null;
|
|
16
|
+
perPageOptions: number[];
|
|
17
|
+
currentPerPage: number;
|
|
18
|
+
showPerPageSelector: boolean;
|
|
19
|
+
}, {}, {}, {}, string, import('vue').ComponentProvideOptions, false, {}, HTMLDivElement>;
|
|
20
|
+
export default _default;
|
|
21
|
+
//# sourceMappingURL=DataTablePagination.vue.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"DataTablePagination.vue.d.ts","sourceRoot":"","sources":["../../src/components/DataTablePagination.vue"],"names":[],"mappings":"AAwOA,OAAO,KAAK,EAAE,yBAAyB,EAAE,MAAM,qCAAqC,CAAA;AAIpF,UAAU,KAAK;IACb,UAAU,CAAC,EAAE,yBAAyB,GAAG,IAAI,CAAA;IAC7C,cAAc,CAAC,EAAE,MAAM,EAAE,CAAA;IACzB,cAAc,CAAC,EAAE,MAAM,CAAA;IACvB,mBAAmB,CAAC,EAAE,OAAO,CAAA;CAC9B;;;;;;;;gBAJc,yBAAyB,GAAG,IAAI;oBAC5B,MAAM,EAAE;oBACR,MAAM;yBACD,OAAO;;AAuT/B,wBASG"}
|
package/dist/index.d.ts
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,OAAO,IAAI,SAAS,EAAE,MAAM,4BAA4B,CAAA;AACjE,OAAO,EAAE,OAAO,IAAI,mBAAmB,EAAE,MAAM,sCAAsC,CAAA;AAGrF,OAAO,EAAE,EAAE,EAAE,MAAM,aAAa,CAAA"}
|
package/dist/index.js
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
"use strict";Object.defineProperty(exports,Symbol.toStringTag,{value:"Module"});const e=require("vue"),x=require("@tanstack/vue-table"),y=require("lucide-vue-next"),B=require("clsx"),C=require("tailwind-merge"),E={class:"flex flex-col gap-4 px-2 py-4"},N={key:0,class:"flex justify-center"},V={class:"flex items-center gap-1",role:"navigation","aria-label":"pagination"},P=["disabled"],D=["disabled"],R={class:"flex items-center gap-1"},$=["onClick"],T={key:1,class:"inline-flex items-center justify-center h-10 w-10 text-gray-500"},j=["disabled"],F=["disabled"],L={class:"flex items-center justify-between text-sm text-gray-600 dark:text-gray-300"},z={key:0,class:"flex items-center gap-2"},I=["value"],M=["value"],O={key:1},S=e.defineComponent({__name:"DataTablePagination",props:{pagination:{default:null},perPageOptions:{default:()=>[10,15,25,50,100]},currentPerPage:{default:10},showPerPageSelector:{type:Boolean,default:!0}},emits:["pageChange","perPageChange"],setup(t,{emit:h}){const s=t,i=h,l=e.computed(()=>s.pagination?s.pagination.meta.current_page>1:!1),d=e.computed(()=>s.pagination?s.pagination.meta.current_page<s.pagination.meta.last_page:!1),f=e.computed(()=>{if(!s.pagination)return[];const g=s.pagination.meta.current_page,r=s.pagination.meta.last_page,o=2,n=[],m=[];let p;for(let a=1;a<=r;a++)(a===1||a===r||a>=g-o&&a<=g+o)&&n.push(a);for(const a of n)p&&(a-p===2?m.push(p+1):a-p!==1&&m.push("...")),m.push(a),p=a;return m}),b=g=>{typeof g=="number"&&i("pageChange",g)},u=()=>{l.value&&i("pageChange",1)},v=()=>{d.value&&s.pagination&&i("pageChange",s.pagination.meta.last_page)},w=()=>{l.value&&s.pagination&&i("pageChange",s.pagination.meta.current_page-1)},k=()=>{d.value&&s.pagination&&i("pageChange",s.pagination.meta.current_page+1)};return(g,r)=>(e.openBlock(),e.createElementBlock("div",E,[t.pagination&&t.pagination.meta.last_page>1?(e.openBlock(),e.createElementBlock("div",N,[e.createElementVNode("nav",V,[e.createElementVNode("button",{disabled:!l.value,class:e.normalizeClass(["inline-flex items-center justify-center gap-1 h-10 px-4 py-2 text-sm font-medium transition-colors rounded-md",l.value?"hover:bg-gray-100 dark:hover:bg-gray-800 text-gray-700 dark:text-gray-200":"opacity-50 cursor-not-allowed text-gray-400 dark:text-gray-600"]),onClick:u},[e.createVNode(e.unref(y.ChevronsLeft),{class:"h-4 w-4"}),r[1]||(r[1]=e.createElementVNode("span",{class:"hidden sm:inline"},"First",-1))],10,P),e.createElementVNode("button",{disabled:!l.value,class:e.normalizeClass(["inline-flex items-center justify-center gap-1 h-10 px-4 py-2 text-sm font-medium transition-colors rounded-md",l.value?"hover:bg-gray-100 dark:hover:bg-gray-800 text-gray-700 dark:text-gray-200":"opacity-50 cursor-not-allowed text-gray-400 dark:text-gray-600"]),onClick:w},[e.createVNode(e.unref(y.ChevronLeft),{class:"h-4 w-4"}),r[2]||(r[2]=e.createElementVNode("span",{class:"hidden sm:inline"},"Previous",-1))],10,D),e.createElementVNode("div",R,[(e.openBlock(!0),e.createElementBlock(e.Fragment,null,e.renderList(f.value,(o,n)=>(e.openBlock(),e.createElementBlock(e.Fragment,{key:n},[o!=="..."?(e.openBlock(),e.createElementBlock("button",{key:0,class:e.normalizeClass(["inline-flex items-center justify-center h-10 w-10 text-sm font-medium transition-colors rounded-md",o===t.pagination.meta.current_page?"bg-blue-500 text-white hover:bg-blue-600":"hover:bg-gray-100 dark:hover:bg-gray-800 text-gray-700 dark:text-gray-200"]),onClick:m=>b(o)},e.toDisplayString(o),11,$)):(e.openBlock(),e.createElementBlock("span",T," ... "))],64))),128))]),e.createElementVNode("button",{disabled:!d.value,class:e.normalizeClass(["inline-flex items-center justify-center gap-1 h-10 px-4 py-2 text-sm font-medium transition-colors rounded-md",d.value?"hover:bg-gray-100 dark:hover:bg-gray-800 text-gray-700 dark:text-gray-200":"opacity-50 cursor-not-allowed text-gray-400 dark:text-gray-600"]),onClick:k},[r[3]||(r[3]=e.createElementVNode("span",{class:"hidden sm:inline"},"Next",-1)),e.createVNode(e.unref(y.ChevronRight),{class:"h-4 w-4"})],10,j),e.createElementVNode("button",{disabled:!d.value,class:e.normalizeClass(["inline-flex items-center justify-center gap-1 h-10 px-4 py-2 text-sm font-medium transition-colors rounded-md",d.value?"hover:bg-gray-100 dark:hover:bg-gray-800 text-gray-700 dark:text-gray-200":"opacity-50 cursor-not-allowed text-gray-400 dark:text-gray-600"]),onClick:v},[r[4]||(r[4]=e.createElementVNode("span",{class:"hidden sm:inline"},"Last",-1)),e.createVNode(e.unref(y.ChevronsRight),{class:"h-4 w-4"})],10,F)])])):e.createCommentVNode("",!0),e.createElementVNode("div",L,[e.createElementVNode("div",null,[t.pagination&&t.pagination.meta.total>0?(e.openBlock(),e.createElementBlock(e.Fragment,{key:0},[e.createTextVNode(" Showing "+e.toDisplayString(t.pagination.meta.from)+" to "+e.toDisplayString(t.pagination.meta.to)+" of "+e.toDisplayString(t.pagination.meta.total)+" entries ",1)],64)):(e.openBlock(),e.createElementBlock(e.Fragment,{key:1},[e.createTextVNode(" No entries found ")],64))]),t.showPerPageSelector?(e.openBlock(),e.createElementBlock("div",z,[r[5]||(r[5]=e.createElementVNode("span",null,"Rows per page:",-1)),e.createElementVNode("select",{value:t.currentPerPage||t.perPageOptions[0],class:"h-10 rounded-md border border-input bg-background px-3 py-2 text-sm ring-offset-background focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2",onChange:r[0]||(r[0]=o=>i("perPageChange",Number(o.target.value)||t.perPageOptions[0]))},[(e.openBlock(!0),e.createElementBlock(e.Fragment,null,e.renderList(t.perPageOptions,o=>(e.openBlock(),e.createElementBlock("option",{key:o,value:o},e.toDisplayString(o),9,M))),128))],40,I)])):e.createCommentVNode("",!0),t.pagination?(e.openBlock(),e.createElementBlock("div",O," Page "+e.toDisplayString(t.pagination.meta.current_page)+" of "+e.toDisplayString(t.pagination.meta.last_page),1)):e.createCommentVNode("",!0)])]))}}),q={class:"flex flex-col gap-4"},_={class:"flex flex-col gap-4 sm:flex-row sm:items-center sm:justify-between"},A={class:"flex flex-col gap-2 sm:flex-row sm:items-center"},G={key:0,class:"relative items-center w-full max-w-sm"},H=["value"],U={class:"absolute inset-y-0 flex items-center justify-center px-2 start-0"},W={class:"flex items-center gap-2"},J={class:"flex items-center"},K={key:0,class:"flex items-center justify-between p-4 bg-blue-50 dark:bg-blue-900/20 border border-blue-200 dark:border-blue-800 rounded-lg"},Q={class:"flex items-center gap-4"},X={class:"text-sm font-medium text-blue-700 dark:text-blue-300"},Y={class:"text-xs text-blue-600 dark:text-blue-400"},Z={class:"flex items-center gap-2"},ee={key:1,class:"flex items-center justify-center p-8"},te={class:"text-lg text-gray-700 dark:text-gray-200"},oe={key:2,class:"flex flex-col items-center p-8"},ne={class:"mb-2 text-lg text-red-600 dark:text-red-400"},ae={class:"mb-4 text-sm text-gray-600 dark:text-gray-300"},le={key:3,class:"rounded-lg border bg-white dark:bg-gray-900"},re={key:0,class:"relative"},se={class:"relative w-full overflow-auto"},ie={class:"w-full caption-bottom text-sm"},ce={key:0,class:"mt-4 text-sm text-muted-foreground"},de={key:0,class:"ml-2 text-blue-600 dark:text-blue-400"},ge={class:"[&_tr]:border-b"},ue=["colspan"],me=["onClick"],pe={key:0,class:"flex flex-col"},fe={class:"[&_tr:last-child]:border-0"},ye={key:1},be=["colspan"],ke=e.defineComponent({__name:"DataTable",props:{data:{default:()=>[]},columns:{},pagination:{default:null},isLoading:{type:Boolean,default:!1},error:{default:null},search:{default:""},currentPerPage:{default:10},perPageOptions:{default:()=>[10,15,25,50,100]},sortBy:{default:null},sortDirection:{default:"asc"},rowSelection:{default:()=>({})},enableRowSelection:{type:Boolean,default:!1},getRowId:{type:Function,default:t=>t.id},showSearch:{type:Boolean,default:!0},showCaption:{type:Boolean,default:!0},showPerPageSelector:{type:Boolean,default:!0},title:{default:"Items"},itemName:{default:"items"},loadingText:{default:"Loading..."},errorTitle:{default:"Error loading data"},emptyStateText:{default:"📭 No items found"}},emits:["pageChange","perPageChange","searchChange","sortChange","retry","update:rowSelection"],setup(t,{expose:h,emit:s}){const i=s,l=t,d=e.computed(()=>Object.keys(l.rowSelection||{}).filter(o=>{var n;return(n=l.rowSelection)==null?void 0:n[o]}).length),f=e.computed(()=>Object.keys(l.rowSelection||{}).filter(o=>{var n;return(n=l.rowSelection)==null?void 0:n[o]})),b=e.computed(()=>!l.data||!l.rowSelection?[]:l.data.filter(o=>l.rowSelection[l.getRowId(o)])),u=x.useVueTable({get data(){return l.data||[]},columns:l.columns,getCoreRowModel:x.getCoreRowModel(),enableSorting:!0,manualSorting:!0,enableRowSelection:l.enableRowSelection,getRowId:l.getRowId,state:{rowSelection:l.rowSelection||{}},onRowSelectionChange:o=>{const n=typeof o=="function"?o(l.rowSelection||{}):o;i("update:rowSelection",n)},enableMultiRowSelection:!0,enableSubRowSelection:!1}),v=()=>f.value,w=()=>b.value,k=()=>i("update:rowSelection",{}),g=()=>{const o={...l.rowSelection};u.getRowModel().rows.forEach(n=>{o[n.id]=!0}),i("update:rowSelection",o)},r=()=>{const o={...l.rowSelection};u.getRowModel().rows.forEach(n=>{delete o[n.id]}),i("update:rowSelection",o)};return h({getSelectedRowIds:v,getSelectedRowData:w,clearSelection:k,selectAllCurrentPage:g,deselectAllCurrentPage:r,selectedRowCount:d,selectedRowIds:f,selectedRowData:b,table:u}),(o,n)=>{var m,p;return e.openBlock(),e.createElementBlock("div",q,[e.createElementVNode("div",_,[e.createElementVNode("div",A,[t.showSearch?(e.openBlock(),e.createElementBlock("div",G,[e.createElementVNode("input",{value:t.search,type:"text",placeholder:"Search...",class:"flex h-10 w-full rounded-md border border-input bg-background px-3 py-2 pl-10 text-sm ring-offset-background file:border-0 file:bg-transparent file:text-sm file:font-medium placeholder:text-muted-foreground focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2 disabled:cursor-not-allowed disabled:opacity-50",onInput:n[0]||(n[0]=a=>i("searchChange",a.target.value))},null,40,H),e.createElementVNode("span",U,[e.createVNode(e.unref(y.Search),{class:"size-6 text-gray-400"})])])):e.createCommentVNode("",!0),e.createElementVNode("div",W,[e.renderSlot(o.$slots,"filters")])]),e.createElementVNode("div",J,[e.renderSlot(o.$slots,"header")])]),t.enableRowSelection&&d.value>0?(e.openBlock(),e.createElementBlock("div",K,[e.createElementVNode("div",Q,[e.createElementVNode("span",X,e.toDisplayString(d.value)+" "+e.toDisplayString(t.itemName)+" selected ",1),e.createElementVNode("div",Y," IDs: "+e.toDisplayString(f.value.slice(0,5).join(", "))+e.toDisplayString(f.value.length>5?"...":""),1)]),e.createElementVNode("div",Z,[e.renderSlot(o.$slots,"bulk-actions",{selectedIds:f.value,selectedData:b.value,selectedCount:d.value,clearSelection:k,selectAllCurrentPage:g,deselectAllCurrentPage:r}),o.$slots["bulk-actions"]?e.createCommentVNode("",!0):(e.openBlock(),e.createElementBlock("button",{key:0,onClick:k,class:"px-3 py-1 text-sm text-blue-700 dark:text-blue-300 hover:bg-blue-100 dark:hover:bg-blue-800 rounded transition-colors"}," Clear Selection "))])])):e.createCommentVNode("",!0),t.isLoading&&!t.data?(e.openBlock(),e.createElementBlock("div",ee,[n[4]||(n[4]=e.createElementVNode("div",{class:"w-8 h-8 mr-3 border-b-2 border-gray-900 dark:border-gray-100 rounded-full animate-spin"},null,-1)),e.createElementVNode("div",te,e.toDisplayString(t.loadingText),1)])):t.error?(e.openBlock(),e.createElementBlock("div",oe,[e.createElementVNode("div",ne,"❌ "+e.toDisplayString(t.errorTitle),1),e.createElementVNode("div",ae,e.toDisplayString(t.error.message),1),e.createElementVNode("button",{class:"px-4 py-2 text-white transition-colors bg-gray-900 rounded-md hover:bg-gray-800 dark:bg-gray-100 dark:text-gray-900 dark:hover:bg-gray-200",onClick:n[1]||(n[1]=a=>i("retry"))}," 🔄 Retry ")])):(e.openBlock(),e.createElementBlock("div",le,[t.isLoading?(e.openBlock(),e.createElementBlock("div",re,[...n[5]||(n[5]=[e.createElementVNode("div",{class:"absolute inset-0 z-10 flex items-center justify-center bg-white/70 dark:bg-gray-900/70 rounded-lg"},[e.createElementVNode("div",{class:"w-6 h-6 border-b-2 border-gray-900 dark:border-gray-100 rounded-full animate-spin"})],-1)])])):e.createCommentVNode("",!0),e.createElementVNode("div",se,[e.createElementVNode("table",ie,[t.showCaption?(e.openBlock(),e.createElementBlock("caption",ce,[e.createTextVNode(e.toDisplayString(t.title)+" - Total: "+e.toDisplayString(((p=(m=t.pagination)==null?void 0:m.meta)==null?void 0:p.total)||0)+" "+e.toDisplayString(t.itemName)+" ",1),t.enableRowSelection&&d.value>0?(e.openBlock(),e.createElementBlock("span",de," ("+e.toDisplayString(d.value)+" selected) ",1)):e.createCommentVNode("",!0)])):e.createCommentVNode("",!0),e.createElementVNode("thead",ge,[(e.openBlock(!0),e.createElementBlock(e.Fragment,null,e.renderList(e.unref(u).getHeaderGroups(),a=>(e.openBlock(),e.createElementBlock("tr",{key:a.id,class:"border-b transition-colors hover:bg-muted/50 data-[state=selected]:bg-muted"},[(e.openBlock(!0),e.createElementBlock(e.Fragment,null,e.renderList(a.headers,c=>(e.openBlock(),e.createElementBlock("th",{key:c.id,colspan:c.colSpan,class:"h-12 px-4 text-left align-middle font-medium text-muted-foreground [&:has([role=checkbox])]:pr-0"},[c.isPlaceholder?e.createCommentVNode("",!0):(e.openBlock(),e.createElementBlock("div",{key:0,class:e.normalizeClass(["flex items-center gap-2",c.column.getCanSort()?"cursor-pointer select-none hover:bg-gray-50 dark:hover:bg-gray-800 p-2 rounded transition-colors":""]),onClick:he=>c.column.getCanSort()?i("sortChange",c.column.id):void 0},[e.createVNode(e.unref(x.FlexRender),{render:c.column.columnDef.header,props:c.getContext()},null,8,["render","props"]),c.column.getCanSort()?(e.openBlock(),e.createElementBlock("div",pe,[e.createVNode(e.unref(y.ChevronUp),{class:e.normalizeClass(["w-3 h-3 transition-colors",t.sortBy===c.column.id&&t.sortDirection==="asc"?"text-gray-900 dark:text-gray-100":"text-gray-400"])},null,8,["class"]),e.createVNode(e.unref(y.ChevronDown),{class:e.normalizeClass(["w-3 h-3 -mt-1 transition-colors",t.sortBy===c.column.id&&t.sortDirection==="desc"?"text-gray-900 dark:text-gray-100":"text-gray-400"])},null,8,["class"])])):e.createCommentVNode("",!0)],10,me))],8,ue))),128))]))),128))]),e.createElementVNode("tbody",fe,[e.unref(u).getRowModel().rows.length>0?(e.openBlock(!0),e.createElementBlock(e.Fragment,{key:0},e.renderList(e.unref(u).getRowModel().rows,a=>(e.openBlock(),e.createElementBlock("tr",{key:a.id,class:e.normalizeClass(["border-b transition-colors hover:bg-muted/50 data-[state=selected]:bg-muted",t.enableRowSelection&&a.getIsSelected()?"bg-blue-50 dark:bg-blue-900/20 border-l-4 border-l-blue-500":""])},[(e.openBlock(!0),e.createElementBlock(e.Fragment,null,e.renderList(a.getVisibleCells(),c=>(e.openBlock(),e.createElementBlock("td",{key:c.id,class:"p-4 align-middle [&:has([role=checkbox])]:pr-0"},[e.createVNode(e.unref(x.FlexRender),{render:c.column.columnDef.cell,props:c.getContext()},null,8,["render","props"])]))),128))],2))),128)):(e.openBlock(),e.createElementBlock("tr",ye,[e.createElementVNode("td",{colspan:t.columns.length,class:"h-24 text-center"},e.toDisplayString(t.emptyStateText),9,be)]))])])]),e.createVNode(S,{pagination:t.pagination,"current-per-page":t.currentPerPage,"per-page-options":t.perPageOptions,"show-per-page-selector":t.showPerPageSelector,onPageChange:n[2]||(n[2]=a=>i("pageChange",a)),onPerPageChange:n[3]||(n[3]=a=>i("perPageChange",a))},null,8,["pagination","current-per-page","per-page-options","show-per-page-selector"])]))])}}});function xe(...t){return C.twMerge(B.clsx(t))}exports.DataTable=ke;exports.DataTablePagination=S;exports.cn=xe;
|
package/dist/index.mjs
ADDED
|
@@ -0,0 +1,393 @@
|
|
|
1
|
+
import { defineComponent as L, computed as P, createElementBlock as a, openBlock as n, createCommentVNode as b, createElementVNode as t, normalizeClass as h, createVNode as y, unref as f, Fragment as p, renderList as S, toDisplayString as i, createTextVNode as B, renderSlot as N } from "vue";
|
|
2
|
+
import { useVueTable as M, getCoreRowModel as O, FlexRender as I } from "@tanstack/vue-table";
|
|
3
|
+
import { ChevronsLeft as V, ChevronLeft as E, ChevronRight as F, ChevronsRight as _, Search as z, ChevronUp as A, ChevronDown as G } from "lucide-vue-next";
|
|
4
|
+
import { clsx as H } from "clsx";
|
|
5
|
+
import { twMerge as U } from "tailwind-merge";
|
|
6
|
+
const W = { class: "flex flex-col gap-4 px-2 py-4" }, q = {
|
|
7
|
+
key: 0,
|
|
8
|
+
class: "flex justify-center"
|
|
9
|
+
}, J = {
|
|
10
|
+
class: "flex items-center gap-1",
|
|
11
|
+
role: "navigation",
|
|
12
|
+
"aria-label": "pagination"
|
|
13
|
+
}, K = ["disabled"], Q = ["disabled"], X = { class: "flex items-center gap-1" }, Y = ["onClick"], Z = {
|
|
14
|
+
key: 1,
|
|
15
|
+
class: "inline-flex items-center justify-center h-10 w-10 text-gray-500"
|
|
16
|
+
}, ee = ["disabled"], te = ["disabled"], oe = { class: "flex items-center justify-between text-sm text-gray-600 dark:text-gray-300" }, ae = {
|
|
17
|
+
key: 0,
|
|
18
|
+
class: "flex items-center gap-2"
|
|
19
|
+
}, ne = ["value"], se = ["value"], re = { key: 1 }, le = /* @__PURE__ */ L({
|
|
20
|
+
__name: "DataTablePagination",
|
|
21
|
+
props: {
|
|
22
|
+
pagination: { default: null },
|
|
23
|
+
perPageOptions: { default: () => [10, 15, 25, 50, 100] },
|
|
24
|
+
currentPerPage: { default: 10 },
|
|
25
|
+
showPerPageSelector: { type: Boolean, default: !0 }
|
|
26
|
+
},
|
|
27
|
+
emits: ["pageChange", "perPageChange"],
|
|
28
|
+
setup(e, { emit: T }) {
|
|
29
|
+
const c = e, g = T, l = P(
|
|
30
|
+
() => c.pagination ? c.pagination.meta.current_page > 1 : !1
|
|
31
|
+
), m = P(
|
|
32
|
+
() => c.pagination ? c.pagination.meta.current_page < c.pagination.meta.last_page : !1
|
|
33
|
+
), C = P(() => {
|
|
34
|
+
if (!c.pagination) return [];
|
|
35
|
+
const x = c.pagination.meta.current_page, d = c.pagination.meta.last_page, o = 2, s = [], w = [];
|
|
36
|
+
let k;
|
|
37
|
+
for (let r = 1; r <= d; r++)
|
|
38
|
+
(r === 1 || r === d || r >= x - o && r <= x + o) && s.push(r);
|
|
39
|
+
for (const r of s)
|
|
40
|
+
k && (r - k === 2 ? w.push(k + 1) : r - k !== 1 && w.push("...")), w.push(r), k = r;
|
|
41
|
+
return w;
|
|
42
|
+
}), R = (x) => {
|
|
43
|
+
typeof x == "number" && g("pageChange", x);
|
|
44
|
+
}, v = () => {
|
|
45
|
+
l.value && g("pageChange", 1);
|
|
46
|
+
}, j = () => {
|
|
47
|
+
m.value && c.pagination && g("pageChange", c.pagination.meta.last_page);
|
|
48
|
+
}, D = () => {
|
|
49
|
+
l.value && c.pagination && g("pageChange", c.pagination.meta.current_page - 1);
|
|
50
|
+
}, $ = () => {
|
|
51
|
+
m.value && c.pagination && g("pageChange", c.pagination.meta.current_page + 1);
|
|
52
|
+
};
|
|
53
|
+
return (x, d) => (n(), a("div", W, [
|
|
54
|
+
e.pagination && e.pagination.meta.last_page > 1 ? (n(), a("div", q, [
|
|
55
|
+
t("nav", J, [
|
|
56
|
+
t("button", {
|
|
57
|
+
disabled: !l.value,
|
|
58
|
+
class: h([
|
|
59
|
+
"inline-flex items-center justify-center gap-1 h-10 px-4 py-2 text-sm font-medium transition-colors rounded-md",
|
|
60
|
+
l.value ? "hover:bg-gray-100 dark:hover:bg-gray-800 text-gray-700 dark:text-gray-200" : "opacity-50 cursor-not-allowed text-gray-400 dark:text-gray-600"
|
|
61
|
+
]),
|
|
62
|
+
onClick: v
|
|
63
|
+
}, [
|
|
64
|
+
y(f(V), { class: "h-4 w-4" }),
|
|
65
|
+
d[1] || (d[1] = t("span", { class: "hidden sm:inline" }, "First", -1))
|
|
66
|
+
], 10, K),
|
|
67
|
+
t("button", {
|
|
68
|
+
disabled: !l.value,
|
|
69
|
+
class: h([
|
|
70
|
+
"inline-flex items-center justify-center gap-1 h-10 px-4 py-2 text-sm font-medium transition-colors rounded-md",
|
|
71
|
+
l.value ? "hover:bg-gray-100 dark:hover:bg-gray-800 text-gray-700 dark:text-gray-200" : "opacity-50 cursor-not-allowed text-gray-400 dark:text-gray-600"
|
|
72
|
+
]),
|
|
73
|
+
onClick: D
|
|
74
|
+
}, [
|
|
75
|
+
y(f(E), { class: "h-4 w-4" }),
|
|
76
|
+
d[2] || (d[2] = t("span", { class: "hidden sm:inline" }, "Previous", -1))
|
|
77
|
+
], 10, Q),
|
|
78
|
+
t("div", X, [
|
|
79
|
+
(n(!0), a(p, null, S(C.value, (o, s) => (n(), a(p, { key: s }, [
|
|
80
|
+
o !== "..." ? (n(), a("button", {
|
|
81
|
+
key: 0,
|
|
82
|
+
class: h([
|
|
83
|
+
"inline-flex items-center justify-center h-10 w-10 text-sm font-medium transition-colors rounded-md",
|
|
84
|
+
o === e.pagination.meta.current_page ? "bg-blue-500 text-white hover:bg-blue-600" : "hover:bg-gray-100 dark:hover:bg-gray-800 text-gray-700 dark:text-gray-200"
|
|
85
|
+
]),
|
|
86
|
+
onClick: (w) => R(o)
|
|
87
|
+
}, i(o), 11, Y)) : (n(), a("span", Z, " ... "))
|
|
88
|
+
], 64))), 128))
|
|
89
|
+
]),
|
|
90
|
+
t("button", {
|
|
91
|
+
disabled: !m.value,
|
|
92
|
+
class: h([
|
|
93
|
+
"inline-flex items-center justify-center gap-1 h-10 px-4 py-2 text-sm font-medium transition-colors rounded-md",
|
|
94
|
+
m.value ? "hover:bg-gray-100 dark:hover:bg-gray-800 text-gray-700 dark:text-gray-200" : "opacity-50 cursor-not-allowed text-gray-400 dark:text-gray-600"
|
|
95
|
+
]),
|
|
96
|
+
onClick: $
|
|
97
|
+
}, [
|
|
98
|
+
d[3] || (d[3] = t("span", { class: "hidden sm:inline" }, "Next", -1)),
|
|
99
|
+
y(f(F), { class: "h-4 w-4" })
|
|
100
|
+
], 10, ee),
|
|
101
|
+
t("button", {
|
|
102
|
+
disabled: !m.value,
|
|
103
|
+
class: h([
|
|
104
|
+
"inline-flex items-center justify-center gap-1 h-10 px-4 py-2 text-sm font-medium transition-colors rounded-md",
|
|
105
|
+
m.value ? "hover:bg-gray-100 dark:hover:bg-gray-800 text-gray-700 dark:text-gray-200" : "opacity-50 cursor-not-allowed text-gray-400 dark:text-gray-600"
|
|
106
|
+
]),
|
|
107
|
+
onClick: j
|
|
108
|
+
}, [
|
|
109
|
+
d[4] || (d[4] = t("span", { class: "hidden sm:inline" }, "Last", -1)),
|
|
110
|
+
y(f(_), { class: "h-4 w-4" })
|
|
111
|
+
], 10, te)
|
|
112
|
+
])
|
|
113
|
+
])) : b("", !0),
|
|
114
|
+
t("div", oe, [
|
|
115
|
+
t("div", null, [
|
|
116
|
+
e.pagination && e.pagination.meta.total > 0 ? (n(), a(p, { key: 0 }, [
|
|
117
|
+
B(" Showing " + i(e.pagination.meta.from) + " to " + i(e.pagination.meta.to) + " of " + i(e.pagination.meta.total) + " entries ", 1)
|
|
118
|
+
], 64)) : (n(), a(p, { key: 1 }, [
|
|
119
|
+
B(" No entries found ")
|
|
120
|
+
], 64))
|
|
121
|
+
]),
|
|
122
|
+
e.showPerPageSelector ? (n(), a("div", ae, [
|
|
123
|
+
d[5] || (d[5] = t("span", null, "Rows per page:", -1)),
|
|
124
|
+
t("select", {
|
|
125
|
+
value: e.currentPerPage || e.perPageOptions[0],
|
|
126
|
+
class: "h-10 rounded-md border border-input bg-background px-3 py-2 text-sm ring-offset-background focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2",
|
|
127
|
+
onChange: d[0] || (d[0] = (o) => g("perPageChange", Number(o.target.value) || e.perPageOptions[0]))
|
|
128
|
+
}, [
|
|
129
|
+
(n(!0), a(p, null, S(e.perPageOptions, (o) => (n(), a("option", {
|
|
130
|
+
key: o,
|
|
131
|
+
value: o
|
|
132
|
+
}, i(o), 9, se))), 128))
|
|
133
|
+
], 40, ne)
|
|
134
|
+
])) : b("", !0),
|
|
135
|
+
e.pagination ? (n(), a("div", re, " Page " + i(e.pagination.meta.current_page) + " of " + i(e.pagination.meta.last_page), 1)) : b("", !0)
|
|
136
|
+
])
|
|
137
|
+
]));
|
|
138
|
+
}
|
|
139
|
+
}), ie = { class: "flex flex-col gap-4" }, de = { class: "flex flex-col gap-4 sm:flex-row sm:items-center sm:justify-between" }, ce = { class: "flex flex-col gap-2 sm:flex-row sm:items-center" }, ge = {
|
|
140
|
+
key: 0,
|
|
141
|
+
class: "relative items-center w-full max-w-sm"
|
|
142
|
+
}, ue = ["value"], me = { class: "absolute inset-y-0 flex items-center justify-center px-2 start-0" }, fe = { class: "flex items-center gap-2" }, be = { class: "flex items-center" }, ye = {
|
|
143
|
+
key: 0,
|
|
144
|
+
class: "flex items-center justify-between p-4 bg-blue-50 dark:bg-blue-900/20 border border-blue-200 dark:border-blue-800 rounded-lg"
|
|
145
|
+
}, xe = { class: "flex items-center gap-4" }, he = { class: "text-sm font-medium text-blue-700 dark:text-blue-300" }, pe = { class: "text-xs text-blue-600 dark:text-blue-400" }, ve = { class: "flex items-center gap-2" }, we = {
|
|
146
|
+
key: 1,
|
|
147
|
+
class: "flex items-center justify-center p-8"
|
|
148
|
+
}, ke = { class: "text-lg text-gray-700 dark:text-gray-200" }, Ce = {
|
|
149
|
+
key: 2,
|
|
150
|
+
class: "flex flex-col items-center p-8"
|
|
151
|
+
}, Se = { class: "mb-2 text-lg text-red-600 dark:text-red-400" }, Pe = { class: "mb-4 text-sm text-gray-600 dark:text-gray-300" }, Re = {
|
|
152
|
+
key: 3,
|
|
153
|
+
class: "rounded-lg border bg-white dark:bg-gray-900"
|
|
154
|
+
}, $e = {
|
|
155
|
+
key: 0,
|
|
156
|
+
class: "relative"
|
|
157
|
+
}, Te = { class: "relative w-full overflow-auto" }, je = { class: "w-full caption-bottom text-sm" }, De = {
|
|
158
|
+
key: 0,
|
|
159
|
+
class: "mt-4 text-sm text-muted-foreground"
|
|
160
|
+
}, Ne = {
|
|
161
|
+
key: 0,
|
|
162
|
+
class: "ml-2 text-blue-600 dark:text-blue-400"
|
|
163
|
+
}, Be = { class: "[&_tr]:border-b" }, Ie = ["colspan"], Le = ["onClick"], Me = {
|
|
164
|
+
key: 0,
|
|
165
|
+
class: "flex flex-col"
|
|
166
|
+
}, Oe = { class: "[&_tr:last-child]:border-0" }, Ve = { key: 1 }, Ee = ["colspan"], Ue = /* @__PURE__ */ L({
|
|
167
|
+
__name: "DataTable",
|
|
168
|
+
props: {
|
|
169
|
+
data: { default: () => [] },
|
|
170
|
+
columns: {},
|
|
171
|
+
pagination: { default: null },
|
|
172
|
+
isLoading: { type: Boolean, default: !1 },
|
|
173
|
+
error: { default: null },
|
|
174
|
+
search: { default: "" },
|
|
175
|
+
currentPerPage: { default: 10 },
|
|
176
|
+
perPageOptions: { default: () => [10, 15, 25, 50, 100] },
|
|
177
|
+
sortBy: { default: null },
|
|
178
|
+
sortDirection: { default: "asc" },
|
|
179
|
+
rowSelection: { default: () => ({}) },
|
|
180
|
+
enableRowSelection: { type: Boolean, default: !1 },
|
|
181
|
+
getRowId: { type: Function, default: (e) => e.id },
|
|
182
|
+
showSearch: { type: Boolean, default: !0 },
|
|
183
|
+
showCaption: { type: Boolean, default: !0 },
|
|
184
|
+
showPerPageSelector: { type: Boolean, default: !0 },
|
|
185
|
+
title: { default: "Items" },
|
|
186
|
+
itemName: { default: "items" },
|
|
187
|
+
loadingText: { default: "Loading..." },
|
|
188
|
+
errorTitle: { default: "Error loading data" },
|
|
189
|
+
emptyStateText: { default: "📭 No items found" }
|
|
190
|
+
},
|
|
191
|
+
emits: ["pageChange", "perPageChange", "searchChange", "sortChange", "retry", "update:rowSelection"],
|
|
192
|
+
setup(e, { expose: T, emit: c }) {
|
|
193
|
+
const g = c, l = e, m = P(() => Object.keys(l.rowSelection || {}).filter((o) => {
|
|
194
|
+
var s;
|
|
195
|
+
return (s = l.rowSelection) == null ? void 0 : s[o];
|
|
196
|
+
}).length), C = P(() => Object.keys(l.rowSelection || {}).filter((o) => {
|
|
197
|
+
var s;
|
|
198
|
+
return (s = l.rowSelection) == null ? void 0 : s[o];
|
|
199
|
+
})), R = P(() => !l.data || !l.rowSelection ? [] : l.data.filter((o) => l.rowSelection[l.getRowId(o)])), v = M({
|
|
200
|
+
get data() {
|
|
201
|
+
return l.data || [];
|
|
202
|
+
},
|
|
203
|
+
columns: l.columns,
|
|
204
|
+
getCoreRowModel: O(),
|
|
205
|
+
enableSorting: !0,
|
|
206
|
+
manualSorting: !0,
|
|
207
|
+
enableRowSelection: l.enableRowSelection,
|
|
208
|
+
getRowId: l.getRowId,
|
|
209
|
+
state: {
|
|
210
|
+
rowSelection: l.rowSelection || {}
|
|
211
|
+
},
|
|
212
|
+
onRowSelectionChange: (o) => {
|
|
213
|
+
const s = typeof o == "function" ? o(l.rowSelection || {}) : o;
|
|
214
|
+
g("update:rowSelection", s);
|
|
215
|
+
},
|
|
216
|
+
enableMultiRowSelection: !0,
|
|
217
|
+
enableSubRowSelection: !1
|
|
218
|
+
}), j = () => C.value, D = () => R.value, $ = () => g("update:rowSelection", {}), x = () => {
|
|
219
|
+
const o = { ...l.rowSelection };
|
|
220
|
+
v.getRowModel().rows.forEach((s) => {
|
|
221
|
+
o[s.id] = !0;
|
|
222
|
+
}), g("update:rowSelection", o);
|
|
223
|
+
}, d = () => {
|
|
224
|
+
const o = { ...l.rowSelection };
|
|
225
|
+
v.getRowModel().rows.forEach((s) => {
|
|
226
|
+
delete o[s.id];
|
|
227
|
+
}), g("update:rowSelection", o);
|
|
228
|
+
};
|
|
229
|
+
return T({
|
|
230
|
+
getSelectedRowIds: j,
|
|
231
|
+
getSelectedRowData: D,
|
|
232
|
+
clearSelection: $,
|
|
233
|
+
selectAllCurrentPage: x,
|
|
234
|
+
deselectAllCurrentPage: d,
|
|
235
|
+
selectedRowCount: m,
|
|
236
|
+
selectedRowIds: C,
|
|
237
|
+
selectedRowData: R,
|
|
238
|
+
table: v
|
|
239
|
+
}), (o, s) => {
|
|
240
|
+
var w, k;
|
|
241
|
+
return n(), a("div", ie, [
|
|
242
|
+
t("div", de, [
|
|
243
|
+
t("div", ce, [
|
|
244
|
+
e.showSearch ? (n(), a("div", ge, [
|
|
245
|
+
t("input", {
|
|
246
|
+
value: e.search,
|
|
247
|
+
type: "text",
|
|
248
|
+
placeholder: "Search...",
|
|
249
|
+
class: "flex h-10 w-full rounded-md border border-input bg-background px-3 py-2 pl-10 text-sm ring-offset-background file:border-0 file:bg-transparent file:text-sm file:font-medium placeholder:text-muted-foreground focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2 disabled:cursor-not-allowed disabled:opacity-50",
|
|
250
|
+
onInput: s[0] || (s[0] = (r) => g("searchChange", r.target.value))
|
|
251
|
+
}, null, 40, ue),
|
|
252
|
+
t("span", me, [
|
|
253
|
+
y(f(z), { class: "size-6 text-gray-400" })
|
|
254
|
+
])
|
|
255
|
+
])) : b("", !0),
|
|
256
|
+
t("div", fe, [
|
|
257
|
+
N(o.$slots, "filters")
|
|
258
|
+
])
|
|
259
|
+
]),
|
|
260
|
+
t("div", be, [
|
|
261
|
+
N(o.$slots, "header")
|
|
262
|
+
])
|
|
263
|
+
]),
|
|
264
|
+
e.enableRowSelection && m.value > 0 ? (n(), a("div", ye, [
|
|
265
|
+
t("div", xe, [
|
|
266
|
+
t("span", he, i(m.value) + " " + i(e.itemName) + " selected ", 1),
|
|
267
|
+
t("div", pe, " IDs: " + i(C.value.slice(0, 5).join(", ")) + i(C.value.length > 5 ? "..." : ""), 1)
|
|
268
|
+
]),
|
|
269
|
+
t("div", ve, [
|
|
270
|
+
N(o.$slots, "bulk-actions", {
|
|
271
|
+
selectedIds: C.value,
|
|
272
|
+
selectedData: R.value,
|
|
273
|
+
selectedCount: m.value,
|
|
274
|
+
clearSelection: $,
|
|
275
|
+
selectAllCurrentPage: x,
|
|
276
|
+
deselectAllCurrentPage: d
|
|
277
|
+
}),
|
|
278
|
+
o.$slots["bulk-actions"] ? b("", !0) : (n(), a("button", {
|
|
279
|
+
key: 0,
|
|
280
|
+
onClick: $,
|
|
281
|
+
class: "px-3 py-1 text-sm text-blue-700 dark:text-blue-300 hover:bg-blue-100 dark:hover:bg-blue-800 rounded transition-colors"
|
|
282
|
+
}, " Clear Selection "))
|
|
283
|
+
])
|
|
284
|
+
])) : b("", !0),
|
|
285
|
+
e.isLoading && !e.data ? (n(), a("div", we, [
|
|
286
|
+
s[4] || (s[4] = t("div", { class: "w-8 h-8 mr-3 border-b-2 border-gray-900 dark:border-gray-100 rounded-full animate-spin" }, null, -1)),
|
|
287
|
+
t("div", ke, i(e.loadingText), 1)
|
|
288
|
+
])) : e.error ? (n(), a("div", Ce, [
|
|
289
|
+
t("div", Se, "❌ " + i(e.errorTitle), 1),
|
|
290
|
+
t("div", Pe, i(e.error.message), 1),
|
|
291
|
+
t("button", {
|
|
292
|
+
class: "px-4 py-2 text-white transition-colors bg-gray-900 rounded-md hover:bg-gray-800 dark:bg-gray-100 dark:text-gray-900 dark:hover:bg-gray-200",
|
|
293
|
+
onClick: s[1] || (s[1] = (r) => g("retry"))
|
|
294
|
+
}, " 🔄 Retry ")
|
|
295
|
+
])) : (n(), a("div", Re, [
|
|
296
|
+
e.isLoading ? (n(), a("div", $e, [...s[5] || (s[5] = [
|
|
297
|
+
t("div", { class: "absolute inset-0 z-10 flex items-center justify-center bg-white/70 dark:bg-gray-900/70 rounded-lg" }, [
|
|
298
|
+
t("div", { class: "w-6 h-6 border-b-2 border-gray-900 dark:border-gray-100 rounded-full animate-spin" })
|
|
299
|
+
], -1)
|
|
300
|
+
])])) : b("", !0),
|
|
301
|
+
t("div", Te, [
|
|
302
|
+
t("table", je, [
|
|
303
|
+
e.showCaption ? (n(), a("caption", De, [
|
|
304
|
+
B(i(e.title) + " - Total: " + i(((k = (w = e.pagination) == null ? void 0 : w.meta) == null ? void 0 : k.total) || 0) + " " + i(e.itemName) + " ", 1),
|
|
305
|
+
e.enableRowSelection && m.value > 0 ? (n(), a("span", Ne, " (" + i(m.value) + " selected) ", 1)) : b("", !0)
|
|
306
|
+
])) : b("", !0),
|
|
307
|
+
t("thead", Be, [
|
|
308
|
+
(n(!0), a(p, null, S(f(v).getHeaderGroups(), (r) => (n(), a("tr", {
|
|
309
|
+
key: r.id,
|
|
310
|
+
class: "border-b transition-colors hover:bg-muted/50 data-[state=selected]:bg-muted"
|
|
311
|
+
}, [
|
|
312
|
+
(n(!0), a(p, null, S(r.headers, (u) => (n(), a("th", {
|
|
313
|
+
key: u.id,
|
|
314
|
+
colspan: u.colSpan,
|
|
315
|
+
class: "h-12 px-4 text-left align-middle font-medium text-muted-foreground [&:has([role=checkbox])]:pr-0"
|
|
316
|
+
}, [
|
|
317
|
+
u.isPlaceholder ? b("", !0) : (n(), a("div", {
|
|
318
|
+
key: 0,
|
|
319
|
+
class: h([
|
|
320
|
+
"flex items-center gap-2",
|
|
321
|
+
u.column.getCanSort() ? "cursor-pointer select-none hover:bg-gray-50 dark:hover:bg-gray-800 p-2 rounded transition-colors" : ""
|
|
322
|
+
]),
|
|
323
|
+
onClick: (Fe) => u.column.getCanSort() ? g("sortChange", u.column.id) : void 0
|
|
324
|
+
}, [
|
|
325
|
+
y(f(I), {
|
|
326
|
+
render: u.column.columnDef.header,
|
|
327
|
+
props: u.getContext()
|
|
328
|
+
}, null, 8, ["render", "props"]),
|
|
329
|
+
u.column.getCanSort() ? (n(), a("div", Me, [
|
|
330
|
+
y(f(A), {
|
|
331
|
+
class: h([
|
|
332
|
+
"w-3 h-3 transition-colors",
|
|
333
|
+
e.sortBy === u.column.id && e.sortDirection === "asc" ? "text-gray-900 dark:text-gray-100" : "text-gray-400"
|
|
334
|
+
])
|
|
335
|
+
}, null, 8, ["class"]),
|
|
336
|
+
y(f(G), {
|
|
337
|
+
class: h([
|
|
338
|
+
"w-3 h-3 -mt-1 transition-colors",
|
|
339
|
+
e.sortBy === u.column.id && e.sortDirection === "desc" ? "text-gray-900 dark:text-gray-100" : "text-gray-400"
|
|
340
|
+
])
|
|
341
|
+
}, null, 8, ["class"])
|
|
342
|
+
])) : b("", !0)
|
|
343
|
+
], 10, Le))
|
|
344
|
+
], 8, Ie))), 128))
|
|
345
|
+
]))), 128))
|
|
346
|
+
]),
|
|
347
|
+
t("tbody", Oe, [
|
|
348
|
+
f(v).getRowModel().rows.length > 0 ? (n(!0), a(p, { key: 0 }, S(f(v).getRowModel().rows, (r) => (n(), a("tr", {
|
|
349
|
+
key: r.id,
|
|
350
|
+
class: h([
|
|
351
|
+
"border-b transition-colors hover:bg-muted/50 data-[state=selected]:bg-muted",
|
|
352
|
+
e.enableRowSelection && r.getIsSelected() ? "bg-blue-50 dark:bg-blue-900/20 border-l-4 border-l-blue-500" : ""
|
|
353
|
+
])
|
|
354
|
+
}, [
|
|
355
|
+
(n(!0), a(p, null, S(r.getVisibleCells(), (u) => (n(), a("td", {
|
|
356
|
+
key: u.id,
|
|
357
|
+
class: "p-4 align-middle [&:has([role=checkbox])]:pr-0"
|
|
358
|
+
}, [
|
|
359
|
+
y(f(I), {
|
|
360
|
+
render: u.column.columnDef.cell,
|
|
361
|
+
props: u.getContext()
|
|
362
|
+
}, null, 8, ["render", "props"])
|
|
363
|
+
]))), 128))
|
|
364
|
+
], 2))), 128)) : (n(), a("tr", Ve, [
|
|
365
|
+
t("td", {
|
|
366
|
+
colspan: e.columns.length,
|
|
367
|
+
class: "h-24 text-center"
|
|
368
|
+
}, i(e.emptyStateText), 9, Ee)
|
|
369
|
+
]))
|
|
370
|
+
])
|
|
371
|
+
])
|
|
372
|
+
]),
|
|
373
|
+
y(le, {
|
|
374
|
+
pagination: e.pagination,
|
|
375
|
+
"current-per-page": e.currentPerPage,
|
|
376
|
+
"per-page-options": e.perPageOptions,
|
|
377
|
+
"show-per-page-selector": e.showPerPageSelector,
|
|
378
|
+
onPageChange: s[2] || (s[2] = (r) => g("pageChange", r)),
|
|
379
|
+
onPerPageChange: s[3] || (s[3] = (r) => g("perPageChange", r))
|
|
380
|
+
}, null, 8, ["pagination", "current-per-page", "per-page-options", "show-per-page-selector"])
|
|
381
|
+
]))
|
|
382
|
+
]);
|
|
383
|
+
};
|
|
384
|
+
}
|
|
385
|
+
});
|
|
386
|
+
function We(...e) {
|
|
387
|
+
return U(H(e));
|
|
388
|
+
}
|
|
389
|
+
export {
|
|
390
|
+
Ue as DataTable,
|
|
391
|
+
le as DataTablePagination,
|
|
392
|
+
We as cn
|
|
393
|
+
};
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"utils.d.ts","sourceRoot":"","sources":["../../src/lib/utils.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,KAAK,UAAU,EAAQ,MAAM,MAAM,CAAA;AAG5C,wBAAgB,EAAE,CAAC,GAAG,MAAM,EAAE,UAAU,EAAE,UAEzC"}
|
package/package.json
ADDED
|
@@ -0,0 +1,77 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@toniel/laravel-tanstack-datatable",
|
|
3
|
+
"version": "0.1.0",
|
|
4
|
+
"description": "Vue 3 DataTable components for Laravel pagination with TanStack Query and shadcn-vue",
|
|
5
|
+
"type": "module",
|
|
6
|
+
"main": "./dist/index.js",
|
|
7
|
+
"module": "./dist/index.mjs",
|
|
8
|
+
"types": "./dist/index.d.ts",
|
|
9
|
+
"exports": {
|
|
10
|
+
".": {
|
|
11
|
+
"types": "./dist/index.d.ts",
|
|
12
|
+
"import": "./dist/index.mjs",
|
|
13
|
+
"require": "./dist/index.js"
|
|
14
|
+
},
|
|
15
|
+
"./style.css": "./dist/style.css"
|
|
16
|
+
},
|
|
17
|
+
"files": [
|
|
18
|
+
"dist",
|
|
19
|
+
"README.md"
|
|
20
|
+
],
|
|
21
|
+
"scripts": {
|
|
22
|
+
"dev": "vite build --watch",
|
|
23
|
+
"build": "vite build && vue-tsc --declaration --emitDeclarationOnly --outDir dist",
|
|
24
|
+
"prepublishOnly": "npm run build"
|
|
25
|
+
},
|
|
26
|
+
"keywords": [
|
|
27
|
+
"vue",
|
|
28
|
+
"vue3",
|
|
29
|
+
"laravel",
|
|
30
|
+
"pagination",
|
|
31
|
+
"datatable",
|
|
32
|
+
"tanstack-query",
|
|
33
|
+
"tanstack-table",
|
|
34
|
+
"table",
|
|
35
|
+
"components",
|
|
36
|
+
"typescript",
|
|
37
|
+
"tailwindcss",
|
|
38
|
+
"ui-components"
|
|
39
|
+
],
|
|
40
|
+
"author": "Toniel <toniel@example.com>",
|
|
41
|
+
"license": "MIT",
|
|
42
|
+
"repository": {
|
|
43
|
+
"type": "git",
|
|
44
|
+
"url": "https://github.com/toniel/laravel-tanstack-datatable.git"
|
|
45
|
+
},
|
|
46
|
+
"homepage": "https://github.com/toniel/laravel-tanstack-datatable#readme",
|
|
47
|
+
"bugs": {
|
|
48
|
+
"url": "https://github.com/toniel/laravel-tanstack-datatable/issues"
|
|
49
|
+
},
|
|
50
|
+
"peerDependencies": {
|
|
51
|
+
"vue": "^3.0.0",
|
|
52
|
+
"@tanstack/vue-query": "^5.0.0",
|
|
53
|
+
"@tanstack/vue-table": "^8.0.0",
|
|
54
|
+
"@toniel/laravel-tanstack-pagination": "^0.1.0",
|
|
55
|
+
"radix-vue": "^1.0.0",
|
|
56
|
+
"class-variance-authority": "^0.7.0",
|
|
57
|
+
"clsx": "^2.0.0",
|
|
58
|
+
"tailwind-merge": "^2.0.0",
|
|
59
|
+
"lucide-vue-next": "^0.460.0"
|
|
60
|
+
},
|
|
61
|
+
"devDependencies": {
|
|
62
|
+
"@tanstack/vue-query": "^5.83.1",
|
|
63
|
+
"@tanstack/vue-table": "^8.20.5",
|
|
64
|
+
"@types/node": "^22.0.0",
|
|
65
|
+
"@vitejs/plugin-vue": "^5.0.0",
|
|
66
|
+
"class-variance-authority": "^0.7.1",
|
|
67
|
+
"clsx": "^2.1.1",
|
|
68
|
+
"lucide-vue-next": "^0.460.0",
|
|
69
|
+
"radix-vue": "^1.9.9",
|
|
70
|
+
"tailwind-merge": "^2.5.5",
|
|
71
|
+
"typescript": "^5.6.0",
|
|
72
|
+
"vite": "^6.0.0",
|
|
73
|
+
"vite-plugin-dts": "^4.0.0",
|
|
74
|
+
"vue": "^3.5.0",
|
|
75
|
+
"vue-tsc": "^2.0.0"
|
|
76
|
+
}
|
|
77
|
+
}
|