@veristone/nuxt-v-app 0.2.5 → 0.2.6

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.
@@ -32,13 +32,15 @@ The primary table component. Wraps Nuxt UI's `<UTable>` with a toolbar, filter c
32
32
  | `data` | `unknown[]` | **required** | Array of row data |
33
33
  | `columns` | `TableColumn[]` | **required** | TanStack column definitions |
34
34
  | `loading` | `boolean` | `false` | Shows loading skeleton on initial load |
35
- | `initialPageLimit` | `number` | `10` | Rows per page |
35
+ | `initialPageLimit` | `number` | `10` | Rows per page (client-side mode) |
36
36
  | `selectable` | `boolean` | `false` | Enable row selection checkboxes |
37
37
  | `filters` | `FilterDefinition[]` | — | Filter dropdown definitions |
38
38
  | `onRefresh` | `() => void \| Promise<void>` | — | Shows refresh button; called on click |
39
39
  | `onRowClick` | `(row: unknown) => void` | — | Called when a row is clicked |
40
40
  | `defaultSort` | `string` | — | Column accessorKey to sort by on mount |
41
41
  | `defaultSortDesc` | `boolean` | `false` | Sort descending by default |
42
+ | `manualPagination` | `boolean` | `false` | Enable server-side pagination mode |
43
+ | `total` | `number` | — | Total row count from server (required for manualPagination) |
42
44
 
43
45
  #### v-model Bindings
44
46
 
@@ -46,6 +48,9 @@ The primary table component. Wraps Nuxt UI's `<UTable>` with a toolbar, filter c
46
48
  |-------|------|-------------|
47
49
  | `sorting` | `SortingState` | TanStack sorting state |
48
50
  | `filterValues` | `Record<string, unknown>` | Active filter values |
51
+ | `globalFilter` | `string` | Search/query filter |
52
+ | `page` | `number` | Current page (1-based, server-side mode) |
53
+ | `itemsPerPage` | `number` | Page size (server-side mode) |
49
54
 
50
55
  #### Slots
51
56
 
@@ -371,6 +376,58 @@ const columns = [
371
376
  </template>
372
377
  ```
373
378
 
379
+ ### Server-side pagination
380
+
381
+ ```vue
382
+ <script setup>
383
+ const columns = [
384
+ { accessorKey: 'name', header: 'Name' },
385
+ { accessorKey: 'email', header: 'Email' },
386
+ { accessorKey: 'status', header: 'Status' },
387
+ ]
388
+
389
+ // Server-side pagination state
390
+ const page = ref(1)
391
+ const itemsPerPage = ref(20)
392
+ const total = ref(0)
393
+ const users = ref([])
394
+ const loading = ref(false)
395
+
396
+ // Fetch data from API with pagination params
397
+ async function fetchUsers() {
398
+ loading.value = true
399
+ try {
400
+ const response = await $fetch('/api/users', {
401
+ query: {
402
+ page: page.value,
403
+ limit: itemsPerPage.value,
404
+ }
405
+ })
406
+ users.value = response.data
407
+ total.value = response.total
408
+ } finally {
409
+ loading.value = false
410
+ }
411
+ }
412
+
413
+ // React to pagination changes
414
+ watch([page, itemsPerPage], fetchUsers, { immediate: true })
415
+ </script>
416
+
417
+ <template>
418
+ <VATable
419
+ name="Users"
420
+ :data="users"
421
+ :columns="columns"
422
+ :loading="loading"
423
+ :manual-pagination="true"
424
+ :total="total"
425
+ v-model:page="page"
426
+ v-model:items-per-page="itemsPerPage"
427
+ />
428
+ </template>
429
+ ```
430
+
374
431
  ---
375
432
 
376
433
  ## Date Auto-Detection
@@ -106,7 +106,13 @@
106
106
  :loading="loading"
107
107
  :row-selection-options="{ enableRowSelection: props.selectable }"
108
108
  :sorting-options="{ getSortedRowModel: getSortedRowModel() }"
109
- :pagination-options="{ getPaginationRowModel: getPaginationRowModel() }"
109
+ :pagination-options="{
110
+ getPaginationRowModel: getPaginationRowModel(),
111
+ manualPagination: props.manualPagination,
112
+ ...(props.manualPagination && props.total !== undefined
113
+ ? { pageCount: Math.ceil(props.total / pagination.pageSize) }
114
+ : {})
115
+ }"
110
116
  :ui="{
111
117
  th: 'px-3 py-2',
112
118
  td: 'px-3 py-2',
@@ -148,7 +154,7 @@
148
154
  :items-per-page="pagination.pageSize"
149
155
  :total="totalRows"
150
156
  size="sm"
151
- @update:page="(p) => (pagination.pageIndex = p - 1)"
157
+ @update:page="onPageChange"
152
158
  />
153
159
  </div>
154
160
  </div>
@@ -184,8 +190,13 @@ const props = withDefaults(defineProps<{
184
190
  defaultSort?: string;
185
191
  /** Default sort direction */
186
192
  defaultSortDesc?: boolean;
193
+ /** Enable server-side pagination mode */
194
+ manualPagination?: boolean;
195
+ /** Total row count from server (required for manualPagination) */
196
+ total?: number;
187
197
  }>(), {
188
198
  selectable: false,
199
+ manualPagination: false,
189
200
  });
190
201
 
191
202
  // Sorting state - v-model support
@@ -197,6 +208,41 @@ const filterValues = defineModel<Record<string, unknown>>("filterValues", {
197
208
  default: () => ({}),
198
209
  });
199
210
 
211
+ // Server-side pagination - v-model support (1-based page)
212
+ const page = defineModel<number>("page", { default: 1 });
213
+ const itemsPerPage = defineModel<number>("itemsPerPage", { default: 10 });
214
+
215
+ // Internal pagination state (0-based pageIndex for TanStack)
216
+ const pagination = ref({
217
+ pageIndex: 0,
218
+ pageSize: 10,
219
+ });
220
+
221
+ // Initialize pagination from props and sync with v-model
222
+ onMounted(() => {
223
+ const defaultPageSize = props.initialPageLimit ?? 10;
224
+ pagination.value.pageSize = defaultPageSize;
225
+
226
+ // Sync itemsPerPage if not already set by parent
227
+ if (itemsPerPage.value === 10 && defaultPageSize !== 10) {
228
+ itemsPerPage.value = defaultPageSize;
229
+ }
230
+ });
231
+
232
+ // Sync internal pagination with v-model when in manual mode
233
+ watch(
234
+ [page, itemsPerPage],
235
+ ([newPage, newItemsPerPage]) => {
236
+ if (props.manualPagination) {
237
+ pagination.value = {
238
+ pageIndex: newPage - 1, // Convert 1-based to 0-based
239
+ pageSize: newItemsPerPage,
240
+ };
241
+ }
242
+ },
243
+ { immediate: true }
244
+ );
245
+
200
246
  const refreshing = ref(false);
201
247
  const slots = useSlots()
202
248
 
@@ -289,12 +335,6 @@ onMounted(() => {
289
335
  }
290
336
  });
291
337
 
292
- // Pagination state
293
- const pagination = ref({
294
- pageIndex: 0,
295
- pageSize: props.initialPageLimit ?? 10,
296
- });
297
-
298
338
  // Column visibility state
299
339
  const columnVisibility = ref<Record<string, boolean>>({});
300
340
 
@@ -446,6 +486,9 @@ function handleRowClick(row: any) {
446
486
 
447
487
  // Computed pagination info
448
488
  const totalRows = computed(() => {
489
+ if (props.manualPagination && props.total !== undefined) {
490
+ return props.total;
491
+ }
449
492
  return table.value?.tableApi?.getFilteredRowModel().rows.length ?? 0;
450
493
  });
451
494
 
@@ -461,17 +504,35 @@ const endIndex = computed(() => {
461
504
 
462
505
  // Handle page size change
463
506
  const onPageSizeChange = (size: number) => {
464
- pagination.value = {
465
- pageIndex: 0,
466
- pageSize: size,
467
- };
507
+ if (props.manualPagination) {
508
+ // Emit to parent for server-side handling
509
+ itemsPerPage.value = size;
510
+ page.value = 1; // Reset to first page
511
+ } else {
512
+ pagination.value = {
513
+ pageIndex: 0,
514
+ pageSize: size,
515
+ };
516
+ }
468
517
  };
469
518
 
470
- // Reset pagination when data changes
519
+ // Handle page change from UPagination
520
+ const onPageChange = (newPage: number) => {
521
+ if (props.manualPagination) {
522
+ // Emit to parent for server-side handling
523
+ page.value = newPage;
524
+ } else {
525
+ pagination.value.pageIndex = newPage - 1;
526
+ }
527
+ };
528
+
529
+ // Reset pagination when data changes (client-side only)
471
530
  watch(
472
531
  () => props.data,
473
532
  () => {
474
- pagination.value.pageIndex = 0;
533
+ if (!props.manualPagination) {
534
+ pagination.value.pageIndex = 0;
535
+ }
475
536
  }
476
537
  );
477
538
 
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@veristone/nuxt-v-app",
3
- "version": "0.2.5",
3
+ "version": "0.2.6",
4
4
  "description": "Veristone Nuxt App Layer - Shared components, composables, and layouts",
5
5
  "type": "module",
6
6
  "private": false,