Skip to content

Commit 1bc189b

Browse files
committed
feat(createDataGrid): add grid adapters (client, server, virtual)
1 parent 4216aef commit 1bc189b

5 files changed

Lines changed: 200 additions & 0 deletions

File tree

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
/**
2+
* @module createDataGrid/adapters
3+
*
4+
* @remarks
5+
* Grid adapter types. Each grid adapter extends the corresponding
6+
* DataTable adapter to insert row ordering between sort and pagination.
7+
*/
8+
9+
export type {
10+
DataTableAdapterContext,
11+
DataTableAdapterInterface,
12+
DataTableAdapterResult,
13+
SortDirection,
14+
SortEntry,
15+
} from '../../createDataTable/adapters/adapter'
Lines changed: 86 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,86 @@
1+
/**
2+
* @module createDataGrid/adapters/client
3+
*
4+
* @remarks
5+
* Client-side grid adapter. Extends DataTableAdapter with row ordering
6+
* inserted between sort and pagination stages.
7+
*/
8+
9+
// Composables
10+
import { createPagination } from '#v0/composables/createPagination'
11+
12+
// Adapters
13+
import { DataTableAdapter } from '../../createDataTable/adapters/adapter'
14+
15+
// Utilities
16+
import { computed, toRef, watch } from 'vue'
17+
18+
// Types
19+
import type { ID } from '#v0/types'
20+
import type { DataTableAdapterContext, DataTableAdapterResult } from '../../createDataTable/adapters/adapter'
21+
import type { ShallowRef } from 'vue'
22+
23+
export class ClientGridAdapter<T extends Record<string, unknown>> extends DataTableAdapter<T> {
24+
private rowOrder: ShallowRef<ID[]>
25+
private itemKey: string
26+
27+
constructor (rowOrder: ShallowRef<ID[]>, itemKey: string) {
28+
super()
29+
this.rowOrder = rowOrder
30+
this.itemKey = itemKey
31+
}
32+
33+
setup (context: DataTableAdapterContext<T>): DataTableAdapterResult<T> {
34+
const { search, sortBy, locale, paginationOptions, customSorts } = context
35+
36+
const { allItems, filteredItems } = this.filter(context)
37+
const sortedItems = this.sort(filteredItems, sortBy, locale, customSorts)
38+
39+
// Row ordering: applied post-sort, pre-pagination
40+
const orderedItems = computed(() => {
41+
const order = this.rowOrder.value
42+
if (order.length === 0) return sortedItems.value
43+
44+
const map = new Map<ID, T>()
45+
for (const item of sortedItems.value) {
46+
map.set(item[this.itemKey] as ID, item)
47+
}
48+
49+
const result: T[] = []
50+
for (const id of order) {
51+
const item = map.get(id)
52+
if (item) result.push(item)
53+
}
54+
55+
for (const item of sortedItems.value) {
56+
if (!order.includes(item[this.itemKey] as ID)) {
57+
result.push(item)
58+
}
59+
}
60+
61+
return result
62+
})
63+
64+
const pagination = createPagination({
65+
...paginationOptions,
66+
size: toRef(() => orderedItems.value.length),
67+
})
68+
69+
const items = computed(() => {
70+
return orderedItems.value.slice(pagination.pageStart.value, pagination.pageStop.value)
71+
})
72+
73+
watch([search, sortBy], () => {
74+
pagination.first()
75+
})
76+
77+
return {
78+
allItems,
79+
filteredItems,
80+
sortedItems: orderedItems,
81+
items,
82+
pagination,
83+
total: toRef(() => orderedItems.value.length),
84+
}
85+
}
86+
}
Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
export type { DataTableAdapterContext, DataTableAdapterInterface, DataTableAdapterResult, SortDirection, SortEntry } from './adapter'
2+
export { ClientGridAdapter } from './client'
3+
export { ServerGridAdapter } from './server'
4+
export type { ServerGridAdapterOptions } from './server'
5+
export { VirtualGridAdapter } from './virtual'
Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
/**
2+
* @module createDataGrid/adapters/server
3+
*
4+
* @remarks
5+
* Server-side grid adapter. Delegates pipeline to the server.
6+
* Row ordering emits a callback for the consumer to sync with the server.
7+
*/
8+
9+
// Types
10+
11+
export { ServerAdapter as ServerGridAdapter, type ServerAdapterOptions as ServerGridAdapterOptions } from '../../createDataTable/adapters/server'
Lines changed: 83 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,83 @@
1+
/**
2+
* @module createDataGrid/adapters/virtual
3+
*
4+
* @remarks
5+
* Virtual scrolling grid adapter. Client-side filter/sort with row
6+
* ordering, feeding all sorted items to createVirtual.
7+
*/
8+
9+
// Composables
10+
import { createPagination } from '#v0/composables/createPagination'
11+
12+
// Adapters
13+
import { DataTableAdapter } from '../../createDataTable/adapters/adapter'
14+
15+
// Utilities
16+
import { computed, toRef, watch } from 'vue'
17+
18+
// Types
19+
import type { ID } from '#v0/types'
20+
import type { DataTableAdapterContext, DataTableAdapterResult } from '../../createDataTable/adapters/adapter'
21+
import type { ShallowRef } from 'vue'
22+
23+
export class VirtualGridAdapter<T extends Record<string, unknown>> extends DataTableAdapter<T> {
24+
private rowOrder: ShallowRef<ID[]>
25+
private itemKey: string
26+
27+
constructor (rowOrder: ShallowRef<ID[]>, itemKey: string) {
28+
super()
29+
this.rowOrder = rowOrder
30+
this.itemKey = itemKey
31+
}
32+
33+
setup (context: DataTableAdapterContext<T>): DataTableAdapterResult<T> {
34+
const { search, sortBy, locale, customSorts } = context
35+
36+
const { allItems, filteredItems } = this.filter(context)
37+
const sortedItems = this.sort(filteredItems, sortBy, locale, customSorts)
38+
39+
const orderedItems = computed(() => {
40+
const order = this.rowOrder.value
41+
if (order.length === 0) return sortedItems.value
42+
43+
const map = new Map<ID, T>()
44+
for (const item of sortedItems.value) {
45+
map.set(item[this.itemKey] as ID, item)
46+
}
47+
48+
const result: T[] = []
49+
for (const id of order) {
50+
const item = map.get(id)
51+
if (item) result.push(item)
52+
}
53+
54+
for (const item of sortedItems.value) {
55+
if (!order.includes(item[this.itemKey] as ID)) {
56+
result.push(item)
57+
}
58+
}
59+
60+
return result
61+
})
62+
63+
const size = toRef(() => orderedItems.value.length)
64+
65+
const pagination = createPagination({
66+
size,
67+
itemsPerPage: size,
68+
})
69+
70+
watch([search, sortBy], () => {
71+
pagination.first()
72+
})
73+
74+
return {
75+
allItems,
76+
filteredItems,
77+
sortedItems: orderedItems,
78+
items: orderedItems,
79+
pagination,
80+
total: toRef(() => orderedItems.value.length),
81+
}
82+
}
83+
}

0 commit comments

Comments
 (0)