@vueye-table/headless 3.0.0-alpha.4 → 3.0.0-alpha.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.
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
- return () => h(props.as, {
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
- return () => h(props.as, slots.default?.({ columns: table.columns }) ?? h(DataTableHeaderRow, () => table.columns.map((column) => h(DataTableHeaderCell, {
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: { as: asProp("tbody") },
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 position = table.rows.indexOf(row);
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
- return () => {
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
- }, slots.default?.({
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: { as: asProp("tbody") },
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
- return () => h(props.as, slots.default?.({ rows: table.rows }) ?? table.rows.map((row, rowIndex) => h("tr", {
582
- key: row.key,
583
- role: "row",
584
- "aria-rowindex": rowIndex + 2,
585
- "data-key": String(row.key)
586
- }, [slots.rowHeader?.({
587
- row,
588
- index: rowIndex
589
- }), ...table.columns.map((column, columnIndex) => h(DataGridCell, {
590
- key: column.id,
591
- row,
592
- column,
593
- rowIndex,
594
- columnIndex
595
- }, slots.cell ? { default: (cellProps) => slots.cell?.(cellProps) } : void 0))])));
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