@svgrid/grid 3.0.0 → 3.0.2
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/CHANGELOG.md +116 -88
- package/README.md +199 -199
- package/dist/FlexRender.svelte +96 -96
- package/dist/GridFooter.svelte +190 -181
- package/dist/GridFooter.svelte.d.ts +8 -0
- package/dist/GridMenus.svelte +18 -10
- package/dist/GridMenus.svelte.d.ts +2 -1
- package/dist/SvAutoComplete.svelte +169 -169
- package/dist/SvAvatar.svelte +75 -75
- package/dist/SvCalendar.svelte +503 -503
- package/dist/SvCarousel.svelte +141 -141
- package/dist/SvCheckBox.svelte +102 -102
- package/dist/SvCircularProgress.svelte +109 -109
- package/dist/SvColorInput.svelte +181 -181
- package/dist/SvComboBox.svelte +279 -279
- package/dist/SvContextMenu.svelte +116 -116
- package/dist/SvCountryInput.svelte +163 -163
- package/dist/SvDrawer.svelte +254 -254
- package/dist/SvDropDownList.svelte +378 -378
- package/dist/SvDurationInput.svelte +126 -126
- package/dist/SvField.svelte +293 -293
- package/dist/SvForm.svelte +437 -437
- package/dist/SvGrid.controller.svelte.d.ts +17 -0
- package/dist/SvGrid.controller.svelte.js +128 -14
- package/dist/SvGrid.css +79 -10
- package/dist/SvGrid.svelte +191 -186
- package/dist/SvGrid.types.d.ts +42 -1
- package/dist/SvGridCellEditor.svelte +748 -744
- package/dist/SvGridChart.svelte +2246 -1716
- package/dist/SvGridChart.svelte.d.ts +63 -1
- package/dist/SvGridChartPanel.svelte +633 -485
- package/dist/SvGridChartView.svelte +79 -70
- package/dist/SvGridChartView.svelte.d.ts +7 -0
- package/dist/SvGridDropdown.svelte +728 -728
- package/dist/SvGridSelect.svelte +270 -270
- package/dist/SvGroupCell.svelte +141 -116
- package/dist/SvGroupCell.svelte.d.ts +8 -0
- package/dist/SvListBox.svelte +334 -334
- package/dist/SvMaskedInput.svelte +122 -122
- package/dist/SvMenu.svelte +124 -124
- package/dist/SvMenuList.svelte +146 -146
- package/dist/SvMultiSelect.svelte +293 -293
- package/dist/SvNumberInput.svelte +172 -172
- package/dist/SvOtpInput.svelte +158 -158
- package/dist/SvPasswordInput.svelte +151 -151
- package/dist/SvPhoneInput.svelte +133 -133
- package/dist/SvPopover.svelte +197 -197
- package/dist/SvProgress.svelte +116 -116
- package/dist/SvRadioGroup.svelte +107 -107
- package/dist/SvRating.svelte +112 -112
- package/dist/SvResult.svelte +73 -73
- package/dist/SvRichText.svelte +211 -211
- package/dist/SvRowGroupPanel.svelte +186 -170
- package/dist/SvRowGroupPanel.svelte.d.ts +8 -0
- package/dist/SvScrollArea.svelte +61 -61
- package/dist/SvSlider.svelte +203 -203
- package/dist/SvSwitchButton.svelte +108 -108
- package/dist/SvTagsInput.svelte +115 -115
- package/dist/SvTextInput.svelte +147 -147
- package/dist/SvTimePicker.svelte +245 -245
- package/dist/SvToaster.svelte +159 -159
- package/dist/SvToggleButton.svelte +85 -85
- package/dist/SvTooltip.svelte +161 -161
- package/dist/SvTour.svelte +208 -208
- package/dist/SvTree.svelte +444 -444
- package/dist/SvTreeSelect.svelte +239 -239
- package/dist/ai.d.ts +11 -2
- package/dist/ai.js +51 -7
- package/dist/cdn/GridMenus-DyFA-QxA.js +602 -0
- package/dist/cdn/GridMenus-M2XP9t0_.js +603 -0
- package/dist/cdn/{SvDateRangeInput-DflbiP7N.js → SvDateRangeInput-CaOuMs8O.js} +1 -1
- package/dist/cdn/{SvDateRangeInput-Bh0A0JkF.js → SvDateRangeInput-DMLKmGEc.js} +1 -1
- package/dist/cdn/{SvDateTimePicker-Bivn8dAP.js → SvDateTimePicker-CCbDZNZB.js} +1 -1
- package/dist/cdn/{SvDateTimePicker-BWwpfB_o.js → SvDateTimePicker-sonaH0oh.js} +1 -1
- package/dist/cdn/{SvGridCellEditor-Ba7rY3eu.js → SvGridCellEditor-BWnTi2N7.js} +2 -2
- package/dist/cdn/{SvGridCellEditor-AXL8cHGO.js → SvGridCellEditor-CjEJMJKc.js} +2 -2
- package/dist/cdn/SvGridChart-DAb9RbRs.js +1480 -0
- package/dist/cdn/SvGridChart-Yl-IXZFO.js +1481 -0
- package/dist/cdn/SvGridChartPanel-DayQpDsR.js +834 -0
- package/dist/cdn/SvGridChartPanel-aqf8n-vJ.js +810 -0
- package/dist/cdn/{SvGridChartView-eSPuJE6g.js → SvGridChartView-CxfakxR0.js} +5 -3
- package/dist/cdn/{SvGridChartView-SmPW10dI.js → SvGridChartView-Dm_YEx9L.js} +5 -3
- package/dist/cdn/{SvGridDropdown-B1ZcLpgs.js → SvGridDropdown-D0VdjeR8.js} +1 -1
- package/dist/cdn/{SvGridDropdown-CtdbHcIS.js → SvGridDropdown-D13MtJ2j.js} +1 -1
- package/dist/cdn/cell-formatting-C2Hf5gqd.js +86 -0
- package/dist/cdn/chart-CKJRCPOk.js +1652 -0
- package/dist/cdn/{date-format-DZT7T1wf.js → date-format-BNii4zeD.js} +2 -2
- package/dist/cdn/{date-format-CcP1tafP.js → date-format-BnnHlqGw.js} +2 -2
- package/dist/cdn/{export-format-Cv1Dll6k.js → export-format-CUDLy2yn.js} +84 -168
- package/dist/cdn/{src-B_YS5AOc.js → src-BJ2opd0j.js} +3642 -3450
- package/dist/cdn/{src-DYXXpuSk.js → src-DNbz94Ct.js} +8649 -8457
- package/dist/cdn/svgrid.js +16 -15
- package/dist/cdn/svgrid.svelte-external.js +16 -15
- package/dist/cell-formatting.d.ts +7 -0
- package/dist/cell-formatting.js +7 -1
- package/dist/chart-export.d.ts +23 -2
- package/dist/chart-export.js +88 -14
- package/dist/chart.d.ts +410 -18
- package/dist/chart.js +824 -24
- package/dist/editing.js +22 -13
- package/dist/grid-icons.d.ts +49 -0
- package/dist/grid-icons.js +86 -0
- package/dist/index.d.ts +3 -2
- package/dist/index.js +3 -2
- package/package.json +1 -1
- package/src/FlexRender.svelte +96 -96
- package/src/GridFooter.svelte +190 -181
- package/src/GridMenus.svelte +18 -10
- package/src/SvAutoComplete.svelte +169 -169
- package/src/SvAvatar.svelte +75 -75
- package/src/SvCalendar.svelte +503 -503
- package/src/SvCalendar.test.ts +226 -226
- package/src/SvCarousel.svelte +141 -141
- package/src/SvCheckBox.svelte +102 -102
- package/src/SvCircularProgress.svelte +109 -109
- package/src/SvColorInput.svelte +181 -181
- package/src/SvComboBox.svelte +279 -279
- package/src/SvContextMenu.svelte +116 -116
- package/src/SvCountryInput.svelte +163 -163
- package/src/SvDrawer.svelte +254 -254
- package/src/SvDropDownList.svelte +378 -378
- package/src/SvDurationInput.svelte +126 -126
- package/src/SvField.svelte +293 -293
- package/src/SvForm.svelte +437 -437
- package/src/SvForm.test.ts +411 -411
- package/src/SvGrid.controller.svelte.ts +146 -13
- package/src/SvGrid.css +79 -10
- package/src/SvGrid.svelte +191 -186
- package/src/SvGrid.types.ts +2133 -2092
- package/src/SvGridCellEditor.svelte +748 -744
- package/src/SvGridChart.svelte +2246 -1716
- package/src/SvGridChart.test.ts +243 -1
- package/src/SvGridChartPanel.svelte +633 -485
- package/src/SvGridChartView.svelte +79 -70
- package/src/SvGridDropdown.svelte +728 -728
- package/src/SvGridSelect.svelte +270 -270
- package/src/SvGroupCell.svelte +141 -116
- package/src/SvListBox.svelte +334 -334
- package/src/SvMaskedInput.svelte +122 -122
- package/src/SvMenu.svelte +124 -124
- package/src/SvMenu.test.ts +97 -97
- package/src/SvMenuList.svelte +146 -146
- package/src/SvMultiSelect.svelte +293 -293
- package/src/SvNumberInput.svelte +172 -172
- package/src/SvOtpInput.svelte +158 -158
- package/src/SvPasswordInput.svelte +151 -151
- package/src/SvPhoneInput.svelte +133 -133
- package/src/SvPopover.svelte +197 -197
- package/src/SvProgress.svelte +116 -116
- package/src/SvRadioGroup.svelte +107 -107
- package/src/SvRating.svelte +112 -112
- package/src/SvResult.svelte +73 -73
- package/src/SvRichText.svelte +211 -211
- package/src/SvRowGroupPanel.svelte +186 -170
- package/src/SvScrollArea.svelte +61 -61
- package/src/SvSlider.svelte +203 -203
- package/src/SvSwitchButton.svelte +108 -108
- package/src/SvTagsInput.svelte +115 -115
- package/src/SvTextInput.svelte +147 -147
- package/src/SvTimePicker.svelte +245 -245
- package/src/SvToaster.svelte +159 -159
- package/src/SvToaster.test.ts +95 -95
- package/src/SvToggleButton.svelte +85 -85
- package/src/SvTooltip.svelte +161 -161
- package/src/SvTour.svelte +208 -208
- package/src/SvTree.svelte +444 -444
- package/src/SvTreeSelect.svelte +239 -239
- package/src/a11y/dismissable.test.ts +119 -119
- package/src/a11y/dismissable.ts +114 -114
- package/src/a11y.contract.test.ts +49 -49
- package/src/a11y.test.ts +59 -59
- package/src/a11y.ts +61 -61
- package/src/ai.test.ts +561 -502
- package/src/ai.ts +1472 -1419
- package/src/build-api.coverage.test.ts +633 -633
- package/src/build-api.ts +846 -846
- package/src/builtin-editors.grid.test.ts +83 -83
- package/src/cell-formatting.ts +177 -171
- package/src/cell-render.test.ts +513 -513
- package/src/cell-render.ts +496 -496
- package/src/cell-values.ts +148 -148
- package/src/chart-export.test.ts +112 -0
- package/src/chart-export.ts +270 -202
- package/src/chart-view.svelte.ts +36 -36
- package/src/chart.test.ts +830 -1
- package/src/chart.ts +3342 -2321
- package/src/collaboration.test.ts +104 -104
- package/src/collaboration.ts +167 -167
- package/src/column-groups.ts +78 -78
- package/src/core.performance.test.ts +30 -30
- package/src/core.ts +1865 -1865
- package/src/createAutocomplete.svelte.ts +132 -132
- package/src/createCombobox.svelte.ts +191 -191
- package/src/createCountryInput.svelte.ts +157 -157
- package/src/createDropdownList.svelte.ts +168 -168
- package/src/createForm.svelte.ts +386 -386
- package/src/createGrid.svelte.ts +42 -42
- package/src/createGrid.test.ts +10 -10
- package/src/createGridState.svelte.ts +17 -17
- package/src/createListbox.svelte.ts +250 -250
- package/src/createMenu.svelte.ts +224 -224
- package/src/createPopoverSelect.svelte.ts +213 -213
- package/src/createSlider.svelte.ts +191 -191
- package/src/createTooltip.svelte.ts +144 -144
- package/src/createTree.svelte.ts +322 -322
- package/src/datetime/date-core.ts +206 -206
- package/src/datetime/date-restrict.ts +61 -61
- package/src/datetime/timezone.ts +135 -135
- package/src/dock-manager-model.ts +596 -596
- package/src/dock-model.ts +374 -374
- package/src/editing.test.ts +974 -974
- package/src/editing.ts +618 -609
- package/src/editor-contract.ts +171 -171
- package/src/editor-registry.grid.test.ts +144 -144
- package/src/editor-registry.ts +122 -122
- package/src/export-data-api.test.ts +126 -126
- package/src/export-format.test.ts +107 -107
- package/src/export-format.ts +601 -601
- package/src/filter-operators.ts +160 -160
- package/src/filtering/excel-filters.ts +325 -325
- package/src/flex-render.ts +3 -3
- package/src/form-field.ts +127 -127
- package/src/grid-icons.test.ts +46 -0
- package/src/grid-icons.ts +184 -0
- package/src/group-display.test.ts +167 -167
- package/src/group-display.ts +200 -200
- package/src/headless.ts +87 -87
- package/src/icon-overrides.grid.test.ts +188 -0
- package/src/icon-seam.test.ts +100 -0
- package/src/index.ts +19 -0
- package/src/js-scroller.svelte.ts +173 -173
- package/src/keyboard-handlers.ts +270 -270
- package/src/keyboard.test.ts +59 -59
- package/src/keyboard.ts +97 -97
- package/src/list-nav.test.ts +49 -49
- package/src/list-nav.ts +29 -29
- package/src/list-option.test.ts +56 -56
- package/src/list-option.ts +179 -179
- package/src/menus.ts +597 -597
- package/src/merge-objects.ts +48 -48
- package/src/overlays.test.ts +90 -90
- package/src/positioning.ts +268 -268
- package/src/render-component.ts +28 -28
- package/src/row-drag.test.ts +401 -401
- package/src/row-drag.ts +419 -419
- package/src/row-resize.test.ts +524 -524
- package/src/row-resize.ts +228 -228
- package/src/scheduler-ical.ts +181 -181
- package/src/scheduler-model.test.ts +562 -562
- package/src/scheduler-model.ts +873 -873
- package/src/selection.test.ts +885 -885
- package/src/server-data-source.test.ts +383 -383
- package/src/server-data-source.ts +469 -469
- package/src/sparkline.test.ts +68 -68
- package/src/sparkline.ts +169 -169
- package/src/spreadsheet.test.ts +488 -488
- package/src/spreadsheet.ts +312 -312
- package/src/static-functions.ts +11 -11
- package/src/subscribe.ts +38 -38
- package/src/summaries.ts +113 -113
- package/src/svgrid-wrapper.types.ts +563 -563
- package/src/svgrid.async-editor-options.test.ts +273 -273
- package/src/svgrid.auto-row-height.test.ts +204 -204
- package/src/svgrid.behavior.test.ts +910 -910
- package/src/svgrid.charting.test.ts +654 -534
- package/src/svgrid.comments-autocomplete.test.ts +127 -127
- package/src/svgrid.context-menu.test.ts +147 -147
- package/src/svgrid.features.test.ts +157 -157
- package/src/svgrid.filter-depth.test.ts +163 -163
- package/src/svgrid.filter-menu-listbox.svelte.test.ts +382 -377
- package/src/svgrid.filter-menu-scroll.test.ts +112 -112
- package/src/svgrid.grand-total.test.ts +188 -188
- package/src/svgrid.group-display-mode.test.ts +171 -171
- package/src/svgrid.group-footers.test.ts +121 -121
- package/src/svgrid.group-pagination.test.ts +153 -153
- package/src/svgrid.new-features.wrapper.test.ts +251 -251
- package/src/svgrid.tree-data.test.ts +186 -186
- package/src/svgrid.wrapper.test.ts +63 -63
- package/src/svgriddropdown.async-panel.svelte.test.ts +195 -195
- package/src/test-setup.ts +62 -62
- package/src/themes/index.ts +288 -288
- package/src/toast-store.svelte.ts +250 -250
- package/src/toast-store.test.ts +147 -147
- package/src/tree-row-model.test.ts +168 -168
- package/src/ui-buttons.test.ts +144 -144
- package/src/ui-inputs.test.ts +118 -118
- package/src/ui-localization.test.ts +113 -113
- package/src/ui-range.test.ts +70 -70
- package/src/ui-selection.test.ts +155 -155
- package/src/ui-tier1.test.ts +142 -142
- package/src/virtual.test.ts +88 -88
- package/src/virtualization/column-virtualizer.test.ts +27 -27
- package/src/virtualization/column-virtualizer.ts +30 -30
- package/src/virtualization/svelte-virtualizer.svelte.ts +26 -26
- package/src/virtualization/types.ts +30 -30
- package/src/virtualization/virtualizer.test.ts +47 -47
- package/src/virtualization/virtualizer.ts +322 -322
- package/dist/cdn/GridMenus-DMihUtma.js +0 -600
- package/dist/cdn/GridMenus-nmNDj1a3.js +0 -601
- package/dist/cdn/SvGridChart-Bs2GIR2Q.js +0 -1202
- package/dist/cdn/SvGridChart-CwhFz7GV.js +0 -1203
- package/dist/cdn/SvGridChartPanel-1WXuStzM.js +0 -561
- package/dist/cdn/SvGridChartPanel-e5_nqNP9.js +0 -585
- package/dist/cdn/chart-i4XcXyHJ.js +0 -1214
|
@@ -1,153 +1,153 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* DOM: with grouping on, `pageSize` budgets DATA rows, not group banners (#73).
|
|
3
|
-
*
|
|
4
|
-
* The row model hands the view one flat list with group banners interleaved
|
|
5
|
-
* between their children. Slicing that list by `pageSize` spent the budget on
|
|
6
|
-
* banners: ten groups of two at `pageSize: 10` showed roughly three data rows,
|
|
7
|
-
* and with enough small groups a page could show almost none.
|
|
8
|
-
*
|
|
9
|
-
* Now the page window is measured in data rows, and each page reprints the
|
|
10
|
-
* banners its rows sit under - so a group split across a page boundary is
|
|
11
|
-
* labelled on both pages.
|
|
12
|
-
*/
|
|
13
|
-
import { afterEach, describe, expect, it } from 'vitest'
|
|
14
|
-
import { mount, unmount } from 'svelte'
|
|
15
|
-
import SvGrid from './SvGrid.svelte'
|
|
16
|
-
import {
|
|
17
|
-
createCoreRowModel,
|
|
18
|
-
createExpandedRowModel,
|
|
19
|
-
createFilteredRowModel,
|
|
20
|
-
createGroupedRowModel,
|
|
21
|
-
createPaginatedRowModel,
|
|
22
|
-
createSortedRowModel,
|
|
23
|
-
sortFns,
|
|
24
|
-
tableFeatures,
|
|
25
|
-
rowSortingFeature,
|
|
26
|
-
columnGroupingFeature,
|
|
27
|
-
} from './index'
|
|
28
|
-
|
|
29
|
-
type Row = { id: number; region: string; amount: number }
|
|
30
|
-
|
|
31
|
-
// Ten groups of two rows - the shape from the report.
|
|
32
|
-
const data: Row[] = []
|
|
33
|
-
for (let g = 0; g < 10; g += 1) {
|
|
34
|
-
data.push({ id: g * 2, region: `R${g}`, amount: 1 })
|
|
35
|
-
data.push({ id: g * 2 + 1, region: `R${g}`, amount: 2 })
|
|
36
|
-
}
|
|
37
|
-
|
|
38
|
-
const columns = [
|
|
39
|
-
{ field: 'region', header: 'Region', width: 120 },
|
|
40
|
-
{ field: 'amount', header: 'Amount', width: 100 },
|
|
41
|
-
]
|
|
42
|
-
|
|
43
|
-
const features = tableFeatures({ rowSortingFeature, columnGroupingFeature })
|
|
44
|
-
const tick = () => new Promise<void>((r) => queueMicrotask(r))
|
|
45
|
-
|
|
46
|
-
function mountGrid(pageSize: number, groupFooters = false) {
|
|
47
|
-
const target = document.createElement('div')
|
|
48
|
-
document.body.appendChild(target)
|
|
49
|
-
// Grouping state starts empty and is driven through the api - there is no
|
|
50
|
-
// initial-grouping prop - so group by region as soon as the api lands.
|
|
51
|
-
let api: { setGroupBy: (ids: string[]) => void } | null = null
|
|
52
|
-
const app = mount(SvGrid, {
|
|
53
|
-
target,
|
|
54
|
-
props: {
|
|
55
|
-
data,
|
|
56
|
-
columns,
|
|
57
|
-
features,
|
|
58
|
-
groupable: true,
|
|
59
|
-
groupFooters,
|
|
60
|
-
onApiReady: (a: never) => { api = a as never },
|
|
61
|
-
pageable: true,
|
|
62
|
-
pageSize,
|
|
63
|
-
_rowModels: {
|
|
64
|
-
coreRowModel: createCoreRowModel(),
|
|
65
|
-
filteredRowModel: createFilteredRowModel(),
|
|
66
|
-
sortedRowModel: createSortedRowModel(sortFns),
|
|
67
|
-
groupedRowModel: createGroupedRowModel(),
|
|
68
|
-
expandedRowModel: createExpandedRowModel(),
|
|
69
|
-
paginatedRowModel: createPaginatedRowModel(),
|
|
70
|
-
},
|
|
71
|
-
containerHeight: 900,
|
|
72
|
-
virtualization: false,
|
|
73
|
-
} as never,
|
|
74
|
-
})
|
|
75
|
-
return {
|
|
76
|
-
target,
|
|
77
|
-
groupByRegion: () => api?.setGroupBy(['region']),
|
|
78
|
-
/** Groups render collapsed by default; click every banner to open them. */
|
|
79
|
-
expandAll: () => {
|
|
80
|
-
for (const btn of target.querySelectorAll<HTMLButtonElement>('.sv-grid-group-toggle')) {
|
|
81
|
-
if (btn.getAttribute('aria-expanded') !== 'true') btn.click()
|
|
82
|
-
}
|
|
83
|
-
},
|
|
84
|
-
destroy: () => { unmount(app); target.remove() },
|
|
85
|
-
}
|
|
86
|
-
}
|
|
87
|
-
|
|
88
|
-
let cleanup: (() => void) | null = null
|
|
89
|
-
afterEach(() => { cleanup?.(); cleanup = null })
|
|
90
|
-
|
|
91
|
-
const dataRows = (t: HTMLElement) =>
|
|
92
|
-
[...t.querySelectorAll('tbody tr.sv-grid-row')].filter(
|
|
93
|
-
(r) => !r.classList.contains('sv-grid-group-row') && !r.classList.contains('sv-grid-row-spacer'),
|
|
94
|
-
)
|
|
95
|
-
const groupRows = (t: HTMLElement) => [...t.querySelectorAll('tbody tr.sv-grid-group-row')]
|
|
96
|
-
|
|
97
|
-
async function grouped(pageSize: number, expand = true, groupFooters = false) {
|
|
98
|
-
const g = mountGrid(pageSize, groupFooters)
|
|
99
|
-
cleanup = g.destroy
|
|
100
|
-
await tick()
|
|
101
|
-
g.groupByRegion()
|
|
102
|
-
await tick()
|
|
103
|
-
if (expand) {
|
|
104
|
-
g.expandAll()
|
|
105
|
-
await tick()
|
|
106
|
-
}
|
|
107
|
-
return g
|
|
108
|
-
}
|
|
109
|
-
|
|
110
|
-
describe('grouped pagination (#73)', () => {
|
|
111
|
-
it('fills the page with pageSize DATA rows, not banners', async () => {
|
|
112
|
-
const { target } = await grouped(10)
|
|
113
|
-
// Before the fix the flat slice returned 10 TOTAL rows - banners included -
|
|
114
|
-
// so only a handful of them were data.
|
|
115
|
-
expect(dataRows(target)).toHaveLength(10)
|
|
116
|
-
// Those 10 data rows span 5 groups, so 5 banners come along for free.
|
|
117
|
-
expect(groupRows(target)).toHaveLength(5)
|
|
118
|
-
})
|
|
119
|
-
|
|
120
|
-
it('reports the data-row count in the pager, not banners + data', async () => {
|
|
121
|
-
const { target } = await grouped(10)
|
|
122
|
-
// 20 data rows at pageSize 10 = 2 pages. Counting banners would say 30.
|
|
123
|
-
expect(target.textContent).toMatch(/of\s+20\b/)
|
|
124
|
-
})
|
|
125
|
-
|
|
126
|
-
it('reprints the banner for a group straddling a page boundary', async () => {
|
|
127
|
-
const { target } = await grouped(3)
|
|
128
|
-
// Page 0 holds R0's two rows plus R1's first, so both banners show.
|
|
129
|
-
const labels = groupRows(target).map((r) => r.textContent ?? '')
|
|
130
|
-
expect(labels.some((t) => t.includes('R0'))).toBe(true)
|
|
131
|
-
expect(labels.some((t) => t.includes('R1'))).toBe(true)
|
|
132
|
-
expect(dataRows(target)).toHaveLength(3)
|
|
133
|
-
})
|
|
134
|
-
|
|
135
|
-
it('does not spend page budget on group footers', async () => {
|
|
136
|
-
// Footers are inserted after paging, so turning them on must not push data
|
|
137
|
-
// rows onto the next page.
|
|
138
|
-
const { target } = await grouped(10, true, true)
|
|
139
|
-
expect(dataRows(target).filter((r) => !r.classList.contains('sv-grid-group-footer-row')))
|
|
140
|
-
.toHaveLength(10)
|
|
141
|
-
expect(target.textContent).toMatch(/of\s+20\b/)
|
|
142
|
-
})
|
|
143
|
-
|
|
144
|
-
it('still fills a page when every group is collapsed', async () => {
|
|
145
|
-
// Collapsed groups are the visible unit. Treating them as free headers
|
|
146
|
-
// emptied the page entirely - caught here, not by the pure helper.
|
|
147
|
-
const { target } = await grouped(4, false)
|
|
148
|
-
expect(groupRows(target)).toHaveLength(4)
|
|
149
|
-
expect(dataRows(target)).toHaveLength(0)
|
|
150
|
-
// 10 collapsed groups over pageSize 4.
|
|
151
|
-
expect(target.textContent).toMatch(/of\s+10\b/)
|
|
152
|
-
})
|
|
153
|
-
})
|
|
1
|
+
/**
|
|
2
|
+
* DOM: with grouping on, `pageSize` budgets DATA rows, not group banners (#73).
|
|
3
|
+
*
|
|
4
|
+
* The row model hands the view one flat list with group banners interleaved
|
|
5
|
+
* between their children. Slicing that list by `pageSize` spent the budget on
|
|
6
|
+
* banners: ten groups of two at `pageSize: 10` showed roughly three data rows,
|
|
7
|
+
* and with enough small groups a page could show almost none.
|
|
8
|
+
*
|
|
9
|
+
* Now the page window is measured in data rows, and each page reprints the
|
|
10
|
+
* banners its rows sit under - so a group split across a page boundary is
|
|
11
|
+
* labelled on both pages.
|
|
12
|
+
*/
|
|
13
|
+
import { afterEach, describe, expect, it } from 'vitest'
|
|
14
|
+
import { mount, unmount } from 'svelte'
|
|
15
|
+
import SvGrid from './SvGrid.svelte'
|
|
16
|
+
import {
|
|
17
|
+
createCoreRowModel,
|
|
18
|
+
createExpandedRowModel,
|
|
19
|
+
createFilteredRowModel,
|
|
20
|
+
createGroupedRowModel,
|
|
21
|
+
createPaginatedRowModel,
|
|
22
|
+
createSortedRowModel,
|
|
23
|
+
sortFns,
|
|
24
|
+
tableFeatures,
|
|
25
|
+
rowSortingFeature,
|
|
26
|
+
columnGroupingFeature,
|
|
27
|
+
} from './index'
|
|
28
|
+
|
|
29
|
+
type Row = { id: number; region: string; amount: number }
|
|
30
|
+
|
|
31
|
+
// Ten groups of two rows - the shape from the report.
|
|
32
|
+
const data: Row[] = []
|
|
33
|
+
for (let g = 0; g < 10; g += 1) {
|
|
34
|
+
data.push({ id: g * 2, region: `R${g}`, amount: 1 })
|
|
35
|
+
data.push({ id: g * 2 + 1, region: `R${g}`, amount: 2 })
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
const columns = [
|
|
39
|
+
{ field: 'region', header: 'Region', width: 120 },
|
|
40
|
+
{ field: 'amount', header: 'Amount', width: 100 },
|
|
41
|
+
]
|
|
42
|
+
|
|
43
|
+
const features = tableFeatures({ rowSortingFeature, columnGroupingFeature })
|
|
44
|
+
const tick = () => new Promise<void>((r) => queueMicrotask(r))
|
|
45
|
+
|
|
46
|
+
function mountGrid(pageSize: number, groupFooters = false) {
|
|
47
|
+
const target = document.createElement('div')
|
|
48
|
+
document.body.appendChild(target)
|
|
49
|
+
// Grouping state starts empty and is driven through the api - there is no
|
|
50
|
+
// initial-grouping prop - so group by region as soon as the api lands.
|
|
51
|
+
let api: { setGroupBy: (ids: string[]) => void } | null = null
|
|
52
|
+
const app = mount(SvGrid, {
|
|
53
|
+
target,
|
|
54
|
+
props: {
|
|
55
|
+
data,
|
|
56
|
+
columns,
|
|
57
|
+
features,
|
|
58
|
+
groupable: true,
|
|
59
|
+
groupFooters,
|
|
60
|
+
onApiReady: (a: never) => { api = a as never },
|
|
61
|
+
pageable: true,
|
|
62
|
+
pageSize,
|
|
63
|
+
_rowModels: {
|
|
64
|
+
coreRowModel: createCoreRowModel(),
|
|
65
|
+
filteredRowModel: createFilteredRowModel(),
|
|
66
|
+
sortedRowModel: createSortedRowModel(sortFns),
|
|
67
|
+
groupedRowModel: createGroupedRowModel(),
|
|
68
|
+
expandedRowModel: createExpandedRowModel(),
|
|
69
|
+
paginatedRowModel: createPaginatedRowModel(),
|
|
70
|
+
},
|
|
71
|
+
containerHeight: 900,
|
|
72
|
+
virtualization: false,
|
|
73
|
+
} as never,
|
|
74
|
+
})
|
|
75
|
+
return {
|
|
76
|
+
target,
|
|
77
|
+
groupByRegion: () => api?.setGroupBy(['region']),
|
|
78
|
+
/** Groups render collapsed by default; click every banner to open them. */
|
|
79
|
+
expandAll: () => {
|
|
80
|
+
for (const btn of target.querySelectorAll<HTMLButtonElement>('.sv-grid-group-toggle')) {
|
|
81
|
+
if (btn.getAttribute('aria-expanded') !== 'true') btn.click()
|
|
82
|
+
}
|
|
83
|
+
},
|
|
84
|
+
destroy: () => { unmount(app); target.remove() },
|
|
85
|
+
}
|
|
86
|
+
}
|
|
87
|
+
|
|
88
|
+
let cleanup: (() => void) | null = null
|
|
89
|
+
afterEach(() => { cleanup?.(); cleanup = null })
|
|
90
|
+
|
|
91
|
+
const dataRows = (t: HTMLElement) =>
|
|
92
|
+
[...t.querySelectorAll('tbody tr.sv-grid-row')].filter(
|
|
93
|
+
(r) => !r.classList.contains('sv-grid-group-row') && !r.classList.contains('sv-grid-row-spacer'),
|
|
94
|
+
)
|
|
95
|
+
const groupRows = (t: HTMLElement) => [...t.querySelectorAll('tbody tr.sv-grid-group-row')]
|
|
96
|
+
|
|
97
|
+
async function grouped(pageSize: number, expand = true, groupFooters = false) {
|
|
98
|
+
const g = mountGrid(pageSize, groupFooters)
|
|
99
|
+
cleanup = g.destroy
|
|
100
|
+
await tick()
|
|
101
|
+
g.groupByRegion()
|
|
102
|
+
await tick()
|
|
103
|
+
if (expand) {
|
|
104
|
+
g.expandAll()
|
|
105
|
+
await tick()
|
|
106
|
+
}
|
|
107
|
+
return g
|
|
108
|
+
}
|
|
109
|
+
|
|
110
|
+
describe('grouped pagination (#73)', () => {
|
|
111
|
+
it('fills the page with pageSize DATA rows, not banners', async () => {
|
|
112
|
+
const { target } = await grouped(10)
|
|
113
|
+
// Before the fix the flat slice returned 10 TOTAL rows - banners included -
|
|
114
|
+
// so only a handful of them were data.
|
|
115
|
+
expect(dataRows(target)).toHaveLength(10)
|
|
116
|
+
// Those 10 data rows span 5 groups, so 5 banners come along for free.
|
|
117
|
+
expect(groupRows(target)).toHaveLength(5)
|
|
118
|
+
})
|
|
119
|
+
|
|
120
|
+
it('reports the data-row count in the pager, not banners + data', async () => {
|
|
121
|
+
const { target } = await grouped(10)
|
|
122
|
+
// 20 data rows at pageSize 10 = 2 pages. Counting banners would say 30.
|
|
123
|
+
expect(target.textContent).toMatch(/of\s+20\b/)
|
|
124
|
+
})
|
|
125
|
+
|
|
126
|
+
it('reprints the banner for a group straddling a page boundary', async () => {
|
|
127
|
+
const { target } = await grouped(3)
|
|
128
|
+
// Page 0 holds R0's two rows plus R1's first, so both banners show.
|
|
129
|
+
const labels = groupRows(target).map((r) => r.textContent ?? '')
|
|
130
|
+
expect(labels.some((t) => t.includes('R0'))).toBe(true)
|
|
131
|
+
expect(labels.some((t) => t.includes('R1'))).toBe(true)
|
|
132
|
+
expect(dataRows(target)).toHaveLength(3)
|
|
133
|
+
})
|
|
134
|
+
|
|
135
|
+
it('does not spend page budget on group footers', async () => {
|
|
136
|
+
// Footers are inserted after paging, so turning them on must not push data
|
|
137
|
+
// rows onto the next page.
|
|
138
|
+
const { target } = await grouped(10, true, true)
|
|
139
|
+
expect(dataRows(target).filter((r) => !r.classList.contains('sv-grid-group-footer-row')))
|
|
140
|
+
.toHaveLength(10)
|
|
141
|
+
expect(target.textContent).toMatch(/of\s+20\b/)
|
|
142
|
+
})
|
|
143
|
+
|
|
144
|
+
it('still fills a page when every group is collapsed', async () => {
|
|
145
|
+
// Collapsed groups are the visible unit. Treating them as free headers
|
|
146
|
+
// emptied the page entirely - caught here, not by the pure helper.
|
|
147
|
+
const { target } = await grouped(4, false)
|
|
148
|
+
expect(groupRows(target)).toHaveLength(4)
|
|
149
|
+
expect(dataRows(target)).toHaveLength(0)
|
|
150
|
+
// 10 collapsed groups over pageSize 4.
|
|
151
|
+
expect(target.textContent).toMatch(/of\s+10\b/)
|
|
152
|
+
})
|
|
153
|
+
})
|