@vueye-table/headless 3.0.0-beta.6 → 3.0.0-beta.8
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 +13 -3
- package/dist/index.d.ts +238 -6
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +1021 -277
- package/dist/index.js.map +1 -1
- package/package.json +3 -3
package/dist/index.js
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { injectDataGrid, injectDataTable, provideDataGrid, provideDataTable, useDataGrid, useTableLocale, useVirtualColumns, useVirtualRows } from "@vueye-table/vue";
|
|
2
|
-
import { Fragment, computed, defineComponent, h, inject, mergeProps, nextTick, onMounted, onScopeDispose, provide, ref, shallowRef, useId, watch } from "vue";
|
|
3
|
-
import { formatValue, getRowItemKey, gridCommand } from "@vueye-table/core";
|
|
2
|
+
import { Fragment, cloneVNode, computed, defineComponent, getCurrentInstance, h, inject, isVNode, mergeProps, nextTick, onMounted, onScopeDispose, onUpdated, provide, ref, shallowRef, useId, watch } from "vue";
|
|
3
|
+
import { clampColumnWidth, formatValue, getRowItemKey, gridCommand } from "@vueye-table/core";
|
|
4
4
|
|
|
5
5
|
//#region src/shared.ts
|
|
6
6
|
/** Leading native utility cells, independent of data-column coordinates. */
|
|
@@ -370,173 +370,447 @@ const DataTableLoadMore = defineComponent({
|
|
|
370
370
|
});
|
|
371
371
|
|
|
372
372
|
//#endregion
|
|
373
|
-
//#region src/
|
|
374
|
-
|
|
375
|
-
|
|
376
|
-
|
|
377
|
-
|
|
373
|
+
//#region src/row-layout.ts
|
|
374
|
+
const groupingProps = { aggregatePosition: {
|
|
375
|
+
type: String,
|
|
376
|
+
default: "group"
|
|
377
|
+
} };
|
|
378
|
+
const layoutKey$1 = Symbol("vt-row-layout");
|
|
379
|
+
const pinnedKey = Symbol("vt-pinned-row");
|
|
380
|
+
function injectRowLayout() {
|
|
381
|
+
return inject(layoutKey$1, void 0);
|
|
378
382
|
}
|
|
379
|
-
|
|
380
|
-
|
|
381
|
-
|
|
382
|
-
|
|
383
|
-
|
|
384
|
-
|
|
385
|
-
|
|
386
|
-
|
|
387
|
-
|
|
388
|
-
|
|
389
|
-
|
|
390
|
-
|
|
391
|
-
|
|
392
|
-
|
|
393
|
-
|
|
394
|
-
|
|
395
|
-
|
|
383
|
+
function injectPinnedRow() {
|
|
384
|
+
return inject(pinnedKey, void 0);
|
|
385
|
+
}
|
|
386
|
+
/** Presentation indices include group headers and optional footers; grid positions stay on leaves. */
|
|
387
|
+
function provideRowLayout(table, options, element) {
|
|
388
|
+
const measured = shallowRef(/* @__PURE__ */ new Map());
|
|
389
|
+
const headerHeight = shallowRef(0);
|
|
390
|
+
const targets = /* @__PURE__ */ new Map();
|
|
391
|
+
let head = null;
|
|
392
|
+
let observer;
|
|
393
|
+
const plan = computed(() => {
|
|
394
|
+
if (!table.grouped && table.topRows.length === 0 && table.bottomRows.length === 0) return {
|
|
395
|
+
items: table.renderItems,
|
|
396
|
+
footers: /* @__PURE__ */ new Map(),
|
|
397
|
+
indices: /* @__PURE__ */ new Map(),
|
|
398
|
+
levels: /* @__PURE__ */ new Map(),
|
|
399
|
+
structured: false
|
|
400
|
+
};
|
|
401
|
+
const items = [];
|
|
402
|
+
const footers = /* @__PURE__ */ new Map();
|
|
403
|
+
const stack = [];
|
|
404
|
+
const levels = /* @__PURE__ */ new Map();
|
|
405
|
+
let depth = 0;
|
|
406
|
+
const appendFooter = () => {
|
|
407
|
+
const group = stack.pop();
|
|
408
|
+
const key = JSON.stringify(["aggregate-footer", group.key]);
|
|
409
|
+
footers.set(key, group);
|
|
410
|
+
items.push(Object.freeze({
|
|
411
|
+
...group,
|
|
412
|
+
key
|
|
413
|
+
}));
|
|
414
|
+
};
|
|
415
|
+
const footerMode = options.aggregatePosition === "footer" && table.columns.some((column) => column.aggregate);
|
|
416
|
+
for (const item of table.renderItems) {
|
|
417
|
+
if (item.kind === "group") depth = item.depth;
|
|
418
|
+
else levels.set(item.row.key, depth + 2);
|
|
419
|
+
if (footerMode && item.kind === "group") {
|
|
420
|
+
while (stack.length && stack.at(-1).depth >= item.depth) appendFooter();
|
|
421
|
+
if (item.isExpanded) stack.push(item);
|
|
422
|
+
}
|
|
423
|
+
items.push(item);
|
|
424
|
+
}
|
|
425
|
+
while (stack.length) appendFooter();
|
|
426
|
+
const structured = table.grouped || table.topRows.length > 0 || table.bottomRows.length > 0;
|
|
427
|
+
const indices = /* @__PURE__ */ new Map();
|
|
428
|
+
table.topRows.forEach((row, index) => indices.set(getRowItemKey(row.key), index + 2));
|
|
429
|
+
items.forEach((item, index) => indices.set(item.key, table.topRows.length + index + 2));
|
|
430
|
+
table.bottomRows.forEach((row, index) => indices.set(getRowItemKey(row.key), table.topRows.length + items.length + index + 2));
|
|
431
|
+
return {
|
|
432
|
+
items: Object.freeze(items),
|
|
433
|
+
footers,
|
|
434
|
+
indices,
|
|
435
|
+
structured,
|
|
436
|
+
levels
|
|
437
|
+
};
|
|
438
|
+
});
|
|
439
|
+
const size = (key) => measured.value.get(key) ?? (options.rowHeight > 0 ? options.rowHeight : 40);
|
|
440
|
+
const region = (side) => side === "top" ? table.topRows : table.bottomRows;
|
|
441
|
+
const height = (side) => region(side).reduce((sum, row) => sum + size(row.key), 0);
|
|
442
|
+
const measure = (target, key) => {
|
|
443
|
+
const value = target.getBoundingClientRect().height;
|
|
444
|
+
if (key === void 0) {
|
|
445
|
+
if (Number.isFinite(value)) headerHeight.value = Math.max(0, value);
|
|
446
|
+
} else if (value > 0 && Number.isFinite(value) && measured.value.get(key) !== value) measured.value = new Map(measured.value).set(key, value);
|
|
447
|
+
};
|
|
448
|
+
const refresh = () => {
|
|
449
|
+
const next = element()?.querySelector("thead") ?? null;
|
|
450
|
+
if (head !== next) {
|
|
451
|
+
if (head) observer?.unobserve(head);
|
|
452
|
+
head = next;
|
|
453
|
+
if (head) observer?.observe(head);
|
|
454
|
+
}
|
|
455
|
+
if (head) measure(head);
|
|
456
|
+
for (const [key, target] of targets) measure(target, key);
|
|
457
|
+
};
|
|
458
|
+
onMounted(() => {
|
|
459
|
+
const Observer = element()?.ownerDocument.defaultView?.ResizeObserver;
|
|
460
|
+
if (Observer) observer = new Observer((entries) => {
|
|
461
|
+
for (const { target } of entries) if (target === head) measure(target);
|
|
462
|
+
else for (const [key, value] of targets) if (value === target) measure(target, key);
|
|
463
|
+
});
|
|
464
|
+
refresh();
|
|
465
|
+
for (const [key, target] of targets) {
|
|
466
|
+
observer?.observe(target);
|
|
467
|
+
measure(target, key);
|
|
468
|
+
}
|
|
469
|
+
});
|
|
470
|
+
onUpdated(refresh);
|
|
471
|
+
onScopeDispose(() => {
|
|
472
|
+
observer?.disconnect();
|
|
473
|
+
targets.clear();
|
|
474
|
+
});
|
|
475
|
+
const layout = {
|
|
476
|
+
get aggregatePosition() {
|
|
477
|
+
return options.aggregatePosition;
|
|
478
|
+
},
|
|
479
|
+
get items() {
|
|
480
|
+
return plan.value.items;
|
|
481
|
+
},
|
|
482
|
+
get headerHeight() {
|
|
483
|
+
return headerHeight.value;
|
|
484
|
+
},
|
|
485
|
+
get topHeight() {
|
|
486
|
+
return height("top");
|
|
487
|
+
},
|
|
488
|
+
get bottomHeight() {
|
|
489
|
+
return height("bottom");
|
|
490
|
+
},
|
|
491
|
+
get count() {
|
|
492
|
+
return plan.value.structured ? table.topRows.length + plan.value.items.length + table.bottomRows.length + 1 : void 0;
|
|
493
|
+
},
|
|
494
|
+
index(key, kind = "row") {
|
|
495
|
+
return plan.value.structured ? plan.value.indices.get(kind === "group" ? key : getRowItemKey(key, kind)) : void 0;
|
|
496
|
+
},
|
|
497
|
+
level(key) {
|
|
498
|
+
return table.grouped ? plan.value.levels.get(key) ?? 1 : void 0;
|
|
499
|
+
},
|
|
500
|
+
footer: (key) => plan.value.footers.get(key),
|
|
501
|
+
register(key, target, owner) {
|
|
502
|
+
const previous = targets.get(key);
|
|
503
|
+
if (!target && owner && previous !== owner) return;
|
|
504
|
+
if (previous === target) return;
|
|
505
|
+
if (previous) observer?.unobserve(previous);
|
|
506
|
+
if (target) {
|
|
507
|
+
targets.set(key, target);
|
|
508
|
+
observer?.observe(target);
|
|
509
|
+
measure(target, key);
|
|
510
|
+
} else {
|
|
511
|
+
targets.delete(key);
|
|
512
|
+
if (measured.value.has(key)) {
|
|
513
|
+
const next = new Map(measured.value);
|
|
514
|
+
next.delete(key);
|
|
515
|
+
measured.value = next;
|
|
516
|
+
}
|
|
517
|
+
}
|
|
518
|
+
},
|
|
519
|
+
pinStyle(side, key, columnPinned) {
|
|
520
|
+
const rows = region(side);
|
|
521
|
+
const index = rows.findIndex((row) => row.key === key);
|
|
522
|
+
const offset = (side === "top" ? rows.slice(0, index) : rows.slice(index + 1)).reduce((sum, row) => sum + size(row.key), 0);
|
|
523
|
+
return {
|
|
524
|
+
position: "sticky",
|
|
525
|
+
[side === "top" ? "insetBlockStart" : "insetBlockEnd"]: `${offset + (side === "top" ? headerHeight.value : 0)}px`,
|
|
526
|
+
zIndex: columnPinned ? "5" : "3"
|
|
527
|
+
};
|
|
528
|
+
},
|
|
529
|
+
headerStyle(columnPinned) {
|
|
530
|
+
return table.topRows.length || table.bottomRows.length ? {
|
|
531
|
+
position: "sticky",
|
|
532
|
+
insetBlockStart: "0px",
|
|
533
|
+
zIndex: columnPinned ? "6" : "4"
|
|
534
|
+
} : void 0;
|
|
535
|
+
}
|
|
536
|
+
};
|
|
537
|
+
provide(layoutKey$1, layout);
|
|
538
|
+
return layout;
|
|
539
|
+
}
|
|
540
|
+
/** Apply region context to an ordinary data row without changing its cell/grid coordinates. */
|
|
541
|
+
const DataTablePinnedRow = defineComponent({
|
|
542
|
+
name: "DataTablePinnedRow",
|
|
543
|
+
props: {
|
|
544
|
+
row: rowProp,
|
|
545
|
+
side: {
|
|
546
|
+
type: String,
|
|
547
|
+
required: true
|
|
548
|
+
}
|
|
396
549
|
},
|
|
397
|
-
|
|
550
|
+
slots: Object,
|
|
551
|
+
setup(props, { slots }) {
|
|
552
|
+
const layout = injectRowLayout();
|
|
553
|
+
const instance = getCurrentInstance();
|
|
554
|
+
let current;
|
|
555
|
+
const register = () => {
|
|
556
|
+
const target = instance?.subTree.el;
|
|
557
|
+
if (target && "getBoundingClientRect" in target) {
|
|
558
|
+
current = target;
|
|
559
|
+
layout?.register(props.row.key, target);
|
|
560
|
+
}
|
|
561
|
+
};
|
|
562
|
+
onMounted(register);
|
|
563
|
+
onUpdated(register);
|
|
564
|
+
onScopeDispose(() => layout?.register(props.row.key, null, current));
|
|
565
|
+
provide(pinnedKey, {
|
|
566
|
+
get side() {
|
|
567
|
+
return props.side;
|
|
568
|
+
},
|
|
569
|
+
attrs: (columnPinned = false) => ({
|
|
570
|
+
"data-row-pinned": props.side,
|
|
571
|
+
style: layout?.pinStyle(props.side, props.row.key, columnPinned)
|
|
572
|
+
})
|
|
573
|
+
});
|
|
574
|
+
return () => {
|
|
575
|
+
const child = slots.default?.()[0];
|
|
576
|
+
return child ? cloneVNode(child, { "data-row-pinned": props.side }, true) : h("tr");
|
|
577
|
+
};
|
|
578
|
+
}
|
|
579
|
+
});
|
|
580
|
+
|
|
581
|
+
//#endregion
|
|
582
|
+
//#region src/column-layout.ts
|
|
583
|
+
const resizingProps = {
|
|
584
|
+
resizableColumns: {
|
|
398
585
|
type: Boolean,
|
|
399
|
-
default:
|
|
586
|
+
default: false
|
|
400
587
|
},
|
|
401
|
-
|
|
402
|
-
|
|
403
|
-
|
|
588
|
+
/** Pixel widths of leading utility columns; unspecified widths default to 48. */
|
|
589
|
+
leadingColumnWidths: {
|
|
590
|
+
type: Array,
|
|
591
|
+
default: void 0
|
|
404
592
|
}
|
|
405
593
|
};
|
|
406
|
-
|
|
407
|
-
const
|
|
408
|
-
|
|
409
|
-
|
|
594
|
+
const layoutKey = Symbol("vt-column-layout");
|
|
595
|
+
const headerKey = Symbol("vt-header-column");
|
|
596
|
+
function provideHeaderColumn(column) {
|
|
597
|
+
provide(headerKey, column);
|
|
598
|
+
}
|
|
599
|
+
function injectColumnLayout() {
|
|
600
|
+
return inject(layoutKey, void 0);
|
|
601
|
+
}
|
|
602
|
+
function effectiveColumnWidth(column, fallback = 120) {
|
|
603
|
+
return Math.max(1, clampColumnWidth(column, column.width ?? fallback));
|
|
604
|
+
}
|
|
605
|
+
/** CSS-only preview keeps one gesture to one engine operation. */
|
|
606
|
+
function provideColumnLayout(table, options, element) {
|
|
607
|
+
const columns = computed(() => table.columns);
|
|
608
|
+
const previewVariables = /* @__PURE__ */ new Set();
|
|
609
|
+
const variable = (column) => `--vt-column-${columns.value.findIndex((item) => item.id === column.id)}-width`;
|
|
610
|
+
const sum = (values) => values.length ? `calc(${values.join(" + ")})` : "0px";
|
|
611
|
+
const layout = {
|
|
612
|
+
enabled: () => options.resizableColumns && columns.value.some((column) => column.resizable) || columns.value.some((column) => column.pinned),
|
|
613
|
+
resizable: () => options.resizableColumns,
|
|
614
|
+
effectiveWidth: (column) => effectiveColumnWidth(column, options.columnWidth ?? 120),
|
|
615
|
+
width: (column, fallback = layout.effectiveWidth(column)) => `var(${variable(column)}, ${fallback}px)`,
|
|
616
|
+
leadingWidths: () => Array.from({ length: options.leadingColumns }, (_, index) => {
|
|
617
|
+
const width = options.leadingColumnWidths?.[index] ?? (options.gutter ? options.gutter / Math.max(1, options.leadingColumns) : 48);
|
|
618
|
+
return Number.isFinite(width) && width > 0 ? width : 48;
|
|
619
|
+
}),
|
|
620
|
+
attrs(column, header = false) {
|
|
621
|
+
if (!layout.enabled()) return {};
|
|
622
|
+
const style = {};
|
|
623
|
+
if (column.width !== void 0) style["width"] = `${column.width}px`;
|
|
624
|
+
if (column.minWidth !== void 0) style["minWidth"] = `${column.minWidth}px`;
|
|
625
|
+
if (layout.enabled()) style["width"] = layout.width(column);
|
|
626
|
+
if (column.pinned) {
|
|
627
|
+
const pins = columns.value.filter((item) => item.pinned === column.pinned);
|
|
628
|
+
const index = pins.findIndex((item) => item.id === column.id);
|
|
629
|
+
const previous = column.pinned === "start" ? pins.slice(0, index) : pins.slice(index + 1);
|
|
630
|
+
style["position"] = "sticky";
|
|
631
|
+
style[column.pinned === "start" ? "insetInlineStart" : "insetInlineEnd"] = sum([...column.pinned === "start" ? layout.leadingWidths().map((width) => `${width}px`) : [], ...previous.map((item) => layout.width(item))]);
|
|
632
|
+
style["zIndex"] = header ? "4" : "2";
|
|
633
|
+
}
|
|
634
|
+
return {
|
|
635
|
+
"data-pinned": column.pinned,
|
|
636
|
+
"data-pinned-edge": flag(column.isPinnedEdge),
|
|
637
|
+
"data-resizable": header ? flag(options.resizableColumns && column.resizable) : void 0,
|
|
638
|
+
style
|
|
639
|
+
};
|
|
640
|
+
},
|
|
641
|
+
leading(index, header) {
|
|
642
|
+
const pinned = columns.value.some((column) => column.pinned);
|
|
643
|
+
return {
|
|
644
|
+
"data-leading-column": index,
|
|
645
|
+
"data-pinned": pinned ? "start" : void 0,
|
|
646
|
+
"data-pinned-edge": flag(pinned && !columns.value.some((column) => column.pinned === "start") && index === options.leadingColumns - 1),
|
|
647
|
+
style: pinned ? {
|
|
648
|
+
position: "sticky",
|
|
649
|
+
insetInlineStart: `${layout.leadingWidths().slice(0, index).reduce((a, b) => a + b, 0)}px`,
|
|
650
|
+
zIndex: header ? "4" : "2"
|
|
651
|
+
} : void 0
|
|
652
|
+
};
|
|
653
|
+
},
|
|
654
|
+
style(total) {
|
|
655
|
+
if (!layout.enabled() && total === void 0) return void 0;
|
|
656
|
+
return {
|
|
657
|
+
tableLayout: "fixed",
|
|
658
|
+
width: total === void 0 ? sum([...layout.leadingWidths().map((value) => `${value}px`), ...columns.value.map((column) => layout.width(column))]) : `calc(${total}px + var(--vt-resize-delta, 0px))`
|
|
659
|
+
};
|
|
660
|
+
},
|
|
661
|
+
preview(column, width) {
|
|
662
|
+
element()?.style.setProperty(variable(column), `${width}px`);
|
|
663
|
+
previewVariables.add(variable(column));
|
|
664
|
+
element()?.style.setProperty("--vt-resize-delta", `${width - layout.effectiveWidth(column)}px`);
|
|
665
|
+
},
|
|
666
|
+
clear() {
|
|
667
|
+
for (const name of previewVariables) element()?.style.removeProperty(name);
|
|
668
|
+
previewVariables.clear();
|
|
669
|
+
element()?.style.removeProperty("--vt-resize-delta");
|
|
670
|
+
},
|
|
671
|
+
colgroup() {
|
|
672
|
+
return layout.enabled() ? h("colgroup", [...layout.leadingWidths().map((width) => h("col", { style: { width: `${width}px` } })), ...columns.value.map((column) => h("col", {
|
|
673
|
+
key: column.id,
|
|
674
|
+
style: { width: layout.width(column) }
|
|
675
|
+
}))]) : null;
|
|
676
|
+
}
|
|
677
|
+
};
|
|
678
|
+
provide(layoutKey, layout);
|
|
679
|
+
return layout;
|
|
680
|
+
}
|
|
681
|
+
/** Leading selection, disclosure or row-number cells share start-region offsets. */
|
|
682
|
+
const DataTableLeadingCell = defineComponent({
|
|
683
|
+
name: "DataTableLeadingCell",
|
|
684
|
+
props: {
|
|
685
|
+
as: asProp("td"),
|
|
686
|
+
index: {
|
|
687
|
+
type: Number,
|
|
688
|
+
default: 0
|
|
689
|
+
}
|
|
690
|
+
},
|
|
691
|
+
slots: Object,
|
|
692
|
+
setup(props, { slots, attrs }) {
|
|
693
|
+
const layout = injectColumnLayout();
|
|
694
|
+
const rows = injectRowLayout();
|
|
695
|
+
const pin = injectPinnedRow();
|
|
696
|
+
return () => {
|
|
697
|
+
const header = props.as === "th" && attrs["scope"] !== "row";
|
|
698
|
+
const leading = layout?.leading(props.index, header) ?? {};
|
|
699
|
+
return h(props.as, mergeProps(leading, { style: header ? rows?.headerStyle(!!leading["data-pinned"]) : void 0 }, pin?.attrs(!!leading["data-pinned"]) ?? {}), slots.default?.());
|
|
700
|
+
};
|
|
701
|
+
}
|
|
702
|
+
});
|
|
703
|
+
/** A keyboard-operable separator; pointer movement previews and release commits once. */
|
|
704
|
+
const DataTableColumnResizer = defineComponent({
|
|
705
|
+
name: "DataTableColumnResizer",
|
|
706
|
+
props: { column: {
|
|
707
|
+
type: Object,
|
|
708
|
+
default: void 0
|
|
709
|
+
} },
|
|
410
710
|
setup(props) {
|
|
711
|
+
const table = injectDataTable("<DataTableColumnResizer>");
|
|
712
|
+
const header = inject(headerKey, void 0);
|
|
713
|
+
const layout = injectColumnLayout();
|
|
411
714
|
const locale = useTableLocale();
|
|
412
|
-
const
|
|
413
|
-
|
|
414
|
-
const
|
|
415
|
-
const
|
|
416
|
-
|
|
417
|
-
|
|
418
|
-
|
|
419
|
-
|
|
420
|
-
|
|
421
|
-
|
|
422
|
-
|
|
423
|
-
|
|
424
|
-
|
|
425
|
-
if (field.value && "setSelectionRange" in field.value && ["text", "number"].includes(props.spec.kind)) field.value.setSelectionRange(field.value.value.length, field.value.value.length);
|
|
426
|
-
});
|
|
427
|
-
const finish = (direction) => {
|
|
428
|
-
if (props.finish) props.finish(direction);
|
|
429
|
-
else props.editor.commit();
|
|
715
|
+
const preview = shallowRef();
|
|
716
|
+
let drag;
|
|
717
|
+
const column = () => props.column ?? header?.();
|
|
718
|
+
const currentWidth = (value) => layout?.effectiveWidth(value) ?? effectiveColumnWidth(value);
|
|
719
|
+
const stop = (commit = false) => {
|
|
720
|
+
const current = drag;
|
|
721
|
+
if (!current) return;
|
|
722
|
+
drag = void 0;
|
|
723
|
+
const width = preview.value;
|
|
724
|
+
if (commit && width !== void 0) table.resizeColumn(current.column.id, width);
|
|
725
|
+
layout?.clear(current.column);
|
|
726
|
+
preview.value = void 0;
|
|
727
|
+
if (current.target.hasPointerCapture?.(current.pointer)) current.target.releasePointerCapture(current.pointer);
|
|
430
728
|
};
|
|
431
|
-
const
|
|
432
|
-
if (event.
|
|
433
|
-
|
|
434
|
-
|
|
435
|
-
event.stopPropagation();
|
|
436
|
-
if (!props.editor.pending) props.editor.cancel();
|
|
437
|
-
} else if (event.key === "Enter" || event.key === "Tab") {
|
|
438
|
-
if (event.key === "Tab" && !props.tabCommit) return;
|
|
439
|
-
event.preventDefault();
|
|
440
|
-
event.stopPropagation();
|
|
441
|
-
if (!props.editor.pending) finish(event.key === "Tab" ? event.shiftKey ? "left" : "right" : event.shiftKey ? "up" : "down");
|
|
442
|
-
}
|
|
443
|
-
};
|
|
444
|
-
const paste = (event) => {
|
|
445
|
-
const text = event.clipboardData?.getData("text/plain");
|
|
446
|
-
if (text === void 0 || props.editor.pending) return;
|
|
447
|
-
event.preventDefault();
|
|
448
|
-
const target = event.target;
|
|
449
|
-
const start = target.selectionStart ?? 0;
|
|
450
|
-
const end = target.selectionEnd ?? target.value.length;
|
|
451
|
-
props.editor.input(target.value.slice(0, start) + text + target.value.slice(end));
|
|
729
|
+
const move = (event) => {
|
|
730
|
+
if (!drag || drag.pointer !== event.pointerId) return;
|
|
731
|
+
preview.value = Math.max(1, clampColumnWidth(drag.column, drag.width + (event.clientX - drag.x) * drag.sign));
|
|
732
|
+
layout?.preview(drag.column, preview.value);
|
|
452
733
|
};
|
|
734
|
+
watch(() => table.columns, () => stop(), { flush: "sync" });
|
|
735
|
+
onScopeDispose(() => stop());
|
|
453
736
|
return () => {
|
|
454
|
-
const
|
|
455
|
-
|
|
456
|
-
|
|
457
|
-
|
|
458
|
-
|
|
459
|
-
"
|
|
460
|
-
|
|
461
|
-
|
|
462
|
-
|
|
463
|
-
|
|
464
|
-
|
|
465
|
-
|
|
466
|
-
|
|
467
|
-
|
|
468
|
-
|
|
737
|
+
const current = column();
|
|
738
|
+
if (!current?.resizable) return null;
|
|
739
|
+
return h("span", {
|
|
740
|
+
role: "separator",
|
|
741
|
+
tabindex: 0,
|
|
742
|
+
"aria-orientation": "vertical",
|
|
743
|
+
"aria-label": locale().messages.resizeColumn(current.header),
|
|
744
|
+
"aria-description": locale().messages.resizeColumnHelp,
|
|
745
|
+
"aria-valuenow": preview.value ?? currentWidth(current),
|
|
746
|
+
"aria-valuemin": Math.max(1, current.minWidth ?? 1),
|
|
747
|
+
"aria-valuemax": current.maxWidth === void 0 ? void 0 : Math.max(1, current.minWidth ?? 1, current.maxWidth),
|
|
748
|
+
"data-column-resizer": "",
|
|
749
|
+
"data-resizing": flag(preview.value !== void 0),
|
|
750
|
+
style: {
|
|
751
|
+
touchAction: "none",
|
|
752
|
+
cursor: "col-resize",
|
|
753
|
+
userSelect: "none"
|
|
754
|
+
},
|
|
755
|
+
onClick: (event) => event.stopPropagation(),
|
|
756
|
+
onDblclick: (event) => {
|
|
757
|
+
event.stopPropagation();
|
|
758
|
+
stop();
|
|
759
|
+
table.resetColumnSize(current.id);
|
|
760
|
+
},
|
|
761
|
+
onPointerdown: (event) => {
|
|
762
|
+
if (event.button !== 0 || drag || !layout) return;
|
|
763
|
+
const target = event.currentTarget;
|
|
764
|
+
target.focus({ preventScroll: true });
|
|
765
|
+
target.setPointerCapture?.(event.pointerId);
|
|
766
|
+
event.preventDefault();
|
|
767
|
+
event.stopPropagation();
|
|
768
|
+
drag = {
|
|
769
|
+
target,
|
|
770
|
+
pointer: event.pointerId,
|
|
771
|
+
x: event.clientX,
|
|
772
|
+
width: currentWidth(current),
|
|
773
|
+
column: current,
|
|
774
|
+
sign: directionOf(target) === "rtl" ? -1 : 1
|
|
775
|
+
};
|
|
776
|
+
preview.value = drag.width;
|
|
777
|
+
},
|
|
778
|
+
onPointermove: move,
|
|
779
|
+
onPointerup: (event) => {
|
|
780
|
+
if (drag?.pointer === event.pointerId) {
|
|
781
|
+
move(event);
|
|
782
|
+
stop(true);
|
|
469
783
|
}
|
|
470
|
-
}, [
|
|
471
|
-
h("input", {
|
|
472
|
-
ref: field,
|
|
473
|
-
type: "search",
|
|
474
|
-
value: query.value,
|
|
475
|
-
"aria-label": messages.searchOptions(editor.column.header),
|
|
476
|
-
disabled: editor.pending,
|
|
477
|
-
onInput: (event) => {
|
|
478
|
-
query.value = event.target.value;
|
|
479
|
-
},
|
|
480
|
-
onKeydown: (event) => {
|
|
481
|
-
if (event.key === "Enter" && shown[0]) {
|
|
482
|
-
event.preventDefault();
|
|
483
|
-
editor.commit(shown[0].value);
|
|
484
|
-
} else keydown(event);
|
|
485
|
-
}
|
|
486
|
-
}),
|
|
487
|
-
h("select", {
|
|
488
|
-
...attrs,
|
|
489
|
-
value: options.findIndex((value) => Object.is(value, editor.value)),
|
|
490
|
-
size: Math.max(2, Math.min(5, shown.length)),
|
|
491
|
-
onChange: (event) => {
|
|
492
|
-
const index = Number(event.target.value);
|
|
493
|
-
if (index >= 0) editor.commit(options[index]);
|
|
494
|
-
}
|
|
495
|
-
}, shown.map(({ value, index }) => h("option", {
|
|
496
|
-
key: index,
|
|
497
|
-
value: index
|
|
498
|
-
}, value === null || value === void 0 ? messages.emptyOption : String(value)))),
|
|
499
|
-
h("span", {
|
|
500
|
-
role: "status",
|
|
501
|
-
"data-editor-hint": ""
|
|
502
|
-
}, matches.value.length === 0 ? messages.noMatchingOptions : matches.value.length > 50 ? messages.firstMatchesOnly(count(50)) : messages.optionCount(count(matches.value.length)))
|
|
503
|
-
]);
|
|
504
|
-
}
|
|
505
|
-
return h("input", {
|
|
506
|
-
...attrs,
|
|
507
|
-
ref: field,
|
|
508
|
-
type: spec.kind === "date" ? "date" : spec.kind === "checkbox" ? "checkbox" : "text",
|
|
509
|
-
inputmode: spec.kind === "number" ? "decimal" : void 0,
|
|
510
|
-
value: editor.draft,
|
|
511
|
-
checked: spec.kind === "checkbox" ? editor.value === true : void 0,
|
|
512
|
-
onInput: spec.kind === "checkbox" ? void 0 : (event) => editor.input(event.target.value),
|
|
513
|
-
onChange: spec.kind === "checkbox" ? (event) => editor.commit(event.target.checked) : void 0,
|
|
514
|
-
onBlur: () => {
|
|
515
|
-
if (props.blurCommit && !editor.pending) finish();
|
|
516
784
|
},
|
|
517
|
-
|
|
785
|
+
onPointercancel: (event) => {
|
|
786
|
+
if (drag?.pointer === event.pointerId) stop();
|
|
787
|
+
},
|
|
788
|
+
onLostpointercapture: (event) => {
|
|
789
|
+
if (drag?.pointer === event.pointerId) stop();
|
|
790
|
+
},
|
|
791
|
+
onKeydown: (event) => {
|
|
792
|
+
if (event.key === "Escape" && drag) {
|
|
793
|
+
event.preventDefault();
|
|
794
|
+
event.stopPropagation();
|
|
795
|
+
stop();
|
|
796
|
+
return;
|
|
797
|
+
}
|
|
798
|
+
if (drag) return;
|
|
799
|
+
let width;
|
|
800
|
+
const sign = directionOf(event.currentTarget) === "rtl" ? -1 : 1;
|
|
801
|
+
if (event.key === "ArrowLeft" || event.key === "ArrowRight") width = currentWidth(current) + (event.key === "ArrowRight" ? 1 : -1) * sign * (event.shiftKey ? 50 : 10);
|
|
802
|
+
else if (event.key === "Home") width = Math.max(1, current.minWidth ?? 1);
|
|
803
|
+
else if (event.key === "End") width = current.maxWidth;
|
|
804
|
+
else if (event.key === "Enter") table.resetColumnSize(current.id);
|
|
805
|
+
else return;
|
|
806
|
+
event.preventDefault();
|
|
807
|
+
event.stopPropagation();
|
|
808
|
+
if (width !== void 0) table.resizeColumn(current.id, Math.max(1, width));
|
|
809
|
+
}
|
|
518
810
|
});
|
|
519
811
|
};
|
|
520
812
|
}
|
|
521
813
|
});
|
|
522
|
-
/** The cell owns the id so it remains stable while its editor mounts and unmounts. */
|
|
523
|
-
function issueAttrs(id, issues, pending) {
|
|
524
|
-
return {
|
|
525
|
-
"aria-invalid": issues.length ? "true" : void 0,
|
|
526
|
-
"aria-describedby": issues.length ? id : void 0,
|
|
527
|
-
"aria-busy": pending ? "true" : void 0
|
|
528
|
-
};
|
|
529
|
-
}
|
|
530
|
-
function editorIssues(id, issues, pending = false) {
|
|
531
|
-
return issues.length || pending ? h("span", {
|
|
532
|
-
id,
|
|
533
|
-
"data-edit-issues": "",
|
|
534
|
-
role: "status"
|
|
535
|
-
}, pending ? "Checking changes…" : issues.map((problem) => problem.message).join(" ")) : null;
|
|
536
|
-
}
|
|
537
|
-
function useEditorId() {
|
|
538
|
-
return `vt-edit-${useId()}`;
|
|
539
|
-
}
|
|
540
814
|
|
|
541
815
|
//#endregion
|
|
542
816
|
//#region src/virtual.ts
|
|
@@ -608,21 +882,27 @@ const DataTableViewport = defineComponent({
|
|
|
608
882
|
});
|
|
609
883
|
function createComponentVirtual(table, options, tableElement, grid, virtualColumns = false, gutter = 0) {
|
|
610
884
|
const scrollElement = inject(viewportKey, shallowRef(null));
|
|
885
|
+
const layout = injectRowLayout();
|
|
611
886
|
const rows = useVirtualRows(table, {
|
|
612
887
|
scrollElement,
|
|
613
888
|
estimateRowHeight: options.rowHeight,
|
|
614
889
|
overscan: options.overscan,
|
|
615
890
|
initialCount: options.initialCount,
|
|
616
891
|
grid,
|
|
617
|
-
|
|
892
|
+
renderItems: () => layout?.items ?? table.renderItems,
|
|
893
|
+
pinnedRowHeights: () => ({
|
|
894
|
+
top: layout?.topHeight ?? 0,
|
|
895
|
+
bottom: layout?.bottomHeight ?? 0
|
|
896
|
+
}),
|
|
897
|
+
scrollMargin: () => layout?.headerHeight ?? tableElement()?.querySelector("thead")?.getBoundingClientRect().height ?? 0
|
|
618
898
|
});
|
|
619
899
|
onMounted(() => {
|
|
620
900
|
watch(() => [
|
|
621
901
|
rows.endIndex,
|
|
622
|
-
table.renderItems.length,
|
|
902
|
+
layout?.items.length ?? table.renderItems.length,
|
|
623
903
|
table.canLoadMore
|
|
624
904
|
], () => {
|
|
625
|
-
if (table.loadingMode === "cursor" && table.canLoadMore && rows.endIndex >= table.renderItems.length - 1 - table.endThreshold) table.loadNext();
|
|
905
|
+
if (table.loadingMode === "cursor" && table.canLoadMore && rows.endIndex >= (layout?.items.length ?? table.renderItems.length) - 1 - table.endThreshold) table.loadNext();
|
|
626
906
|
}, { immediate: true });
|
|
627
907
|
});
|
|
628
908
|
const columns = grid && virtualColumns ? useVirtualColumns(grid, {
|
|
@@ -632,22 +912,27 @@ function createComponentVirtual(table, options, tableElement, grid, virtualColum
|
|
|
632
912
|
initialCount: options.initialColumnCount ?? 5,
|
|
633
913
|
scrollMargin: gutter
|
|
634
914
|
}) : void 0;
|
|
635
|
-
const
|
|
915
|
+
const retainedRows = computed(() => {
|
|
636
916
|
const result = [...rows.items];
|
|
637
917
|
const positions = /* @__PURE__ */ new Set([grid?.selection?.focus.row, grid?.editor?.position.row]);
|
|
638
918
|
for (const position of positions) {
|
|
639
919
|
if (position === void 0 || result.some((item) => item.renderItem.kind === "row" && item.renderItem.rowIndex === position)) continue;
|
|
640
|
-
const
|
|
641
|
-
const
|
|
920
|
+
const items = layout?.items ?? table.renderItems;
|
|
921
|
+
const direct = items[position];
|
|
922
|
+
const index = direct?.kind === "row" && direct.rowIndex === position ? position : items.findIndex((item) => item.kind === "row" && item.rowIndex === position);
|
|
642
923
|
const item = rows.getItem(index);
|
|
643
924
|
if (item) result.push(item);
|
|
644
925
|
}
|
|
645
926
|
return result.sort((a, b) => a.index - b.index);
|
|
646
927
|
});
|
|
647
|
-
const
|
|
928
|
+
const retainedColumns = computed(() => {
|
|
648
929
|
if (!columns) return void 0;
|
|
649
930
|
const result = [...columns.items];
|
|
650
|
-
const positions = /* @__PURE__ */ new Set([
|
|
931
|
+
const positions = /* @__PURE__ */ new Set([
|
|
932
|
+
grid?.selection?.focus.column,
|
|
933
|
+
grid?.editor?.position.column,
|
|
934
|
+
...table.grouped ? [0] : []
|
|
935
|
+
]);
|
|
651
936
|
for (const position of positions) {
|
|
652
937
|
if (position === void 0 || result.some((item) => item.index === position)) continue;
|
|
653
938
|
const item = columns.getItem(position);
|
|
@@ -660,10 +945,10 @@ function createComponentVirtual(table, options, tableElement, grid, virtualColum
|
|
|
660
945
|
columns,
|
|
661
946
|
gutter,
|
|
662
947
|
get rowItems() {
|
|
663
|
-
return
|
|
948
|
+
return retainedRows.value;
|
|
664
949
|
},
|
|
665
950
|
get columnItems() {
|
|
666
|
-
return
|
|
951
|
+
return retainedColumns.value;
|
|
667
952
|
}
|
|
668
953
|
};
|
|
669
954
|
provide(virtualKey, binding);
|
|
@@ -724,55 +1009,357 @@ function rowSpacer(size, colspan, key) {
|
|
|
724
1009
|
}
|
|
725
1010
|
})]) : null;
|
|
726
1011
|
}
|
|
727
|
-
function columnSpacer(size, tag, key) {
|
|
728
|
-
return size > 0 ? h(tag, {
|
|
729
|
-
key,
|
|
730
|
-
"aria-hidden": "true",
|
|
731
|
-
role: "presentation",
|
|
732
|
-
"data-virtual-spacer": "",
|
|
733
|
-
style: {
|
|
734
|
-
width: `${size}px`,
|
|
735
|
-
minWidth: `${size}px`,
|
|
736
|
-
padding: "0",
|
|
737
|
-
border: "0"
|
|
738
|
-
}
|
|
739
|
-
}) : null;
|
|
1012
|
+
function columnSpacer(size, tag, key) {
|
|
1013
|
+
return size > 0 ? h(tag, {
|
|
1014
|
+
key,
|
|
1015
|
+
"aria-hidden": "true",
|
|
1016
|
+
role: "presentation",
|
|
1017
|
+
"data-virtual-spacer": "",
|
|
1018
|
+
style: {
|
|
1019
|
+
width: `${size}px`,
|
|
1020
|
+
minWidth: `${size}px`,
|
|
1021
|
+
padding: "0",
|
|
1022
|
+
border: "0"
|
|
1023
|
+
}
|
|
1024
|
+
}) : null;
|
|
1025
|
+
}
|
|
1026
|
+
function renderColumns(tableColumns, binding, render, tag) {
|
|
1027
|
+
if (!binding?.columns || !binding.columnItems) return tableColumns.map(render);
|
|
1028
|
+
const result = [];
|
|
1029
|
+
let end = 0;
|
|
1030
|
+
for (const item of binding.columnItems) {
|
|
1031
|
+
result.push(columnSpacer(item.start - end, tag, `gap-${item.index}`), render(item.column, item.index));
|
|
1032
|
+
end = item.start + item.size;
|
|
1033
|
+
}
|
|
1034
|
+
result.push(columnSpacer(binding.columns.totalSize - end, tag, "gap-end"));
|
|
1035
|
+
return result;
|
|
1036
|
+
}
|
|
1037
|
+
/** Native colspans count rendered cells and spacers, rather than logical omitted columns. */
|
|
1038
|
+
function physicalColumnCount(binding, count, leading = 0) {
|
|
1039
|
+
if (!binding?.columns || !binding.columnItems) return Math.max(1, count + leading);
|
|
1040
|
+
let end = 0;
|
|
1041
|
+
let size = leading;
|
|
1042
|
+
for (const item of binding.columnItems) {
|
|
1043
|
+
if (item.start > end) size++;
|
|
1044
|
+
size++;
|
|
1045
|
+
end = item.start + item.size;
|
|
1046
|
+
}
|
|
1047
|
+
if (binding.columns.totalSize > end) size++;
|
|
1048
|
+
return Math.max(1, size);
|
|
1049
|
+
}
|
|
1050
|
+
function renderRows(binding, colspan, render) {
|
|
1051
|
+
const result = [];
|
|
1052
|
+
let end = 0;
|
|
1053
|
+
for (const item of binding.rowItems) {
|
|
1054
|
+
result.push(rowSpacer(item.start - end, colspan, `gap-${item.index}`), render(item));
|
|
1055
|
+
end = item.start + item.size;
|
|
1056
|
+
}
|
|
1057
|
+
result.push(rowSpacer(binding.rows.totalSize - end, colspan, "gap-end"));
|
|
1058
|
+
return result;
|
|
1059
|
+
}
|
|
1060
|
+
function virtualColgroup(tableColumns, binding, width, leadingWidths) {
|
|
1061
|
+
if (!binding.columns || !binding.columnItems) return null;
|
|
1062
|
+
const cols = leadingWidths?.length ? leadingWidths.map((size) => h("col", { style: { width: `${size}px` } })) : binding.gutter ? [h("col", { style: { width: `${binding.gutter}px` } })] : [];
|
|
1063
|
+
let end = 0;
|
|
1064
|
+
for (const item of binding.columnItems) {
|
|
1065
|
+
if (item.start > end) cols.push(h("col", { style: { width: `${item.start - end}px` } }));
|
|
1066
|
+
cols.push(h("col", { style: { width: width?.(item.column, item.size) ?? `${item.size}px` } }));
|
|
1067
|
+
end = item.start + item.size;
|
|
1068
|
+
}
|
|
1069
|
+
if (binding.columns.totalSize > end) cols.push(h("col", { style: { width: `${binding.columns.totalSize - end}px` } }));
|
|
1070
|
+
return h("colgroup", cols);
|
|
1071
|
+
}
|
|
1072
|
+
function virtualRow(binding, row) {
|
|
1073
|
+
return binding.rowItems.find((item) => item.renderItem.kind === "row" && item.renderItem.row.key === row.key);
|
|
1074
|
+
}
|
|
1075
|
+
|
|
1076
|
+
//#endregion
|
|
1077
|
+
//#region src/grouped-rows.ts
|
|
1078
|
+
const groupProp = {
|
|
1079
|
+
type: Object,
|
|
1080
|
+
required: true
|
|
1081
|
+
};
|
|
1082
|
+
const DataTableAggregateCell = defineComponent({
|
|
1083
|
+
name: "DataTableAggregateCell",
|
|
1084
|
+
props: {
|
|
1085
|
+
group: groupProp,
|
|
1086
|
+
column: columnProp,
|
|
1087
|
+
as: asProp("td")
|
|
1088
|
+
},
|
|
1089
|
+
slots: Object,
|
|
1090
|
+
setup(props, { slots }) {
|
|
1091
|
+
const layout = injectColumnLayout();
|
|
1092
|
+
const table = injectDataTable("<DataTableAggregateCell>");
|
|
1093
|
+
const offset = injectColumnOffset();
|
|
1094
|
+
return () => h(props.as, {
|
|
1095
|
+
"data-aggregate": props.column.id,
|
|
1096
|
+
"aria-readonly": props.as === "td" ? "true" : void 0,
|
|
1097
|
+
"data-align": props.column.align,
|
|
1098
|
+
"aria-colindex": props.as === "td" ? table.columns.indexOf(props.column) + offset() + 1 : void 0,
|
|
1099
|
+
...props.as === "td" ? layout?.attrs(props.column) : {}
|
|
1100
|
+
}, props.column.aggregate ? slots.default?.({
|
|
1101
|
+
group: props.group,
|
|
1102
|
+
column: props.column,
|
|
1103
|
+
value: props.group.getAggregate(props.column.id),
|
|
1104
|
+
display: props.group.getAggregateDisplay(props.column.id)
|
|
1105
|
+
}) ?? props.group.getAggregateDisplay(props.column.id) : void 0);
|
|
1106
|
+
}
|
|
1107
|
+
});
|
|
1108
|
+
/** A read-only structural row; aggregate cells use the same native column layout as data cells. */
|
|
1109
|
+
const DataTableGroupRow = defineComponent({
|
|
1110
|
+
name: "DataTableGroupRow",
|
|
1111
|
+
props: {
|
|
1112
|
+
group: groupProp,
|
|
1113
|
+
footer: {
|
|
1114
|
+
type: Boolean,
|
|
1115
|
+
default: false
|
|
1116
|
+
},
|
|
1117
|
+
itemKey: {
|
|
1118
|
+
type: String,
|
|
1119
|
+
default: void 0
|
|
1120
|
+
},
|
|
1121
|
+
aggregates: {
|
|
1122
|
+
type: Boolean,
|
|
1123
|
+
default: true
|
|
1124
|
+
}
|
|
1125
|
+
},
|
|
1126
|
+
slots: Object,
|
|
1127
|
+
setup(props, { slots }) {
|
|
1128
|
+
const table = injectDataTable("<DataTableGroupRow>");
|
|
1129
|
+
const locale = useTableLocale();
|
|
1130
|
+
const offset = injectColumnOffset();
|
|
1131
|
+
const virtual = injectVirtual();
|
|
1132
|
+
const layout = injectRowLayout();
|
|
1133
|
+
return () => {
|
|
1134
|
+
const { group } = props;
|
|
1135
|
+
const label = locale().messages.groupLabel(table.getColumn(group.columnId)?.header ?? group.columnId, String(group.value), locale().count(group.leafCount));
|
|
1136
|
+
const toggle = () => table.toggleGroup(group.key);
|
|
1137
|
+
const content = props.footer ? locale().messages.groupTotals(label) : [table.selectionMode !== "none" ? h("input", {
|
|
1138
|
+
type: "checkbox",
|
|
1139
|
+
checked: group.selection === "all",
|
|
1140
|
+
indeterminate: group.selection === "some",
|
|
1141
|
+
"aria-label": locale().messages.selectGroup(label),
|
|
1142
|
+
onChange: (event) => table.toggleGroupSelection(group.key, event.target.checked)
|
|
1143
|
+
}) : null, h("button", {
|
|
1144
|
+
type: "button",
|
|
1145
|
+
"aria-expanded": String(group.isExpanded),
|
|
1146
|
+
"aria-label": (group.isExpanded ? locale().messages.collapseGroup : locale().messages.expandGroup)(label),
|
|
1147
|
+
onClick: toggle,
|
|
1148
|
+
onKeydown: (event) => event.stopPropagation()
|
|
1149
|
+
}, slots.group?.({
|
|
1150
|
+
group,
|
|
1151
|
+
label,
|
|
1152
|
+
toggle
|
|
1153
|
+
}) ?? label)];
|
|
1154
|
+
const aggregate = (column, as = "td") => h(DataTableAggregateCell, {
|
|
1155
|
+
key: column.id,
|
|
1156
|
+
group,
|
|
1157
|
+
column,
|
|
1158
|
+
as
|
|
1159
|
+
}, { default: slots[`aggregate.${column.id}`] });
|
|
1160
|
+
const hasAggregates = props.aggregates && table.columns.some((column) => column.aggregate);
|
|
1161
|
+
const labelCell = h("td", {
|
|
1162
|
+
"data-group-label": "",
|
|
1163
|
+
"aria-readonly": "true",
|
|
1164
|
+
colspan: hasAggregates ? offset() + 1 : physicalColumnCount(virtual, table.columns.length, offset()),
|
|
1165
|
+
style: { "--vt-group-depth": group.depth }
|
|
1166
|
+
}, [h("div", { class: "vt-group-label-content" }, content), hasAggregates && table.columns[0]?.aggregate ? aggregate(table.columns[0], "span") : null]);
|
|
1167
|
+
const cells = hasAggregates ? [labelCell, ...renderColumns(table.columns, virtual, (column, index) => index === 0 ? null : aggregate(column), "td")] : [labelCell];
|
|
1168
|
+
const key = props.itemKey ?? group.key;
|
|
1169
|
+
return h("tr", {
|
|
1170
|
+
role: "row",
|
|
1171
|
+
"data-group": group.key,
|
|
1172
|
+
"data-group-depth": group.depth,
|
|
1173
|
+
"data-aggregate-footer": props.footer ? "" : void 0,
|
|
1174
|
+
"aria-level": group.depth + 1,
|
|
1175
|
+
"aria-expanded": props.footer ? void 0 : String(group.isExpanded),
|
|
1176
|
+
"aria-rowindex": layout?.index(key, "group"),
|
|
1177
|
+
...virtual ? {
|
|
1178
|
+
"data-virtual-row": "",
|
|
1179
|
+
ref: (target) => virtual.rows.measureElement(target, key)
|
|
1180
|
+
} : {}
|
|
1181
|
+
}, cells);
|
|
1182
|
+
};
|
|
1183
|
+
}
|
|
1184
|
+
});
|
|
1185
|
+
function groupRow(item, slots, aggregatePosition, footer) {
|
|
1186
|
+
return h(DataTableGroupRow, {
|
|
1187
|
+
key: item.key,
|
|
1188
|
+
itemKey: item.key,
|
|
1189
|
+
group: footer ?? item,
|
|
1190
|
+
footer: !!footer,
|
|
1191
|
+
aggregates: !!footer || aggregatePosition === "group",
|
|
1192
|
+
class: "vt-group-row"
|
|
1193
|
+
}, slots);
|
|
1194
|
+
}
|
|
1195
|
+
|
|
1196
|
+
//#endregion
|
|
1197
|
+
//#region src/editor.ts
|
|
1198
|
+
function editorText(value, kind) {
|
|
1199
|
+
if (value === null || value === void 0) return "";
|
|
1200
|
+
if (kind === "date" && value instanceof Date) return Number.isFinite(value.getTime()) ? value.toISOString().slice(0, 10) : "";
|
|
1201
|
+
return formatValue(value);
|
|
740
1202
|
}
|
|
741
|
-
|
|
742
|
-
|
|
743
|
-
|
|
744
|
-
|
|
745
|
-
|
|
746
|
-
|
|
747
|
-
|
|
1203
|
+
const cellEditorProps = {
|
|
1204
|
+
editor: {
|
|
1205
|
+
type: Object,
|
|
1206
|
+
required: true
|
|
1207
|
+
},
|
|
1208
|
+
spec: {
|
|
1209
|
+
type: Object,
|
|
1210
|
+
default: () => ({ kind: "text" })
|
|
1211
|
+
},
|
|
1212
|
+
/** Keyboard movement is owned by the surrounding cell. */
|
|
1213
|
+
finish: {
|
|
1214
|
+
type: Function,
|
|
1215
|
+
default: void 0
|
|
1216
|
+
},
|
|
1217
|
+
autofocus: {
|
|
1218
|
+
type: Boolean,
|
|
1219
|
+
default: true
|
|
1220
|
+
},
|
|
1221
|
+
blurCommit: {
|
|
1222
|
+
type: Boolean,
|
|
1223
|
+
default: true
|
|
1224
|
+
},
|
|
1225
|
+
tabCommit: {
|
|
1226
|
+
type: Boolean,
|
|
1227
|
+
default: true
|
|
748
1228
|
}
|
|
749
|
-
|
|
750
|
-
|
|
751
|
-
|
|
752
|
-
|
|
753
|
-
|
|
754
|
-
|
|
755
|
-
|
|
756
|
-
|
|
757
|
-
|
|
1229
|
+
};
|
|
1230
|
+
/** Plain native fields. Select results are searched and capped at 50 mounted options. */
|
|
1231
|
+
const DataCellEditor = defineComponent({
|
|
1232
|
+
name: "DataCellEditor",
|
|
1233
|
+
props: cellEditorProps,
|
|
1234
|
+
setup(props) {
|
|
1235
|
+
const locale = useTableLocale();
|
|
1236
|
+
const field = ref();
|
|
1237
|
+
const query = ref("");
|
|
1238
|
+
const options = props.spec.options ?? [];
|
|
1239
|
+
const matches = computed(() => {
|
|
1240
|
+
const search = query.value.trim().toLocaleLowerCase();
|
|
1241
|
+
return options.map((value, index) => ({
|
|
1242
|
+
value,
|
|
1243
|
+
index
|
|
1244
|
+
})).filter(({ value }) => String(value ?? "").toLocaleLowerCase().includes(search));
|
|
1245
|
+
});
|
|
1246
|
+
onMounted(() => {
|
|
1247
|
+
if (!props.autofocus) return;
|
|
1248
|
+
field.value?.focus();
|
|
1249
|
+
if (field.value && "setSelectionRange" in field.value && ["text", "number"].includes(props.spec.kind)) field.value.setSelectionRange(field.value.value.length, field.value.value.length);
|
|
1250
|
+
});
|
|
1251
|
+
const finish = (direction) => {
|
|
1252
|
+
if (props.finish) props.finish(direction);
|
|
1253
|
+
else props.editor.commit();
|
|
1254
|
+
};
|
|
1255
|
+
const keydown = (event) => {
|
|
1256
|
+
if (event.isComposing) return;
|
|
1257
|
+
if (event.key === "Escape") {
|
|
1258
|
+
event.preventDefault();
|
|
1259
|
+
event.stopPropagation();
|
|
1260
|
+
if (!props.editor.pending) props.editor.cancel();
|
|
1261
|
+
} else if (event.key === "Enter" || event.key === "Tab") {
|
|
1262
|
+
if (event.key === "Tab" && !props.tabCommit) return;
|
|
1263
|
+
event.preventDefault();
|
|
1264
|
+
event.stopPropagation();
|
|
1265
|
+
if (!props.editor.pending) finish(event.key === "Tab" ? event.shiftKey ? "left" : "right" : event.shiftKey ? "up" : "down");
|
|
1266
|
+
}
|
|
1267
|
+
};
|
|
1268
|
+
const paste = (event) => {
|
|
1269
|
+
const text = event.clipboardData?.getData("text/plain");
|
|
1270
|
+
if (text === void 0 || props.editor.pending) return;
|
|
1271
|
+
event.preventDefault();
|
|
1272
|
+
const target = event.target;
|
|
1273
|
+
const start = target.selectionStart ?? 0;
|
|
1274
|
+
const end = target.selectionEnd ?? target.value.length;
|
|
1275
|
+
props.editor.input(target.value.slice(0, start) + text + target.value.slice(end));
|
|
1276
|
+
};
|
|
1277
|
+
return () => {
|
|
1278
|
+
const { editor, spec } = props;
|
|
1279
|
+
const { messages, count } = locale();
|
|
1280
|
+
const attrs = {
|
|
1281
|
+
...editor.attrs,
|
|
1282
|
+
"aria-label": messages.editCell(editor.column.header),
|
|
1283
|
+
"data-editor": "",
|
|
1284
|
+
disabled: editor.pending,
|
|
1285
|
+
onKeydown: keydown
|
|
1286
|
+
};
|
|
1287
|
+
if (spec.kind === "select") {
|
|
1288
|
+
const shown = matches.value.slice(0, 50);
|
|
1289
|
+
return h("div", {
|
|
1290
|
+
"data-select-editor": "",
|
|
1291
|
+
onKeydown: (event) => {
|
|
1292
|
+
if (event.key === "Escape") keydown(event);
|
|
1293
|
+
}
|
|
1294
|
+
}, [
|
|
1295
|
+
h("input", {
|
|
1296
|
+
ref: field,
|
|
1297
|
+
type: "search",
|
|
1298
|
+
value: query.value,
|
|
1299
|
+
"aria-label": messages.searchOptions(editor.column.header),
|
|
1300
|
+
disabled: editor.pending,
|
|
1301
|
+
onInput: (event) => {
|
|
1302
|
+
query.value = event.target.value;
|
|
1303
|
+
},
|
|
1304
|
+
onKeydown: (event) => {
|
|
1305
|
+
if (event.key === "Enter" && shown[0]) {
|
|
1306
|
+
event.preventDefault();
|
|
1307
|
+
editor.commit(shown[0].value);
|
|
1308
|
+
} else keydown(event);
|
|
1309
|
+
}
|
|
1310
|
+
}),
|
|
1311
|
+
h("select", {
|
|
1312
|
+
...attrs,
|
|
1313
|
+
value: options.findIndex((value) => Object.is(value, editor.value)),
|
|
1314
|
+
size: Math.max(2, Math.min(5, shown.length)),
|
|
1315
|
+
onChange: (event) => {
|
|
1316
|
+
const index = Number(event.target.value);
|
|
1317
|
+
if (index >= 0) editor.commit(options[index]);
|
|
1318
|
+
}
|
|
1319
|
+
}, shown.map(({ value, index }) => h("option", {
|
|
1320
|
+
key: index,
|
|
1321
|
+
value: index
|
|
1322
|
+
}, value === null || value === void 0 ? messages.emptyOption : String(value)))),
|
|
1323
|
+
h("span", {
|
|
1324
|
+
role: "status",
|
|
1325
|
+
"data-editor-hint": ""
|
|
1326
|
+
}, matches.value.length === 0 ? messages.noMatchingOptions : matches.value.length > 50 ? messages.firstMatchesOnly(count(50)) : messages.optionCount(count(matches.value.length)))
|
|
1327
|
+
]);
|
|
1328
|
+
}
|
|
1329
|
+
return h("input", {
|
|
1330
|
+
...attrs,
|
|
1331
|
+
ref: field,
|
|
1332
|
+
type: spec.kind === "date" ? "date" : spec.kind === "checkbox" ? "checkbox" : "text",
|
|
1333
|
+
inputmode: spec.kind === "number" ? "decimal" : void 0,
|
|
1334
|
+
value: editor.draft,
|
|
1335
|
+
checked: spec.kind === "checkbox" ? editor.value === true : void 0,
|
|
1336
|
+
onInput: spec.kind === "checkbox" ? void 0 : (event) => editor.input(event.target.value),
|
|
1337
|
+
onChange: spec.kind === "checkbox" ? (event) => editor.commit(event.target.checked) : void 0,
|
|
1338
|
+
onBlur: () => {
|
|
1339
|
+
if (props.blurCommit && !editor.pending) finish();
|
|
1340
|
+
},
|
|
1341
|
+
onPaste: spec.kind === "checkbox" ? void 0 : paste
|
|
1342
|
+
});
|
|
1343
|
+
};
|
|
758
1344
|
}
|
|
759
|
-
|
|
760
|
-
|
|
1345
|
+
});
|
|
1346
|
+
/** The cell owns the id so it remains stable while its editor mounts and unmounts. */
|
|
1347
|
+
function issueAttrs(id, issues, pending) {
|
|
1348
|
+
return {
|
|
1349
|
+
"aria-invalid": issues.length ? "true" : void 0,
|
|
1350
|
+
"aria-describedby": issues.length ? id : void 0,
|
|
1351
|
+
"aria-busy": pending ? "true" : void 0
|
|
1352
|
+
};
|
|
761
1353
|
}
|
|
762
|
-
function
|
|
763
|
-
|
|
764
|
-
|
|
765
|
-
|
|
766
|
-
|
|
767
|
-
|
|
768
|
-
cols.push(h("col", { style: { width: `${item.size}px` } }));
|
|
769
|
-
end = item.start + item.size;
|
|
770
|
-
}
|
|
771
|
-
if (binding.columns.totalSize > end) cols.push(h("col", { style: { width: `${binding.columns.totalSize - end}px` } }));
|
|
772
|
-
return h("colgroup", cols);
|
|
1354
|
+
function editorIssues(id, issues, pending = false) {
|
|
1355
|
+
return issues.length || pending ? h("span", {
|
|
1356
|
+
id,
|
|
1357
|
+
"data-edit-issues": "",
|
|
1358
|
+
role: "status"
|
|
1359
|
+
}, pending ? "Checking changes…" : issues.map((problem) => problem.message).join(" ")) : null;
|
|
773
1360
|
}
|
|
774
|
-
function
|
|
775
|
-
return
|
|
1361
|
+
function useEditorId() {
|
|
1362
|
+
return `vt-edit-${useId()}`;
|
|
776
1363
|
}
|
|
777
1364
|
|
|
778
1365
|
//#endregion
|
|
@@ -857,8 +1444,9 @@ function treeKeydown(event, context, virtual) {
|
|
|
857
1444
|
if (!table.tree || !target?.closest) return;
|
|
858
1445
|
if (target.closest("input, textarea, select, [contenteditable=true]") || target.closest("button") && !target.closest("[data-expand-toggle]")) return;
|
|
859
1446
|
const key = target.closest("tr")?.getAttribute("data-tree-key");
|
|
860
|
-
const
|
|
861
|
-
const
|
|
1447
|
+
const visible = table.gridRows;
|
|
1448
|
+
const index = visible.findIndex((row) => getRowItemKey(row.key) === key);
|
|
1449
|
+
const row = visible[index];
|
|
862
1450
|
if (!row) return;
|
|
863
1451
|
const command = gridCommand({
|
|
864
1452
|
key: event.key,
|
|
@@ -874,11 +1462,15 @@ function treeKeydown(event, context, virtual) {
|
|
|
874
1462
|
let next = row;
|
|
875
1463
|
if (command?.type === "tree") {
|
|
876
1464
|
if (command.action === "expand" || command.action === "collapse") table.toggleExpanded(row.key, command.action === "expand");
|
|
877
|
-
else if (command.action === "siblings") for (const sibling of
|
|
878
|
-
|
|
879
|
-
|
|
880
|
-
|
|
881
|
-
|
|
1465
|
+
else if (command.action === "siblings") for (const sibling of [
|
|
1466
|
+
...table.topRows,
|
|
1467
|
+
...table.processedRows,
|
|
1468
|
+
...table.bottomRows
|
|
1469
|
+
].filter((candidate) => candidate.parentKey === row.parentKey && candidate.canExpand)) table.toggleExpanded(sibling.key, true);
|
|
1470
|
+
else if (command.action === "child") next = visible.find((candidate) => candidate.parentKey === row.key) ?? row;
|
|
1471
|
+
else next = visible.find((candidate) => candidate.key === row.parentKey) ?? row;
|
|
1472
|
+
} else if (event.key === "ArrowDown" || event.key === "ArrowUp") next = visible[index + (event.key === "ArrowDown" ? 1 : -1)] ?? row;
|
|
1473
|
+
else if (event.key === "Home" || event.key === "End") next = visible[event.key === "Home" ? 0 : visible.length - 1] ?? row;
|
|
882
1474
|
else return;
|
|
883
1475
|
event.preventDefault();
|
|
884
1476
|
const root = target.closest("table");
|
|
@@ -912,11 +1504,12 @@ const DataTableExpandToggle = defineComponent({
|
|
|
912
1504
|
slots: Object,
|
|
913
1505
|
setup(props, { slots }) {
|
|
914
1506
|
const table = injectDataTable("<DataTableExpandToggle>");
|
|
1507
|
+
const pin = injectPinnedRow();
|
|
915
1508
|
const context = injectHierarchy();
|
|
916
1509
|
const grid = injectDataGrid();
|
|
917
1510
|
const locale = useTableLocale();
|
|
918
1511
|
const label = () => props.row.isExpanded ? props.collapseLabel ?? locale().messages.collapseRow : props.expandLabel ?? locale().messages.expandRow;
|
|
919
|
-
return () => props.row.canExpand ? h("button", {
|
|
1512
|
+
return () => props.row.canExpand && !(pin && !table.tree) ? h("button", {
|
|
920
1513
|
type: "button",
|
|
921
1514
|
"data-expand-toggle": "",
|
|
922
1515
|
tabindex: table.tree ? -1 : void 0,
|
|
@@ -928,7 +1521,7 @@ const DataTableExpandToggle = defineComponent({
|
|
|
928
1521
|
onClick: (event) => {
|
|
929
1522
|
event.stopPropagation();
|
|
930
1523
|
if (grid?.table === table) grid.focusCell({
|
|
931
|
-
row: table.
|
|
1524
|
+
row: table.gridRows.indexOf(props.row),
|
|
932
1525
|
column: Math.max(0, table.columns.findIndex((column) => column.id === resolveTreeColumn(table, context?.treeColumn)))
|
|
933
1526
|
});
|
|
934
1527
|
table.toggleExpanded(props.row.key);
|
|
@@ -965,7 +1558,7 @@ const DataTableTreeCell = defineComponent({
|
|
|
965
1558
|
event.stopPropagation();
|
|
966
1559
|
const element = event.currentTarget.closest("table");
|
|
967
1560
|
if (grid?.table === table) grid.focusCell({
|
|
968
|
-
row: table.
|
|
1561
|
+
row: table.gridRows.indexOf(props.row),
|
|
969
1562
|
column: Math.max(0, table.columns.findIndex((column) => column.id === resolveTreeColumn(table, context?.treeColumn)))
|
|
970
1563
|
});
|
|
971
1564
|
table.toggleExpanded(props.row.key, true);
|
|
@@ -999,8 +1592,10 @@ const DataTableDetailRow = defineComponent({
|
|
|
999
1592
|
slots: Object,
|
|
1000
1593
|
setup(props, { slots }) {
|
|
1001
1594
|
const table = injectDataTable("<DataTableDetailRow>");
|
|
1595
|
+
const columnOffset = injectColumnOffset();
|
|
1002
1596
|
const context = injectHierarchy();
|
|
1003
1597
|
const virtual = injectVirtual();
|
|
1598
|
+
const rowLayout = injectRowLayout();
|
|
1004
1599
|
let opened = false;
|
|
1005
1600
|
return () => {
|
|
1006
1601
|
if (props.row.isExpanded && !props.hidden) opened = true;
|
|
@@ -1009,10 +1604,11 @@ const DataTableDetailRow = defineComponent({
|
|
|
1009
1604
|
return h("tr", {
|
|
1010
1605
|
id: itemId(context, props.row, true),
|
|
1011
1606
|
"data-detail": "",
|
|
1607
|
+
"aria-rowindex": hidden ? void 0 : rowLayout?.index(props.row.key, "detail"),
|
|
1012
1608
|
hidden,
|
|
1013
1609
|
...virtual && !hidden ? { ref: (target) => virtual.rows.measureElement(target, getRowItemKey(props.row.key, "detail")) } : {}
|
|
1014
1610
|
}, [h("td", {
|
|
1015
|
-
colspan: Math.max(1, props.colspan ?? table.columns.length),
|
|
1611
|
+
colspan: virtual ? physicalColumnCount(virtual, table.columns.length, columnOffset()) : Math.max(1, props.colspan ?? table.columns.length),
|
|
1016
1612
|
class: "vt-detail-cell"
|
|
1017
1613
|
}, [slots.default?.({ row: props.row })])]);
|
|
1018
1614
|
};
|
|
@@ -1043,7 +1639,7 @@ function createDetails(table, slot, colspan) {
|
|
|
1043
1639
|
visited.delete(key);
|
|
1044
1640
|
return [];
|
|
1045
1641
|
}
|
|
1046
|
-
return visible.has(key) ? [] : [render(table.rows[index], index, true)];
|
|
1642
|
+
return visible.has(key) ? [] : [render(table.rows[index], index + table.topRows.length, true)];
|
|
1047
1643
|
});
|
|
1048
1644
|
}
|
|
1049
1645
|
};
|
|
@@ -1066,29 +1662,36 @@ const DataTableRoot = defineComponent({
|
|
|
1066
1662
|
as: asProp("table"),
|
|
1067
1663
|
...virtualProps,
|
|
1068
1664
|
...hierarchyProps,
|
|
1069
|
-
...columnLayoutProps
|
|
1665
|
+
...columnLayoutProps,
|
|
1666
|
+
...resizingProps,
|
|
1667
|
+
...groupingProps
|
|
1070
1668
|
},
|
|
1071
1669
|
setup(props, { slots }) {
|
|
1072
1670
|
provideDataTable(props.table);
|
|
1073
1671
|
provideColumnOffset(() => props.leadingColumns);
|
|
1074
1672
|
const hierarchy = provideHierarchy(props.table, props);
|
|
1075
1673
|
const element = shallowRef();
|
|
1674
|
+
const layout = provideColumnLayout(props.table, props, () => element.value);
|
|
1675
|
+
const rowLayout = provideRowLayout(props.table, props, () => element.value);
|
|
1076
1676
|
const editingGrid = injectEditingGrid();
|
|
1677
|
+
const virtualGrid = props.virtualColumns ? editingGrid ?? useDataGrid(props.table) : editingGrid;
|
|
1077
1678
|
const render = (virtual) => h(props.as, {
|
|
1078
|
-
|
|
1079
|
-
|
|
1679
|
+
ref: element,
|
|
1680
|
+
style: layout.style(virtual?.columns ? virtual.columns.totalSize + virtual.gutter : void 0),
|
|
1681
|
+
"data-column-layout": flag(layout.enabled()),
|
|
1682
|
+
role: props.table.tree || props.table.grouped ? "treegrid" : void 0,
|
|
1683
|
+
"aria-rowcount": rowLayout.count ?? (props.table.tree ? props.table.processedRows.length : props.table.rowCount) + 1,
|
|
1080
1684
|
"aria-colcount": props.table.columns.length + props.leadingColumns,
|
|
1081
1685
|
"aria-busy": props.table.loadState === "loading" || props.table.loadState === "streaming" ? "true" : void 0,
|
|
1082
|
-
"data-empty": flag(props.table.
|
|
1686
|
+
"data-empty": flag(props.table.renderItems.length === 0 && props.table.topRows.length === 0 && props.table.bottomRows.length === 0),
|
|
1083
1687
|
onKeydown: (event) => treeKeydown(event, hierarchy, virtual),
|
|
1084
|
-
...virtual ? {
|
|
1085
|
-
|
|
1086
|
-
"data-virtual": ""
|
|
1087
|
-
} : {}
|
|
1088
|
-
}, slots.default?.({ table: props.table }) ?? [h(DataTableHeader), h(DataTableBody)]);
|
|
1688
|
+
...virtual ? { "data-virtual": "" } : {}
|
|
1689
|
+
}, [virtual?.columns ? virtualColgroup(props.table.columns, virtual, layout.width, layout.leadingWidths()) : layout.colgroup(), slots.default?.({ table: props.table }) ?? [h(DataTableHeader), h(DataTableBody)]]);
|
|
1089
1690
|
return () => props.virtual ? h(VirtualContent, {
|
|
1090
1691
|
table: props.table,
|
|
1091
|
-
...
|
|
1692
|
+
...virtualGrid ? { grid: virtualGrid } : {},
|
|
1693
|
+
virtualColumns: props.virtualColumns,
|
|
1694
|
+
gutter: layout.leadingWidths().reduce((sum, width) => sum + width, 0),
|
|
1092
1695
|
options: virtualOptions(props),
|
|
1093
1696
|
tableElement: () => element.value,
|
|
1094
1697
|
render
|
|
@@ -1159,6 +1762,9 @@ const DataTableHeaderCell = defineComponent({
|
|
|
1159
1762
|
setup(props, { slots }) {
|
|
1160
1763
|
const table = injectDataTable("<DataTableHeaderCell>");
|
|
1161
1764
|
const columnOffset = injectColumnOffset();
|
|
1765
|
+
const layout = injectColumnLayout();
|
|
1766
|
+
const rows = injectRowLayout();
|
|
1767
|
+
provideHeaderColumn(() => props.column);
|
|
1162
1768
|
return () => {
|
|
1163
1769
|
const { column } = props;
|
|
1164
1770
|
const sort = table.getSort(column.id);
|
|
@@ -1175,9 +1781,14 @@ const DataTableHeaderCell = defineComponent({
|
|
|
1175
1781
|
"data-align": column.align,
|
|
1176
1782
|
"data-sortable": flag(column.sortable),
|
|
1177
1783
|
"data-sort": sort?.direction,
|
|
1178
|
-
|
|
1784
|
+
...layout?.attrs(column, true),
|
|
1785
|
+
style: [
|
|
1786
|
+
columnStyle(column),
|
|
1787
|
+
layout?.attrs(column, true)["style"],
|
|
1788
|
+
rows?.headerStyle(!!column.pinned)
|
|
1789
|
+
],
|
|
1179
1790
|
"aria-colindex": table.columns.indexOf(column) + columnOffset() + 1
|
|
1180
|
-
}, content);
|
|
1791
|
+
}, [content, layout?.resizable() && column.resizable ? h(DataTableColumnResizer) : null]);
|
|
1181
1792
|
};
|
|
1182
1793
|
}
|
|
1183
1794
|
});
|
|
@@ -1219,6 +1830,7 @@ const DataTableSortButton = defineComponent({
|
|
|
1219
1830
|
*/
|
|
1220
1831
|
const DataTableBody = defineComponent({
|
|
1221
1832
|
name: "DataTableBody",
|
|
1833
|
+
inheritAttrs: false,
|
|
1222
1834
|
slots: Object,
|
|
1223
1835
|
props: {
|
|
1224
1836
|
as: asProp("tbody"),
|
|
@@ -1228,36 +1840,74 @@ const DataTableBody = defineComponent({
|
|
|
1228
1840
|
default: void 0
|
|
1229
1841
|
}
|
|
1230
1842
|
},
|
|
1231
|
-
setup(props, { slots }) {
|
|
1843
|
+
setup(props, { slots, attrs }) {
|
|
1232
1844
|
const table = injectDataTable("<DataTableBody>");
|
|
1233
1845
|
const locale = useTableLocale();
|
|
1234
1846
|
const virtual = injectVirtual();
|
|
1847
|
+
const rowLayout = injectRowLayout();
|
|
1235
1848
|
const details = createDetails(table, () => slots.detail, () => props.colspan ?? table.columns.length);
|
|
1236
1849
|
return () => {
|
|
1237
|
-
if (props.virtual && !virtual) return h(VirtualDataTableBody, props, slots);
|
|
1238
|
-
if (virtual) return renderTableBody(table, virtual, props.as, props.colspan, slots, details);
|
|
1850
|
+
if (props.virtual && !virtual) return h(VirtualDataTableBody, mergeProps(props, attrs), slots);
|
|
1851
|
+
if (virtual) return pinnedTableSections(table, renderTableBody(table, virtual, props.as, props.colspan, slots, details, void 0, rowLayout), props.as, slots, attrs);
|
|
1239
1852
|
let content = slots.default?.({ rows: table.rows });
|
|
1240
|
-
if (!content) content = table.
|
|
1853
|
+
if (!content) content = table.renderItems.length === 0 && slots.empty ? h("tr", { "data-empty": "" }, [h("td", { colspan: Math.max(1, table.columns.length) }, slots.empty())]) : (rowLayout?.items ?? table.renderItems).map((item) => item.kind === "row" ? slots.row ? h(Fragment, { key: item.key }, [slots.row(item)]) : h(DataTableRow, {
|
|
1241
1854
|
key: item.key,
|
|
1242
1855
|
row: item.row,
|
|
1243
1856
|
rowIndex: item.rowIndex
|
|
1244
|
-
}) : item.kind === "detail" ? details.render(item.row, item.rowIndex) :
|
|
1857
|
+
}) : item.kind === "detail" ? details.render(item.row, item.rowIndex) : groupRow(item, slots, rowLayout?.aggregatePosition ?? "group", rowLayout?.footer(item.key)));
|
|
1245
1858
|
const visibleDetails = new Set(table.renderItems.filter((item) => item.kind === "detail").map((item) => item.row.key));
|
|
1246
1859
|
const retained = slots.default ? [] : details.retained(visibleDetails);
|
|
1247
1860
|
const sentinel = loadSentinel(table, props.colspan ?? table.columns.length, locale());
|
|
1248
|
-
return h(props.as, [
|
|
1861
|
+
return pinnedTableSections(table, h(props.as, { "data-row-region": "centre" }, [
|
|
1249
1862
|
...Array.isArray(content) ? content : content ? [content] : [],
|
|
1250
1863
|
...retained,
|
|
1251
1864
|
...sentinel ? [sentinel] : []
|
|
1252
|
-
]);
|
|
1865
|
+
]), props.as, slots, attrs);
|
|
1253
1866
|
};
|
|
1254
1867
|
}
|
|
1255
1868
|
});
|
|
1256
|
-
function
|
|
1257
|
-
const
|
|
1258
|
-
|
|
1869
|
+
function pinnedTableSections(table, centre, as, slots, attrs = {}) {
|
|
1870
|
+
const body = cloneVNode(centre, {
|
|
1871
|
+
...attrs,
|
|
1872
|
+
"data-row-region": "centre"
|
|
1873
|
+
});
|
|
1874
|
+
const region = (side) => {
|
|
1875
|
+
const rows = side === "top" ? table.topRows : table.bottomRows;
|
|
1876
|
+
return rows.length ? h(as, {
|
|
1877
|
+
"data-row-region": side,
|
|
1878
|
+
class: attrs["class"]
|
|
1879
|
+
}, rows.map((row, index) => {
|
|
1880
|
+
const rowIndex = side === "top" ? index : table.topRows.length + table.rows.length + index;
|
|
1881
|
+
return h(DataTablePinnedRow, {
|
|
1882
|
+
key: getRowItemKey(row.key),
|
|
1883
|
+
row,
|
|
1884
|
+
side
|
|
1885
|
+
}, { default: () => {
|
|
1886
|
+
const child = slots.row?.({
|
|
1887
|
+
row,
|
|
1888
|
+
rowIndex
|
|
1889
|
+
}) ?? h(DataTableRow, {
|
|
1890
|
+
row,
|
|
1891
|
+
rowIndex
|
|
1892
|
+
});
|
|
1893
|
+
return [isVNode(child) ? child : h(Fragment, null, [child])];
|
|
1894
|
+
} });
|
|
1895
|
+
})) : null;
|
|
1896
|
+
};
|
|
1897
|
+
return table.topRows.length || table.bottomRows.length ? h(Fragment, [
|
|
1898
|
+
region("top"),
|
|
1899
|
+
body,
|
|
1900
|
+
region("bottom")
|
|
1901
|
+
]) : body;
|
|
1902
|
+
}
|
|
1903
|
+
function renderTableBody(table, virtual, as, colspan, slots, details, element, rowLayout) {
|
|
1904
|
+
const width = physicalColumnCount(virtual, table.columns.length, Math.max(0, (colspan ?? table.columns.length) - table.columns.length));
|
|
1905
|
+
const attrs = {
|
|
1906
|
+
"data-row-region": "centre",
|
|
1907
|
+
...element ? { ref: element } : {}
|
|
1908
|
+
};
|
|
1259
1909
|
const content = slots.default?.({ rows: virtual.rowItems.flatMap((item) => item.renderItem.kind === "row" ? [item.renderItem.row] : []) });
|
|
1260
|
-
if (table.
|
|
1910
|
+
if (table.renderItems.length === 0 && slots.empty) return h(as, attrs, h("tr", { "data-empty": "" }, [h("td", { colspan: Math.max(1, width) }, slots.empty())]));
|
|
1261
1911
|
if (content) return h(as, attrs, [
|
|
1262
1912
|
rowSpacer(virtual.rows.paddingStart, width, "gap-start"),
|
|
1263
1913
|
...content,
|
|
@@ -1269,13 +1919,15 @@ function renderTableBody(table, virtual, as, colspan, slots, details, element) {
|
|
|
1269
1919
|
key: item.key,
|
|
1270
1920
|
row: item.renderItem.row,
|
|
1271
1921
|
rowIndex: item.renderItem.rowIndex
|
|
1272
|
-
}) : item.renderItem.kind === "detail" ? details.render(item.renderItem.row, item.renderItem.rowIndex) :
|
|
1922
|
+
}) : item.renderItem.kind === "detail" ? details.render(item.renderItem.row, item.renderItem.rowIndex) : groupRow(item.renderItem, slots, rowLayout?.aggregatePosition ?? "group", rowLayout?.footer(item.key))),
|
|
1923
|
+
...table.bottomRows.length ? [rowSpacer(Math.max(0, virtual.rows.viewportSize - virtual.rows.totalSize), width, "pin-fill")] : [],
|
|
1273
1924
|
...details.retained(new Set(virtual.rowItems.flatMap((item) => item.renderItem.kind === "detail" ? [item.renderItem.row.key] : []))),
|
|
1274
1925
|
...loadSentinel(table, width) ? [loadSentinel(table, width)] : []
|
|
1275
1926
|
]);
|
|
1276
1927
|
}
|
|
1277
1928
|
const VirtualDataTableBody = defineComponent({
|
|
1278
1929
|
name: "DataTableVirtualBody",
|
|
1930
|
+
inheritAttrs: false,
|
|
1279
1931
|
props: {
|
|
1280
1932
|
as: asProp("tbody"),
|
|
1281
1933
|
...virtualProps,
|
|
@@ -1285,12 +1937,13 @@ const VirtualDataTableBody = defineComponent({
|
|
|
1285
1937
|
}
|
|
1286
1938
|
},
|
|
1287
1939
|
slots: Object,
|
|
1288
|
-
setup(props, { slots }) {
|
|
1940
|
+
setup(props, { slots, attrs }) {
|
|
1289
1941
|
const table = injectDataTable("<DataTableBody>");
|
|
1942
|
+
const rowLayout = injectRowLayout();
|
|
1290
1943
|
const element = shallowRef();
|
|
1291
1944
|
const virtual = createComponentVirtual(table, virtualOptions(props), () => element.value?.closest("table"));
|
|
1292
1945
|
const details = createDetails(table, () => slots.detail, () => props.colspan ?? table.columns.length);
|
|
1293
|
-
return () => renderTableBody(table, virtual, props.as, props.colspan, slots, details, element);
|
|
1946
|
+
return () => pinnedTableSections(table, renderTableBody(table, virtual, props.as, props.colspan, slots, details, element, rowLayout), props.as, slots, attrs);
|
|
1294
1947
|
}
|
|
1295
1948
|
});
|
|
1296
1949
|
/** A body row; `aria-selected` and `data-selected` follow the selection. */
|
|
@@ -1317,19 +1970,21 @@ const DataTableRow = defineComponent({
|
|
|
1317
1970
|
const table = injectDataTable("<DataTableRow>");
|
|
1318
1971
|
const virtual = injectVirtual();
|
|
1319
1972
|
const hierarchy = injectHierarchy();
|
|
1973
|
+
const rowLayout = injectRowLayout();
|
|
1320
1974
|
return () => {
|
|
1321
1975
|
const { row } = props;
|
|
1322
1976
|
const selected = table.isSelected(row.key);
|
|
1323
1977
|
const item = virtual ? virtualRow(virtual, row) : void 0;
|
|
1324
|
-
const position = props.rowIndex ?? (item?.renderItem.kind === "row" ? item.renderItem.rowIndex : table.
|
|
1978
|
+
const position = props.rowIndex ?? (item?.renderItem.kind === "row" ? item.renderItem.rowIndex : table.gridRows.indexOf(row));
|
|
1325
1979
|
return h(props.as, mergeProps(props.attributes ?? {}, {
|
|
1326
|
-
"aria-rowindex": position === -1 ? void 0 : table.pageStart + position + 1,
|
|
1980
|
+
"aria-rowindex": rowLayout?.index(row.key) ?? (position === -1 ? void 0 : table.pageStart + position + 1),
|
|
1327
1981
|
"aria-selected": table.selectionMode === "none" ? void 0 : String(selected),
|
|
1982
|
+
"aria-level": rowLayout?.level(row.key),
|
|
1328
1983
|
"data-selected": flag(selected),
|
|
1329
1984
|
"data-key": String(row.key),
|
|
1330
1985
|
"data-dirty": flag(row.isDirty),
|
|
1331
1986
|
...hierarchyRowAttrs(table, row, hierarchy),
|
|
1332
|
-
tabindex: table.tree ? (hierarchy?.focusKey ?? table.
|
|
1987
|
+
tabindex: table.tree ? (hierarchy?.focusKey ?? table.gridRows[0]?.key) === row.key ? 0 : -1 : void 0,
|
|
1333
1988
|
onFocus: () => {
|
|
1334
1989
|
if (hierarchy) hierarchy.focus.value = row.key;
|
|
1335
1990
|
},
|
|
@@ -1341,11 +1996,11 @@ const DataTableRow = defineComponent({
|
|
|
1341
1996
|
row,
|
|
1342
1997
|
selected,
|
|
1343
1998
|
columns: table.columns
|
|
1344
|
-
}) ?? table.columns
|
|
1999
|
+
}) ?? renderColumns(table.columns, virtual, (column) => h(DataTableCell, {
|
|
1345
2000
|
key: column.id,
|
|
1346
2001
|
row,
|
|
1347
2002
|
column
|
|
1348
|
-
})));
|
|
2003
|
+
}), "td"));
|
|
1349
2004
|
};
|
|
1350
2005
|
}
|
|
1351
2006
|
});
|
|
@@ -1366,6 +2021,8 @@ const DataTableCell = defineComponent({
|
|
|
1366
2021
|
const table = injectDataTable("<DataTableCell>");
|
|
1367
2022
|
const columnOffset = injectColumnOffset();
|
|
1368
2023
|
const hierarchy = injectHierarchy();
|
|
2024
|
+
const layout = injectColumnLayout();
|
|
2025
|
+
const pin = injectPinnedRow();
|
|
1369
2026
|
return () => {
|
|
1370
2027
|
const { row, column } = props;
|
|
1371
2028
|
const value = row.getValue(column.id);
|
|
@@ -1379,6 +2036,8 @@ const DataTableCell = defineComponent({
|
|
|
1379
2036
|
return h(props.as, {
|
|
1380
2037
|
"data-column": column.id,
|
|
1381
2038
|
"data-align": column.align,
|
|
2039
|
+
...layout?.attrs(column),
|
|
2040
|
+
...pin ? mergeProps(layout?.attrs(column) ?? {}, pin.attrs(!!column.pinned)) : {},
|
|
1382
2041
|
"aria-colindex": table.columns.indexOf(column) + columnOffset() + 1
|
|
1383
2042
|
}, props.tree && table.tree && column.id === resolveTreeColumn(table, hierarchy?.treeColumn) ? h(DataTableTreeCell, { row }, { default: content }) : content());
|
|
1384
2043
|
};
|
|
@@ -1499,7 +2158,7 @@ const DataTableEditCell = defineComponent({
|
|
|
1499
2158
|
const id = useEditorId();
|
|
1500
2159
|
const element = shallowRef();
|
|
1501
2160
|
const position = () => ({
|
|
1502
|
-
row: props.rowIndex ?? table.
|
|
2161
|
+
row: props.rowIndex ?? table.gridRows.indexOf(props.row),
|
|
1503
2162
|
column: table.columns.indexOf(props.column)
|
|
1504
2163
|
});
|
|
1505
2164
|
const active = computed(() => context.mode === "row" ? context.draft?.rowKey === props.row.key : grid.isEditing(position()));
|
|
@@ -1652,6 +2311,22 @@ const DataTableRowActions = defineComponent({
|
|
|
1652
2311
|
const context = inject(editingKey, void 0);
|
|
1653
2312
|
const id = useEditorId();
|
|
1654
2313
|
const element = shallowRef();
|
|
2314
|
+
const virtual = injectVirtual();
|
|
2315
|
+
const pin = (side) => {
|
|
2316
|
+
const root = element.value?.closest("table");
|
|
2317
|
+
const key = props.row.key;
|
|
2318
|
+
table.pinRow(key, side);
|
|
2319
|
+
if (side === false) virtual?.rows.scrollToKey(key);
|
|
2320
|
+
nextTick(() => {
|
|
2321
|
+
const control = [...root?.querySelectorAll("[data-row-actions-key]") ?? []].find((target) => target.getAttribute("data-row-actions-key") === getRowItemKey(key))?.querySelector("summary");
|
|
2322
|
+
control?.focus({ preventScroll: true });
|
|
2323
|
+
if (side === false) control?.scrollIntoView?.({
|
|
2324
|
+
block: "nearest",
|
|
2325
|
+
inline: "nearest"
|
|
2326
|
+
});
|
|
2327
|
+
if (!control) root?.querySelector("thead button")?.focus();
|
|
2328
|
+
});
|
|
2329
|
+
};
|
|
1655
2330
|
watch(() => context?.draft?.rowKey === props.row.key, (active, previous) => {
|
|
1656
2331
|
const target = element.value;
|
|
1657
2332
|
if (previous && !active && !context?.draft && target?.closest("tr")?.contains(target.ownerDocument.activeElement)) nextTick(() => target.querySelector("button[data-edit-row]")?.focus());
|
|
@@ -1672,6 +2347,7 @@ const DataTableRowActions = defineComponent({
|
|
|
1672
2347
|
return h("div", {
|
|
1673
2348
|
ref: element,
|
|
1674
2349
|
"data-row-actions": "",
|
|
2350
|
+
"data-row-actions-key": getRowItemKey(props.row.key),
|
|
1675
2351
|
role: "group",
|
|
1676
2352
|
"aria-label": messages.rowActionsFor(rowName),
|
|
1677
2353
|
"aria-busy": draft?.pending ? "true" : void 0
|
|
@@ -1683,7 +2359,13 @@ const DataTableRowActions = defineComponent({
|
|
|
1683
2359
|
block: "nearest",
|
|
1684
2360
|
inline: "nearest"
|
|
1685
2361
|
}));
|
|
1686
|
-
} }, [h("summary", { "aria-label": messages.actionsForRow(rowName) }, messages.actions), h("div", { "data-row-menu": "" }, [
|
|
2362
|
+
} }, [h("summary", { "aria-label": messages.actionsForRow(rowName) }, messages.actions), h("div", { "data-row-menu": "" }, [
|
|
2363
|
+
button(messages.pinRowTop, () => pin("top"), !!draft || table.rowPinning.top.includes(props.row.key)),
|
|
2364
|
+
button(messages.pinRowBottom, () => pin("bottom"), !!draft || table.rowPinning.bottom.includes(props.row.key)),
|
|
2365
|
+
table.rowPinning.top.includes(props.row.key) || table.rowPinning.bottom.includes(props.row.key) ? button(messages.unpinRow, () => pin(false), !!draft) : null,
|
|
2366
|
+
button(messages.revertRow, () => table.revert([props.row.key]), !props.row.isDirty || !!draft),
|
|
2367
|
+
props.removable ? button(messages.removeRow, () => table.removeRows([props.row.key]), !!draft) : null
|
|
2368
|
+
])]),
|
|
1687
2369
|
editorIssues(id, issues, !!draft?.pending)
|
|
1688
2370
|
]);
|
|
1689
2371
|
};
|
|
@@ -1743,6 +2425,8 @@ const DataGridRoot = defineComponent({
|
|
|
1743
2425
|
...virtualProps,
|
|
1744
2426
|
...hierarchyProps,
|
|
1745
2427
|
...columnLayoutProps,
|
|
2428
|
+
...resizingProps,
|
|
2429
|
+
...groupingProps,
|
|
1746
2430
|
/** Width reserved before data columns, for a row-number/header column. */
|
|
1747
2431
|
gutter: {
|
|
1748
2432
|
type: Number,
|
|
@@ -1760,6 +2444,8 @@ const DataGridRoot = defineComponent({
|
|
|
1760
2444
|
provideDataGrid(grid);
|
|
1761
2445
|
provideHierarchy(props.table, props);
|
|
1762
2446
|
const element = ref();
|
|
2447
|
+
const layout = provideColumnLayout(props.table, props, () => element.value);
|
|
2448
|
+
const rowLayout = provideRowLayout(props.table, props, () => element.value);
|
|
1763
2449
|
const id = `vt-grid-${useId()}`;
|
|
1764
2450
|
const focus = () => {
|
|
1765
2451
|
nextTick(() => {
|
|
@@ -1794,7 +2480,7 @@ const DataGridRoot = defineComponent({
|
|
|
1794
2480
|
row: 0,
|
|
1795
2481
|
column: 0
|
|
1796
2482
|
} : {
|
|
1797
|
-
row: props.table.
|
|
2483
|
+
row: props.table.gridRows.length - 1,
|
|
1798
2484
|
column: props.table.columns.length - 1
|
|
1799
2485
|
}, { extend: event.shiftKey });
|
|
1800
2486
|
event.preventDefault();
|
|
@@ -1842,11 +2528,11 @@ const DataGridRoot = defineComponent({
|
|
|
1842
2528
|
return h(props.as, {
|
|
1843
2529
|
ref: element,
|
|
1844
2530
|
id,
|
|
1845
|
-
role: props.table.tree ? "treegrid" : "grid",
|
|
2531
|
+
role: props.table.tree || props.table.grouped ? "treegrid" : "grid",
|
|
1846
2532
|
tabindex: 0,
|
|
1847
2533
|
"aria-label": props.label,
|
|
1848
2534
|
"aria-multiselectable": "true",
|
|
1849
|
-
"aria-rowcount": (props.table.tree ? props.table.processedRows.length : binding ? props.table.rowCount : props.table.rows.length) + 1,
|
|
2535
|
+
"aria-rowcount": rowLayout.count ?? (props.table.tree ? props.table.processedRows.length : binding ? props.table.rowCount : props.table.rows.length) + props.table.topRows.length + props.table.bottomRows.length + 1,
|
|
1850
2536
|
"aria-colcount": props.table.columns.length + props.leadingColumns,
|
|
1851
2537
|
"aria-busy": props.table.loadState === "loading" || props.table.loadState === "streaming" ? "true" : void 0,
|
|
1852
2538
|
"aria-activedescendant": focusPosition && !grid.editor ? cellId(id, focusPosition.row, focusPosition.column) : void 0,
|
|
@@ -1854,20 +2540,16 @@ const DataGridRoot = defineComponent({
|
|
|
1854
2540
|
onCopy: (event) => onCopy(event),
|
|
1855
2541
|
onCut: (event) => onCopy(event, true),
|
|
1856
2542
|
onPaste,
|
|
1857
|
-
|
|
1858
|
-
|
|
1859
|
-
|
|
1860
|
-
|
|
1861
|
-
width: `${binding.columns.totalSize + binding.gutter}px`
|
|
1862
|
-
} : void 0
|
|
1863
|
-
} : {}
|
|
1864
|
-
}, binding ? [virtualColgroup(props.table.columns, binding), slots.default?.({
|
|
2543
|
+
"data-column-layout": flag(layout.enabled()),
|
|
2544
|
+
style: layout.style(binding?.columns ? binding.columns.totalSize + binding.gutter : void 0),
|
|
2545
|
+
...binding ? { "data-virtual": "" } : {}
|
|
2546
|
+
}, binding ? [binding.columns ? virtualColgroup(props.table.columns, binding, layout.width, layout.leadingWidths()) : layout.colgroup(), slots.default?.({
|
|
1865
2547
|
table: props.table,
|
|
1866
2548
|
grid
|
|
1867
|
-
}) ?? [h(DataTableHeader), h(DataGridBody)]] : slots.default?.({
|
|
2549
|
+
}) ?? [h(DataTableHeader), h(DataGridBody)]] : [layout.colgroup(), slots.default?.({
|
|
1868
2550
|
table: props.table,
|
|
1869
2551
|
grid
|
|
1870
|
-
}) ?? [h(DataTableHeader), h(DataGridBody)]);
|
|
2552
|
+
}) ?? [h(DataTableHeader), h(DataGridBody)]]);
|
|
1871
2553
|
};
|
|
1872
2554
|
return () => props.virtual ? h(VirtualContent, {
|
|
1873
2555
|
table: props.table,
|
|
@@ -1886,6 +2568,7 @@ const DataGridRoot = defineComponent({
|
|
|
1886
2568
|
*/
|
|
1887
2569
|
const DataGridBody = defineComponent({
|
|
1888
2570
|
name: "DataGridBody",
|
|
2571
|
+
inheritAttrs: false,
|
|
1889
2572
|
slots: Object,
|
|
1890
2573
|
props: {
|
|
1891
2574
|
as: asProp("tbody"),
|
|
@@ -1904,22 +2587,76 @@ const DataGridBody = defineComponent({
|
|
|
1904
2587
|
default: void 0
|
|
1905
2588
|
}
|
|
1906
2589
|
},
|
|
1907
|
-
setup(props, { slots }) {
|
|
2590
|
+
setup(props, { slots, attrs }) {
|
|
1908
2591
|
const table = injectDataTable("<DataGridBody>");
|
|
1909
2592
|
const { grid } = useGrid("<DataGridBody>");
|
|
1910
2593
|
const virtual = injectVirtual();
|
|
1911
2594
|
const hierarchy = injectHierarchy();
|
|
2595
|
+
const rowLayout = injectRowLayout();
|
|
2596
|
+
const columnOffset = injectColumnOffset();
|
|
1912
2597
|
const details = createDetails(table, () => slots.detail, () => props.colspan ?? table.columns.length + (slots.rowHeader ? 1 : 0));
|
|
1913
2598
|
const element = ref();
|
|
2599
|
+
const pinnedSections = (centre, binding) => {
|
|
2600
|
+
const body = cloneVNode(centre, {
|
|
2601
|
+
...attrs,
|
|
2602
|
+
"data-row-region": "centre"
|
|
2603
|
+
});
|
|
2604
|
+
const region = (side) => {
|
|
2605
|
+
const rows = side === "top" ? table.topRows : table.bottomRows;
|
|
2606
|
+
return rows.length ? h(props.as, {
|
|
2607
|
+
"data-row-region": side,
|
|
2608
|
+
class: attrs["class"]
|
|
2609
|
+
}, rows.map((row, index) => {
|
|
2610
|
+
const rowIndex = side === "top" ? index : table.topRows.length + table.rows.length + index;
|
|
2611
|
+
return h(DataTablePinnedRow, {
|
|
2612
|
+
key: row.key,
|
|
2613
|
+
row,
|
|
2614
|
+
side
|
|
2615
|
+
}, { default: () => [h("tr", mergeProps(rowAttributes(props.rowAttrs, row), {
|
|
2616
|
+
role: "row",
|
|
2617
|
+
"data-key": String(row.key),
|
|
2618
|
+
"data-dirty": flag(row.isDirty),
|
|
2619
|
+
"aria-rowindex": rowLayout?.index(row.key),
|
|
2620
|
+
"aria-level": rowLayout?.level(row.key),
|
|
2621
|
+
...hierarchyRowAttrs(table, row, hierarchy)
|
|
2622
|
+
}), [slots.rowHeader?.({
|
|
2623
|
+
row,
|
|
2624
|
+
index: rowIndex
|
|
2625
|
+
}), ...renderColumns(table.columns, binding, (column, columnIndex) => h(DataGridCell, {
|
|
2626
|
+
key: column.id,
|
|
2627
|
+
row,
|
|
2628
|
+
column,
|
|
2629
|
+
rowIndex,
|
|
2630
|
+
columnIndex,
|
|
2631
|
+
tree: props.treeCell
|
|
2632
|
+
}, {
|
|
2633
|
+
default: slots.cell,
|
|
2634
|
+
editor: slots.editor,
|
|
2635
|
+
$stable: true
|
|
2636
|
+
}), "td")])] });
|
|
2637
|
+
})) : null;
|
|
2638
|
+
};
|
|
2639
|
+
return table.topRows.length || table.bottomRows.length ? h(Fragment, [
|
|
2640
|
+
region("top"),
|
|
2641
|
+
body,
|
|
2642
|
+
region("bottom")
|
|
2643
|
+
]) : body;
|
|
2644
|
+
};
|
|
1914
2645
|
const render = (binding) => {
|
|
1915
2646
|
if (binding && slots.default) {
|
|
1916
2647
|
const sentinel = loadSentinel(table, props.colspan ?? table.columns.length + (slots.rowHeader ? 1 : 0));
|
|
1917
2648
|
const content = slots.default({ rows: binding.rowItems.flatMap((item) => item.renderItem.kind === "row" ? [item.renderItem.row] : []) });
|
|
1918
|
-
return h(props.as, {
|
|
2649
|
+
return pinnedSections(h(props.as, {
|
|
2650
|
+
ref: element,
|
|
2651
|
+
"data-row-region": "centre"
|
|
2652
|
+
}, sentinel ? [...content, sentinel] : content), binding);
|
|
1919
2653
|
}
|
|
1920
|
-
if (binding) return h(props.as, {
|
|
1921
|
-
|
|
1922
|
-
|
|
2654
|
+
if (binding) return pinnedSections(h(props.as, {
|
|
2655
|
+
ref: element,
|
|
2656
|
+
"data-row-region": "centre"
|
|
2657
|
+
}, [
|
|
2658
|
+
...renderRows(binding, physicalColumnCount(binding, table.columns.length, columnOffset()), (item) => {
|
|
2659
|
+
if (item.renderItem.kind === "group") return groupRow(item.renderItem, slots, rowLayout?.aggregatePosition ?? "group", rowLayout?.footer(item.key));
|
|
1923
2660
|
if (item.renderItem.kind !== "row") return details.render(item.renderItem.row, item.renderItem.rowIndex);
|
|
1924
2661
|
const { row, rowIndex } = item.renderItem;
|
|
1925
2662
|
const columns = renderColumns(table.columns, binding, (column, columnIndex) => h(DataGridCell, {
|
|
@@ -1937,7 +2674,8 @@ const DataGridBody = defineComponent({
|
|
|
1937
2674
|
return h("tr", mergeProps(rowAttributes(props.rowAttrs, row), {
|
|
1938
2675
|
key: item.key,
|
|
1939
2676
|
role: "row",
|
|
1940
|
-
"aria-rowindex": table.pageStart + rowIndex + 1,
|
|
2677
|
+
"aria-rowindex": rowLayout?.index(row.key) ?? table.pageStart + rowIndex + 1,
|
|
2678
|
+
"aria-level": rowLayout?.level(row.key),
|
|
1941
2679
|
"data-key": String(row.key),
|
|
1942
2680
|
"data-dirty": flag(row.isDirty),
|
|
1943
2681
|
...hierarchyRowAttrs(table, row, hierarchy),
|
|
@@ -1948,15 +2686,17 @@ const DataGridBody = defineComponent({
|
|
|
1948
2686
|
index: rowIndex
|
|
1949
2687
|
}), ...columns]);
|
|
1950
2688
|
}),
|
|
2689
|
+
...table.bottomRows.length ? [rowSpacer(Math.max(0, binding.rows.viewportSize - binding.rows.totalSize), physicalColumnCount(binding, table.columns.length, columnOffset()), "pin-fill")] : [],
|
|
1951
2690
|
...details.retained(new Set(binding.rowItems.flatMap((item) => item.renderItem.kind === "detail" ? [item.renderItem.row.key] : []))),
|
|
1952
2691
|
...loadSentinel(table, props.colspan ?? table.columns.length + (slots.rowHeader ? 1 : 0)) ? [loadSentinel(table, props.colspan ?? table.columns.length + (slots.rowHeader ? 1 : 0))] : []
|
|
1953
|
-
]);
|
|
1954
|
-
const content = slots.default?.({ rows: table.rows }) ?? table.renderItems.map((item) => item.kind === "group" ?
|
|
2692
|
+
]), binding);
|
|
2693
|
+
const content = slots.default?.({ rows: table.rows }) ?? (rowLayout?.items ?? table.renderItems).map((item) => item.kind === "group" ? groupRow(item, slots, rowLayout?.aggregatePosition ?? "group", rowLayout?.footer(item.key)) : item.kind === "detail" ? details.render(item.row, item.rowIndex) : (() => {
|
|
1955
2694
|
const { row, rowIndex } = item;
|
|
1956
2695
|
return h("tr", mergeProps(rowAttributes(props.rowAttrs, row), {
|
|
1957
2696
|
key: item.key,
|
|
1958
2697
|
role: "row",
|
|
1959
|
-
"aria-rowindex": rowIndex + 2,
|
|
2698
|
+
"aria-rowindex": rowLayout?.index(row.key) ?? rowIndex + 2,
|
|
2699
|
+
"aria-level": rowLayout?.level(row.key),
|
|
1960
2700
|
"data-key": String(row.key),
|
|
1961
2701
|
"data-dirty": flag(row.isDirty),
|
|
1962
2702
|
...hierarchyRowAttrs(table, row, hierarchy)
|
|
@@ -1977,11 +2717,11 @@ const DataGridBody = defineComponent({
|
|
|
1977
2717
|
}))]);
|
|
1978
2718
|
})());
|
|
1979
2719
|
const sentinel = loadSentinel(table, props.colspan ?? table.columns.length + (slots.rowHeader ? 1 : 0));
|
|
1980
|
-
return h(props.as, [
|
|
2720
|
+
return pinnedSections(h(props.as, { "data-row-region": "centre" }, [
|
|
1981
2721
|
...content,
|
|
1982
2722
|
...slots.default ? [] : details.retained(new Set(table.renderItems.filter((item) => item.kind === "detail").map((item) => item.row.key))),
|
|
1983
2723
|
sentinel
|
|
1984
|
-
]);
|
|
2724
|
+
]));
|
|
1985
2725
|
};
|
|
1986
2726
|
return () => props.virtual && !virtual ? h(VirtualContent, {
|
|
1987
2727
|
table,
|
|
@@ -2022,12 +2762,14 @@ const DataGridCell = defineComponent({
|
|
|
2022
2762
|
const table = injectDataTable("<DataGridCell>");
|
|
2023
2763
|
const columnOffset = injectColumnOffset();
|
|
2024
2764
|
const { grid, context } = useGrid("<DataGridCell>");
|
|
2765
|
+
const layout = injectColumnLayout();
|
|
2766
|
+
const pin = injectPinnedRow();
|
|
2025
2767
|
const virtual = injectVirtual();
|
|
2026
2768
|
const hierarchy = injectHierarchy();
|
|
2027
2769
|
const element = ref();
|
|
2028
2770
|
const issueId = useEditorId();
|
|
2029
2771
|
const position = () => ({
|
|
2030
|
-
row: props.rowIndex ?? table.
|
|
2772
|
+
row: props.rowIndex ?? table.gridRows.indexOf(props.row),
|
|
2031
2773
|
column: props.columnIndex ?? table.columns.indexOf(props.column)
|
|
2032
2774
|
});
|
|
2033
2775
|
watch(() => grid.isFocused(position()), (focused) => {
|
|
@@ -2110,6 +2852,8 @@ const DataGridCell = defineComponent({
|
|
|
2110
2852
|
"data-dirty": flag(row.isDirty),
|
|
2111
2853
|
...issueAttrs(issueId, issues, pending),
|
|
2112
2854
|
style: columnStyle(column),
|
|
2855
|
+
...layout?.attrs(column),
|
|
2856
|
+
...pin ? mergeProps(layout?.attrs(column) ?? {}, pin.attrs(!!column.pinned)) : {},
|
|
2113
2857
|
onMousedown: (event) => {
|
|
2114
2858
|
if (editing || event.button !== 0) return;
|
|
2115
2859
|
grid.focusCell(at, { extend: event.shiftKey });
|
|
@@ -2128,5 +2872,5 @@ const DataGridCell = defineComponent({
|
|
|
2128
2872
|
});
|
|
2129
2873
|
|
|
2130
2874
|
//#endregion
|
|
2131
|
-
export { DataCellEditor, DataGridBody, DataGridCell, DataGridRoot, DataTableBody, DataTableCaption, DataTableCell, DataTableColumnVisibility, DataTableDetailRow, DataTableEditCell, DataTableEditRoot, DataTableEmpty, DataTableExpandToggle, DataTableHeader, DataTableHeaderCell, DataTableHeaderRow, DataTableLoadMore, DataTablePageSize, DataTablePagination, DataTableRoot, DataTableRow, DataTableRowActions, DataTableSearch, DataTableSelectAll, DataTableSelectRow, DataTableSortButton, DataTableStatus, DataTableTreeCell, DataTableViewport, DataTableVirtualColumns, cellEditorProps, cellId, columnStyle, expandToggleProps, hierarchyProps, injectVirtual as injectVirtualRenderer, resolveTreeColumn, rowAttributes, treeCellProps, virtualProps };
|
|
2875
|
+
export { DataCellEditor, DataGridBody, DataGridCell, DataGridRoot, DataTableAggregateCell, DataTableBody, DataTableCaption, DataTableCell, DataTableColumnResizer, DataTableColumnVisibility, DataTableDetailRow, DataTableEditCell, DataTableEditRoot, DataTableEmpty, DataTableExpandToggle, DataTableGroupRow, DataTableHeader, DataTableHeaderCell, DataTableHeaderRow, DataTableLeadingCell, DataTableLoadMore, DataTablePageSize, DataTablePagination, DataTablePinnedRow, DataTableRoot, DataTableRow, DataTableRowActions, DataTableSearch, DataTableSelectAll, DataTableSelectRow, DataTableSortButton, DataTableStatus, DataTableTreeCell, DataTableViewport, DataTableVirtualColumns, cellEditorProps, cellId, columnStyle, expandToggleProps, groupingProps, hierarchyProps, injectVirtual as injectVirtualRenderer, resolveTreeColumn, rowAttributes, treeCellProps, virtualProps };
|
|
2132
2876
|
//# sourceMappingURL=index.js.map
|