@vueye-table/headless 3.0.0-alpha.3 → 3.0.0-alpha.5
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 +2 -0
- package/dist/index.d.ts +356 -5
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +457 -33
- package/dist/index.js.map +1 -1
- package/package.json +3 -3
package/dist/index.js
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
import { injectDataGrid, injectDataTable, provideDataGrid, provideDataTable, useDataGrid } from "@vueye-table/vue";
|
|
2
|
-
import { defineComponent, h, inject, nextTick, onMounted, onScopeDispose, provide, ref, useId, watch } from "vue";
|
|
1
|
+
import { injectDataGrid, injectDataTable, provideDataGrid, provideDataTable, useDataGrid, useVirtualColumns, useVirtualRows } from "@vueye-table/vue";
|
|
2
|
+
import { Fragment, computed, defineComponent, h, inject, nextTick, onMounted, onScopeDispose, provide, ref, shallowRef, useId, watch } from "vue";
|
|
3
3
|
|
|
4
4
|
//#region src/shared.ts
|
|
5
5
|
/** The element a component renders. Every headless component accepts `as`. */
|
|
@@ -271,6 +271,234 @@ const DataTableStatus = defineComponent({
|
|
|
271
271
|
}
|
|
272
272
|
});
|
|
273
273
|
|
|
274
|
+
//#endregion
|
|
275
|
+
//#region src/virtual.ts
|
|
276
|
+
/** Shared opt-in renderer props. Options are applied when the virtual renderer is created. */
|
|
277
|
+
const virtualProps = {
|
|
278
|
+
virtual: {
|
|
279
|
+
type: [Boolean, Object],
|
|
280
|
+
default: false
|
|
281
|
+
},
|
|
282
|
+
height: {
|
|
283
|
+
type: String,
|
|
284
|
+
default: void 0
|
|
285
|
+
},
|
|
286
|
+
rowHeight: {
|
|
287
|
+
type: Number,
|
|
288
|
+
default: 40
|
|
289
|
+
},
|
|
290
|
+
overscan: {
|
|
291
|
+
type: Number,
|
|
292
|
+
default: 5
|
|
293
|
+
},
|
|
294
|
+
virtualColumns: {
|
|
295
|
+
type: Boolean,
|
|
296
|
+
default: false
|
|
297
|
+
},
|
|
298
|
+
columnWidth: {
|
|
299
|
+
type: Number,
|
|
300
|
+
default: 120
|
|
301
|
+
}
|
|
302
|
+
};
|
|
303
|
+
function virtualOptions(props) {
|
|
304
|
+
return {
|
|
305
|
+
rowHeight: props.rowHeight,
|
|
306
|
+
overscan: props.overscan,
|
|
307
|
+
columnWidth: props.columnWidth,
|
|
308
|
+
...typeof props.virtual === "object" ? props.virtual : {}
|
|
309
|
+
};
|
|
310
|
+
}
|
|
311
|
+
const viewportKey = Symbol("vt-viewport");
|
|
312
|
+
const virtualKey = Symbol("vt-virtual-renderer");
|
|
313
|
+
function injectVirtual() {
|
|
314
|
+
return inject(virtualKey, void 0);
|
|
315
|
+
}
|
|
316
|
+
/** A scroll container for a headless table/grid. It supplies its element without global reads. */
|
|
317
|
+
const DataTableViewport = defineComponent({
|
|
318
|
+
name: "DataTableViewport",
|
|
319
|
+
slots: Object,
|
|
320
|
+
props: {
|
|
321
|
+
as: asProp("div"),
|
|
322
|
+
height: {
|
|
323
|
+
type: String,
|
|
324
|
+
default: "24rem"
|
|
325
|
+
}
|
|
326
|
+
},
|
|
327
|
+
setup(props, { slots, expose }) {
|
|
328
|
+
const element = shallowRef(null);
|
|
329
|
+
provide(viewportKey, element);
|
|
330
|
+
expose({ element });
|
|
331
|
+
return () => h(props.as, {
|
|
332
|
+
ref: element,
|
|
333
|
+
"data-virtual-viewport": "",
|
|
334
|
+
style: {
|
|
335
|
+
height: props.height,
|
|
336
|
+
overflow: "auto",
|
|
337
|
+
overflowAnchor: "none"
|
|
338
|
+
}
|
|
339
|
+
}, slots.default?.());
|
|
340
|
+
}
|
|
341
|
+
});
|
|
342
|
+
function createComponentVirtual(table, options, tableElement, grid, virtualColumns = false, gutter = 0) {
|
|
343
|
+
const scrollElement = inject(viewportKey, shallowRef(null));
|
|
344
|
+
const rows = useVirtualRows(table, {
|
|
345
|
+
scrollElement,
|
|
346
|
+
estimateRowHeight: options.rowHeight,
|
|
347
|
+
overscan: options.overscan,
|
|
348
|
+
initialCount: options.initialCount,
|
|
349
|
+
grid,
|
|
350
|
+
scrollMargin: () => tableElement()?.querySelector("thead")?.getBoundingClientRect().height ?? 0
|
|
351
|
+
});
|
|
352
|
+
const columns = grid && virtualColumns ? useVirtualColumns(grid, {
|
|
353
|
+
scrollElement,
|
|
354
|
+
estimateColumnWidth: (index) => table.columns[index]?.width ?? options.columnWidth ?? 120,
|
|
355
|
+
overscan: options.columnOverscan ?? 1,
|
|
356
|
+
initialCount: options.initialColumnCount ?? 5,
|
|
357
|
+
scrollMargin: gutter
|
|
358
|
+
}) : void 0;
|
|
359
|
+
const pinnedRows = computed(() => {
|
|
360
|
+
const result = [...rows.items];
|
|
361
|
+
const positions = /* @__PURE__ */ new Set([grid?.selection?.focus.row, grid?.editor?.position.row]);
|
|
362
|
+
for (const position of positions) {
|
|
363
|
+
if (position === void 0 || result.some((item) => item.renderItem.kind === "row" && item.renderItem.rowIndex === position)) continue;
|
|
364
|
+
const direct = table.renderItems[position];
|
|
365
|
+
const index = direct?.kind === "row" && direct.rowIndex === position ? position : table.renderItems.findIndex((item) => item.kind === "row" && item.rowIndex === position);
|
|
366
|
+
const item = rows.getItem(index);
|
|
367
|
+
if (item) result.push(item);
|
|
368
|
+
}
|
|
369
|
+
return result.sort((a, b) => a.index - b.index);
|
|
370
|
+
});
|
|
371
|
+
const pinnedColumns = computed(() => {
|
|
372
|
+
if (!columns) return void 0;
|
|
373
|
+
const result = [...columns.items];
|
|
374
|
+
const positions = /* @__PURE__ */ new Set([grid?.selection?.focus.column, grid?.editor?.position.column]);
|
|
375
|
+
for (const position of positions) {
|
|
376
|
+
if (position === void 0 || result.some((item) => item.index === position)) continue;
|
|
377
|
+
const item = columns.getItem(position);
|
|
378
|
+
if (item) result.push(item);
|
|
379
|
+
}
|
|
380
|
+
return result.sort((a, b) => a.index - b.index);
|
|
381
|
+
});
|
|
382
|
+
const binding = {
|
|
383
|
+
rows,
|
|
384
|
+
columns,
|
|
385
|
+
gutter,
|
|
386
|
+
get rowItems() {
|
|
387
|
+
return pinnedRows.value;
|
|
388
|
+
},
|
|
389
|
+
get columnItems() {
|
|
390
|
+
return pinnedColumns.value;
|
|
391
|
+
}
|
|
392
|
+
};
|
|
393
|
+
provide(virtualKey, binding);
|
|
394
|
+
return binding;
|
|
395
|
+
}
|
|
396
|
+
/** Create composables only for an enabled renderer, preserving the ordinary component path. */
|
|
397
|
+
const VirtualContent = defineComponent({
|
|
398
|
+
name: "DataTableVirtualContent",
|
|
399
|
+
props: {
|
|
400
|
+
table: {
|
|
401
|
+
type: Object,
|
|
402
|
+
required: true
|
|
403
|
+
},
|
|
404
|
+
options: {
|
|
405
|
+
type: Object,
|
|
406
|
+
required: true
|
|
407
|
+
},
|
|
408
|
+
tableElement: {
|
|
409
|
+
type: Function,
|
|
410
|
+
required: true
|
|
411
|
+
},
|
|
412
|
+
grid: {
|
|
413
|
+
type: Object,
|
|
414
|
+
default: void 0
|
|
415
|
+
},
|
|
416
|
+
virtualColumns: {
|
|
417
|
+
type: Boolean,
|
|
418
|
+
default: false
|
|
419
|
+
},
|
|
420
|
+
gutter: {
|
|
421
|
+
type: Number,
|
|
422
|
+
default: 0
|
|
423
|
+
},
|
|
424
|
+
render: {
|
|
425
|
+
type: Function,
|
|
426
|
+
required: true
|
|
427
|
+
}
|
|
428
|
+
},
|
|
429
|
+
setup(props) {
|
|
430
|
+
const binding = createComponentVirtual(props.table, props.options, props.tableElement, props.grid, props.virtualColumns, props.gutter);
|
|
431
|
+
return () => props.render(binding);
|
|
432
|
+
}
|
|
433
|
+
});
|
|
434
|
+
function rowSpacer(size, colspan, key) {
|
|
435
|
+
return size > 0 ? h("tr", {
|
|
436
|
+
key,
|
|
437
|
+
"aria-hidden": "true",
|
|
438
|
+
role: "presentation",
|
|
439
|
+
"data-virtual-spacer": "",
|
|
440
|
+
style: { height: `${size}px` }
|
|
441
|
+
}, [h("td", {
|
|
442
|
+
colspan: Math.max(1, colspan),
|
|
443
|
+
style: {
|
|
444
|
+
height: `${size}px`,
|
|
445
|
+
padding: "0",
|
|
446
|
+
border: "0",
|
|
447
|
+
lineHeight: "0"
|
|
448
|
+
}
|
|
449
|
+
})]) : null;
|
|
450
|
+
}
|
|
451
|
+
function columnSpacer(size, tag, key) {
|
|
452
|
+
return size > 0 ? h(tag, {
|
|
453
|
+
key,
|
|
454
|
+
"aria-hidden": "true",
|
|
455
|
+
role: "presentation",
|
|
456
|
+
"data-virtual-spacer": "",
|
|
457
|
+
style: {
|
|
458
|
+
width: `${size}px`,
|
|
459
|
+
minWidth: `${size}px`,
|
|
460
|
+
padding: "0",
|
|
461
|
+
border: "0"
|
|
462
|
+
}
|
|
463
|
+
}) : null;
|
|
464
|
+
}
|
|
465
|
+
function renderColumns(tableColumns, binding, render, tag) {
|
|
466
|
+
if (!binding?.columns || !binding.columnItems) return tableColumns.map(render);
|
|
467
|
+
const result = [];
|
|
468
|
+
let end = 0;
|
|
469
|
+
for (const item of binding.columnItems) {
|
|
470
|
+
result.push(columnSpacer(item.start - end, tag, `gap-${item.index}`), render(item.column, item.index));
|
|
471
|
+
end = item.start + item.size;
|
|
472
|
+
}
|
|
473
|
+
result.push(columnSpacer(binding.columns.totalSize - end, tag, "gap-end"));
|
|
474
|
+
return result;
|
|
475
|
+
}
|
|
476
|
+
function renderRows(binding, colspan, render) {
|
|
477
|
+
const result = [];
|
|
478
|
+
let end = 0;
|
|
479
|
+
for (const item of binding.rowItems) {
|
|
480
|
+
result.push(rowSpacer(item.start - end, colspan, `gap-${item.index}`), render(item));
|
|
481
|
+
end = item.start + item.size;
|
|
482
|
+
}
|
|
483
|
+
result.push(rowSpacer(binding.rows.totalSize - end, colspan, "gap-end"));
|
|
484
|
+
return result;
|
|
485
|
+
}
|
|
486
|
+
function virtualColgroup(tableColumns, binding) {
|
|
487
|
+
if (!binding.columns || !binding.columnItems) return null;
|
|
488
|
+
const cols = binding.gutter ? [h("col", { style: { width: `${binding.gutter}px` } })] : [];
|
|
489
|
+
let end = 0;
|
|
490
|
+
for (const item of binding.columnItems) {
|
|
491
|
+
if (item.start > end) cols.push(h("col", { style: { width: `${item.start - end}px` } }));
|
|
492
|
+
cols.push(h("col", { style: { width: `${item.size}px` } }));
|
|
493
|
+
end = item.start + item.size;
|
|
494
|
+
}
|
|
495
|
+
if (binding.columns.totalSize > end) cols.push(h("col", { style: { width: `${binding.columns.totalSize - end}px` } }));
|
|
496
|
+
return h("colgroup", cols);
|
|
497
|
+
}
|
|
498
|
+
function virtualRow(binding, row) {
|
|
499
|
+
return binding.rowItems.find((item) => item.renderItem.kind === "row" && item.renderItem.row.key === row.key);
|
|
500
|
+
}
|
|
501
|
+
|
|
274
502
|
//#endregion
|
|
275
503
|
//#region src/table.ts
|
|
276
504
|
/**
|
|
@@ -285,15 +513,27 @@ const DataTableRoot = defineComponent({
|
|
|
285
513
|
type: Object,
|
|
286
514
|
required: true
|
|
287
515
|
},
|
|
288
|
-
as: asProp("table")
|
|
516
|
+
as: asProp("table"),
|
|
517
|
+
...virtualProps
|
|
289
518
|
},
|
|
290
519
|
setup(props, { slots }) {
|
|
291
520
|
provideDataTable(props.table);
|
|
292
|
-
|
|
521
|
+
const element = shallowRef();
|
|
522
|
+
const render = (virtual) => h(props.as, {
|
|
293
523
|
"aria-rowcount": props.table.rowCount + 1,
|
|
294
524
|
"aria-colcount": props.table.columns.length,
|
|
295
|
-
"data-empty": flag(props.table.rowCount === 0)
|
|
525
|
+
"data-empty": flag(props.table.rowCount === 0),
|
|
526
|
+
...virtual ? {
|
|
527
|
+
ref: element,
|
|
528
|
+
"data-virtual": ""
|
|
529
|
+
} : {}
|
|
296
530
|
}, slots.default?.({ table: props.table }) ?? [h(DataTableHeader), h(DataTableBody)]);
|
|
531
|
+
return () => props.virtual ? h(VirtualContent, {
|
|
532
|
+
table: props.table,
|
|
533
|
+
options: virtualOptions(props),
|
|
534
|
+
tableElement: () => element.value,
|
|
535
|
+
render
|
|
536
|
+
}) : render();
|
|
297
537
|
}
|
|
298
538
|
});
|
|
299
539
|
const DataTableCaption = defineComponent({
|
|
@@ -311,7 +551,11 @@ const DataTableHeader = defineComponent({
|
|
|
311
551
|
props: { as: asProp("thead") },
|
|
312
552
|
setup(props, { slots }) {
|
|
313
553
|
const table = injectDataTable("<DataTableHeader>");
|
|
314
|
-
|
|
554
|
+
const virtual = injectVirtual();
|
|
555
|
+
return () => h(props.as, slots.default?.({ columns: table.columns }) ?? h(DataTableHeaderRow, () => virtual?.columns ? h(DataTableVirtualColumns, null, { default: ({ column }) => [h(DataTableHeaderCell, {
|
|
556
|
+
key: column.id,
|
|
557
|
+
column
|
|
558
|
+
})] }) : table.columns.map((column) => h(DataTableHeaderCell, {
|
|
315
559
|
key: column.id,
|
|
316
560
|
column
|
|
317
561
|
}))));
|
|
@@ -325,6 +569,23 @@ const DataTableHeaderRow = defineComponent({
|
|
|
325
569
|
return () => h(props.as, { "aria-rowindex": 1 }, slots.default?.());
|
|
326
570
|
}
|
|
327
571
|
});
|
|
572
|
+
/** Shared header/body column slice, with native spacer cells for omitted columns. */
|
|
573
|
+
const DataTableVirtualColumns = defineComponent({
|
|
574
|
+
name: "DataTableVirtualColumns",
|
|
575
|
+
slots: Object,
|
|
576
|
+
props: { as: {
|
|
577
|
+
type: String,
|
|
578
|
+
default: "th"
|
|
579
|
+
} },
|
|
580
|
+
setup(props, { slots }) {
|
|
581
|
+
const table = injectDataTable("<DataTableVirtualColumns>");
|
|
582
|
+
const virtual = injectVirtual();
|
|
583
|
+
return () => h(Fragment, renderColumns(table.columns, virtual, (column, index) => slots.default?.({
|
|
584
|
+
column,
|
|
585
|
+
index
|
|
586
|
+
}), props.as));
|
|
587
|
+
}
|
|
588
|
+
});
|
|
328
589
|
/**
|
|
329
590
|
* A column header with `aria-sort`. Without a slot it shows the header text inside a sort button
|
|
330
591
|
* for sortable columns.
|
|
@@ -338,6 +599,7 @@ const DataTableHeaderCell = defineComponent({
|
|
|
338
599
|
},
|
|
339
600
|
setup(props, { slots }) {
|
|
340
601
|
const table = injectDataTable("<DataTableHeaderCell>");
|
|
602
|
+
const virtual = injectVirtual();
|
|
341
603
|
return () => {
|
|
342
604
|
const { column } = props;
|
|
343
605
|
const sort = table.getSort(column.id);
|
|
@@ -354,7 +616,8 @@ const DataTableHeaderCell = defineComponent({
|
|
|
354
616
|
"data-align": column.align,
|
|
355
617
|
"data-sortable": flag(column.sortable),
|
|
356
618
|
"data-sort": sort?.direction,
|
|
357
|
-
style: columnStyle(column)
|
|
619
|
+
style: columnStyle(column),
|
|
620
|
+
...virtual?.columns ? { "aria-colindex": table.columns.indexOf(column) + 1 } : {}
|
|
358
621
|
}, content);
|
|
359
622
|
};
|
|
360
623
|
}
|
|
@@ -397,10 +660,20 @@ const DataTableSortButton = defineComponent({
|
|
|
397
660
|
const DataTableBody = defineComponent({
|
|
398
661
|
name: "DataTableBody",
|
|
399
662
|
slots: Object,
|
|
400
|
-
props: {
|
|
663
|
+
props: {
|
|
664
|
+
as: asProp("tbody"),
|
|
665
|
+
...virtualProps,
|
|
666
|
+
colspan: {
|
|
667
|
+
type: Number,
|
|
668
|
+
default: void 0
|
|
669
|
+
}
|
|
670
|
+
},
|
|
401
671
|
setup(props, { slots }) {
|
|
402
672
|
const table = injectDataTable("<DataTableBody>");
|
|
673
|
+
const virtual = injectVirtual();
|
|
403
674
|
return () => {
|
|
675
|
+
if (props.virtual && !virtual) return h(VirtualDataTableBody, props, slots);
|
|
676
|
+
if (virtual) return renderTableBody(table, virtual, props.as, props.colspan, slots);
|
|
404
677
|
let content = slots.default?.({ rows: table.rows });
|
|
405
678
|
if (!content) content = table.rows.length === 0 && slots.empty ? h("tr", { "data-empty": "" }, [h("td", { colspan: Math.max(1, table.columns.length) }, slots.empty())]) : table.rows.map((row) => h(DataTableRow, {
|
|
406
679
|
key: row.key,
|
|
@@ -410,25 +683,73 @@ const DataTableBody = defineComponent({
|
|
|
410
683
|
};
|
|
411
684
|
}
|
|
412
685
|
});
|
|
686
|
+
function renderTableBody(table, virtual, as, colspan, slots, element) {
|
|
687
|
+
const width = colspan ?? table.columns.length;
|
|
688
|
+
const attrs = element ? { ref: element } : {};
|
|
689
|
+
const content = slots.default?.({ rows: virtual.rowItems.filter((item) => item.renderItem.kind === "row").map((item) => item.renderItem.row) });
|
|
690
|
+
if (table.rows.length === 0 && slots.empty) return h(as, attrs, h("tr", { "data-empty": "" }, [h("td", { colspan: Math.max(1, width) }, slots.empty())]));
|
|
691
|
+
if (content) return h(as, attrs, [
|
|
692
|
+
rowSpacer(virtual.rows.paddingStart, width, "gap-start"),
|
|
693
|
+
...content,
|
|
694
|
+
rowSpacer(virtual.rows.paddingEnd, width, "gap-end")
|
|
695
|
+
]);
|
|
696
|
+
return h(as, attrs, renderRows(virtual, width, (item) => item.renderItem.kind === "row" ? h(DataTableRow, {
|
|
697
|
+
key: item.key,
|
|
698
|
+
row: item.renderItem.row,
|
|
699
|
+
rowIndex: item.renderItem.rowIndex
|
|
700
|
+
}) : h("tr", {
|
|
701
|
+
key: item.key,
|
|
702
|
+
"data-detail": "",
|
|
703
|
+
ref: (target) => virtual.rows.measureElement(target, item.key)
|
|
704
|
+
}, [h("td", { colspan: Math.max(1, width) }, slots.detail?.(item.renderItem))])));
|
|
705
|
+
}
|
|
706
|
+
const VirtualDataTableBody = defineComponent({
|
|
707
|
+
name: "DataTableVirtualBody",
|
|
708
|
+
props: {
|
|
709
|
+
as: asProp("tbody"),
|
|
710
|
+
...virtualProps,
|
|
711
|
+
colspan: {
|
|
712
|
+
type: Number,
|
|
713
|
+
default: void 0
|
|
714
|
+
}
|
|
715
|
+
},
|
|
716
|
+
slots: Object,
|
|
717
|
+
setup(props, { slots }) {
|
|
718
|
+
const table = injectDataTable("<DataTableBody>");
|
|
719
|
+
const element = shallowRef();
|
|
720
|
+
const virtual = createComponentVirtual(table, virtualOptions(props), () => element.value?.closest("table"));
|
|
721
|
+
return () => renderTableBody(table, virtual, props.as, props.colspan, slots, element);
|
|
722
|
+
}
|
|
723
|
+
});
|
|
413
724
|
/** A body row; `aria-selected` and `data-selected` follow the selection. */
|
|
414
725
|
const DataTableRow = defineComponent({
|
|
415
726
|
name: "DataTableRow",
|
|
416
727
|
slots: Object,
|
|
417
728
|
props: {
|
|
418
729
|
row: rowProp,
|
|
419
|
-
as: asProp("tr")
|
|
730
|
+
as: asProp("tr"),
|
|
731
|
+
rowIndex: {
|
|
732
|
+
type: Number,
|
|
733
|
+
default: void 0
|
|
734
|
+
}
|
|
420
735
|
},
|
|
421
736
|
setup(props, { slots }) {
|
|
422
737
|
const table = injectDataTable("<DataTableRow>");
|
|
738
|
+
const virtual = injectVirtual();
|
|
423
739
|
return () => {
|
|
424
740
|
const { row } = props;
|
|
425
741
|
const selected = table.isSelected(row.key);
|
|
426
|
-
const
|
|
742
|
+
const item = virtual ? virtualRow(virtual, row) : void 0;
|
|
743
|
+
const position = props.rowIndex ?? item?.renderItem.rowIndex ?? table.rows.indexOf(row);
|
|
427
744
|
return h(props.as, {
|
|
428
745
|
"aria-rowindex": position === -1 ? void 0 : table.pageStart + position + 1,
|
|
429
746
|
"aria-selected": table.selectionMode === "none" ? void 0 : String(selected),
|
|
430
747
|
"data-selected": flag(selected),
|
|
431
|
-
"data-key": String(row.key)
|
|
748
|
+
"data-key": String(row.key),
|
|
749
|
+
...virtual && item ? {
|
|
750
|
+
ref: (element) => virtual.rows.measureElement(element, item.key),
|
|
751
|
+
"data-virtual-row": ""
|
|
752
|
+
} : {}
|
|
432
753
|
}, slots.default?.({
|
|
433
754
|
row,
|
|
434
755
|
selected,
|
|
@@ -510,6 +831,12 @@ const DataGridRoot = defineComponent({
|
|
|
510
831
|
label: {
|
|
511
832
|
type: String,
|
|
512
833
|
default: void 0
|
|
834
|
+
},
|
|
835
|
+
...virtualProps,
|
|
836
|
+
/** Width reserved before data columns, for a row-number/header column. */
|
|
837
|
+
gutter: {
|
|
838
|
+
type: Number,
|
|
839
|
+
default: 0
|
|
513
840
|
}
|
|
514
841
|
},
|
|
515
842
|
setup(props, { slots, expose }) {
|
|
@@ -529,8 +856,34 @@ const DataGridRoot = defineComponent({
|
|
|
529
856
|
grid,
|
|
530
857
|
focus
|
|
531
858
|
});
|
|
859
|
+
let virtual;
|
|
532
860
|
const onKeydown = (event) => {
|
|
533
861
|
if (event.target !== element.value) return;
|
|
862
|
+
if (virtual && !grid.editor && (event.ctrlKey || event.metaKey) && (event.key === "Home" || event.key === "End")) {
|
|
863
|
+
grid.focusCell(event.key === "Home" ? {
|
|
864
|
+
row: 0,
|
|
865
|
+
column: 0
|
|
866
|
+
} : {
|
|
867
|
+
row: props.table.rows.length - 1,
|
|
868
|
+
column: props.table.columns.length - 1
|
|
869
|
+
}, { extend: event.shiftKey });
|
|
870
|
+
event.preventDefault();
|
|
871
|
+
return;
|
|
872
|
+
}
|
|
873
|
+
if (virtual && !grid.editor && (event.key === "PageUp" || event.key === "PageDown")) {
|
|
874
|
+
const current = grid.selection?.focus ?? {
|
|
875
|
+
row: 0,
|
|
876
|
+
column: 0
|
|
877
|
+
};
|
|
878
|
+
const item = virtual.rowItems.find((entry) => entry.renderItem.rowIndex === current.row);
|
|
879
|
+
const step = Math.max(1, Math.floor(virtual.rows.viewportSize / (item?.size ?? props.rowHeight)));
|
|
880
|
+
grid.focusCell({
|
|
881
|
+
row: current.row + (event.key === "PageDown" ? step : -step),
|
|
882
|
+
column: current.column
|
|
883
|
+
}, { extend: event.shiftKey });
|
|
884
|
+
event.preventDefault();
|
|
885
|
+
return;
|
|
886
|
+
}
|
|
534
887
|
if (grid.handleKey(event)) event.preventDefault();
|
|
535
888
|
};
|
|
536
889
|
const onCopy = (event, cut = false) => {
|
|
@@ -545,7 +898,8 @@ const DataGridRoot = defineComponent({
|
|
|
545
898
|
event.preventDefault();
|
|
546
899
|
grid.paste(text);
|
|
547
900
|
};
|
|
548
|
-
|
|
901
|
+
const render = (binding) => {
|
|
902
|
+
virtual = binding;
|
|
549
903
|
const focusPosition = grid.selection?.focus;
|
|
550
904
|
return h(props.as, {
|
|
551
905
|
ref: element,
|
|
@@ -554,18 +908,37 @@ const DataGridRoot = defineComponent({
|
|
|
554
908
|
tabindex: 0,
|
|
555
909
|
"aria-label": props.label,
|
|
556
910
|
"aria-multiselectable": "true",
|
|
557
|
-
"aria-rowcount": props.table.rows.length + 1,
|
|
911
|
+
"aria-rowcount": (binding ? props.table.rowCount : props.table.rows.length) + 1,
|
|
558
912
|
"aria-colcount": props.table.columns.length,
|
|
559
913
|
"aria-activedescendant": focusPosition && !grid.editor ? cellId(id, focusPosition.row, focusPosition.column) : void 0,
|
|
560
914
|
onKeydown,
|
|
561
915
|
onCopy: (event) => onCopy(event),
|
|
562
916
|
onCut: (event) => onCopy(event, true),
|
|
563
|
-
onPaste
|
|
564
|
-
|
|
917
|
+
onPaste,
|
|
918
|
+
...binding ? {
|
|
919
|
+
"data-virtual": "",
|
|
920
|
+
style: binding.columns ? {
|
|
921
|
+
tableLayout: "fixed",
|
|
922
|
+
width: `${binding.columns.totalSize + binding.gutter}px`
|
|
923
|
+
} : void 0
|
|
924
|
+
} : {}
|
|
925
|
+
}, binding ? [virtualColgroup(props.table.columns, binding), slots.default?.({
|
|
926
|
+
table: props.table,
|
|
927
|
+
grid
|
|
928
|
+
}) ?? [h(DataTableHeader), h(DataGridBody)]] : slots.default?.({
|
|
565
929
|
table: props.table,
|
|
566
930
|
grid
|
|
567
931
|
}) ?? [h(DataTableHeader), h(DataGridBody)]);
|
|
568
932
|
};
|
|
933
|
+
return () => props.virtual ? h(VirtualContent, {
|
|
934
|
+
table: props.table,
|
|
935
|
+
grid,
|
|
936
|
+
options: virtualOptions(props),
|
|
937
|
+
virtualColumns: props.virtualColumns,
|
|
938
|
+
gutter: props.gutter,
|
|
939
|
+
tableElement: () => element.value,
|
|
940
|
+
render
|
|
941
|
+
}) : render();
|
|
569
942
|
}
|
|
570
943
|
});
|
|
571
944
|
/**
|
|
@@ -575,24 +948,74 @@ const DataGridRoot = defineComponent({
|
|
|
575
948
|
const DataGridBody = defineComponent({
|
|
576
949
|
name: "DataGridBody",
|
|
577
950
|
slots: Object,
|
|
578
|
-
props: {
|
|
951
|
+
props: {
|
|
952
|
+
as: asProp("tbody"),
|
|
953
|
+
...virtualProps,
|
|
954
|
+
colspan: {
|
|
955
|
+
type: Number,
|
|
956
|
+
default: void 0
|
|
957
|
+
}
|
|
958
|
+
},
|
|
579
959
|
setup(props, { slots }) {
|
|
580
960
|
const table = injectDataTable("<DataGridBody>");
|
|
581
|
-
|
|
582
|
-
|
|
583
|
-
|
|
584
|
-
|
|
585
|
-
|
|
586
|
-
|
|
587
|
-
|
|
588
|
-
|
|
589
|
-
|
|
590
|
-
|
|
591
|
-
|
|
592
|
-
|
|
593
|
-
|
|
594
|
-
|
|
595
|
-
|
|
961
|
+
const { grid } = useGrid("<DataGridBody>");
|
|
962
|
+
const virtual = injectVirtual();
|
|
963
|
+
const element = ref();
|
|
964
|
+
const render = (binding) => {
|
|
965
|
+
if (binding && slots.default) return h(props.as, { ref: element }, slots.default({ rows: binding.rowItems.filter((item) => item.renderItem.kind === "row").map((item) => item.renderItem.row) }));
|
|
966
|
+
if (binding) return h(props.as, { ref: element }, renderRows(binding, props.colspan ?? table.columns.length + (slots.rowHeader ? 1 : 0), (item) => {
|
|
967
|
+
if (item.renderItem.kind !== "row") return h("tr", {
|
|
968
|
+
key: item.key,
|
|
969
|
+
"aria-hidden": "true",
|
|
970
|
+
"data-detail": "",
|
|
971
|
+
style: { height: `${item.size}px` }
|
|
972
|
+
}, [h("td", {
|
|
973
|
+
colspan: Math.max(1, table.columns.length),
|
|
974
|
+
style: { padding: "0" }
|
|
975
|
+
})]);
|
|
976
|
+
const { row, rowIndex } = item.renderItem;
|
|
977
|
+
const columns = renderColumns(table.columns, binding, (column, columnIndex) => h(DataGridCell, {
|
|
978
|
+
key: column.id,
|
|
979
|
+
row,
|
|
980
|
+
column,
|
|
981
|
+
rowIndex,
|
|
982
|
+
columnIndex
|
|
983
|
+
}, slots.cell ? { default: (cellProps) => slots.cell?.(cellProps) } : void 0), "td");
|
|
984
|
+
return h("tr", {
|
|
985
|
+
key: item.key,
|
|
986
|
+
role: "row",
|
|
987
|
+
"aria-rowindex": table.pageStart + rowIndex + 1,
|
|
988
|
+
"data-key": String(row.key),
|
|
989
|
+
"data-virtual-row": "",
|
|
990
|
+
ref: (target) => binding.rows.measureElement(target, item.key)
|
|
991
|
+
}, [slots.rowHeader?.({
|
|
992
|
+
row,
|
|
993
|
+
index: rowIndex
|
|
994
|
+
}), ...columns]);
|
|
995
|
+
}));
|
|
996
|
+
return h(props.as, slots.default?.({ rows: table.rows }) ?? table.rows.map((row, rowIndex) => h("tr", {
|
|
997
|
+
key: row.key,
|
|
998
|
+
role: "row",
|
|
999
|
+
"aria-rowindex": rowIndex + 2,
|
|
1000
|
+
"data-key": String(row.key)
|
|
1001
|
+
}, [slots.rowHeader?.({
|
|
1002
|
+
row,
|
|
1003
|
+
index: rowIndex
|
|
1004
|
+
}), ...table.columns.map((column, columnIndex) => h(DataGridCell, {
|
|
1005
|
+
key: column.id,
|
|
1006
|
+
row,
|
|
1007
|
+
column,
|
|
1008
|
+
rowIndex,
|
|
1009
|
+
columnIndex
|
|
1010
|
+
}, slots.cell ? { default: (cellProps) => slots.cell?.(cellProps) } : void 0))])));
|
|
1011
|
+
};
|
|
1012
|
+
return () => props.virtual && !virtual ? h(VirtualContent, {
|
|
1013
|
+
table,
|
|
1014
|
+
grid,
|
|
1015
|
+
options: virtualOptions(props),
|
|
1016
|
+
tableElement: () => element.value?.closest("table"),
|
|
1017
|
+
render
|
|
1018
|
+
}) : render(virtual);
|
|
596
1019
|
}
|
|
597
1020
|
});
|
|
598
1021
|
/** The text box shown in a cell while it is edited. */
|
|
@@ -666,13 +1089,14 @@ const DataGridCell = defineComponent({
|
|
|
666
1089
|
setup(props, { slots }) {
|
|
667
1090
|
const table = injectDataTable("<DataGridCell>");
|
|
668
1091
|
const { grid, context } = useGrid("<DataGridCell>");
|
|
1092
|
+
const virtual = injectVirtual();
|
|
669
1093
|
const element = ref();
|
|
670
1094
|
const position = () => ({
|
|
671
1095
|
row: props.rowIndex ?? table.rows.indexOf(props.row),
|
|
672
1096
|
column: props.columnIndex ?? table.columns.indexOf(props.column)
|
|
673
1097
|
});
|
|
674
1098
|
watch(() => grid.isFocused(position()), (focused) => {
|
|
675
|
-
if (focused) element.value?.scrollIntoView?.({
|
|
1099
|
+
if (focused && !virtual) element.value?.scrollIntoView?.({
|
|
676
1100
|
block: "nearest",
|
|
677
1101
|
inline: "nearest"
|
|
678
1102
|
});
|
|
@@ -730,5 +1154,5 @@ const DataGridCell = defineComponent({
|
|
|
730
1154
|
});
|
|
731
1155
|
|
|
732
1156
|
//#endregion
|
|
733
|
-
export { DataGridBody, DataGridCell, DataGridRoot, DataTableBody, DataTableCaption, DataTableCell, DataTableColumnVisibility, DataTableEmpty, DataTableHeader, DataTableHeaderCell, DataTableHeaderRow, DataTablePageSize, DataTablePagination, DataTableRoot, DataTableRow, DataTableSearch, DataTableSelectAll, DataTableSelectRow, DataTableSortButton, DataTableStatus, cellId, columnStyle };
|
|
1157
|
+
export { DataGridBody, DataGridCell, DataGridRoot, DataTableBody, DataTableCaption, DataTableCell, DataTableColumnVisibility, DataTableEmpty, DataTableHeader, DataTableHeaderCell, DataTableHeaderRow, DataTablePageSize, DataTablePagination, DataTableRoot, DataTableRow, DataTableSearch, DataTableSelectAll, DataTableSelectRow, DataTableSortButton, DataTableStatus, DataTableViewport, DataTableVirtualColumns, cellId, columnStyle, injectVirtual as injectVirtualRenderer, virtualProps };
|
|
734
1158
|
//# sourceMappingURL=index.js.map
|