@svgrid/grid 2.1.22 → 2.2.0
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 +9 -2
- package/dist/DockNodeView.svelte +306 -0
- package/dist/DockNodeView.svelte.d.ts +7 -0
- package/dist/DockPopoutHost.svelte +17 -0
- package/dist/DockPopoutHost.svelte.d.ts +14 -0
- package/dist/FlexRender.svelte +96 -96
- package/dist/GridFooter.svelte +178 -178
- package/dist/GridMenus.svelte +83 -3
- package/dist/SvAutoComplete.svelte +5 -3
- package/dist/SvCarousel.svelte +141 -163
- package/dist/SvColorInput.svelte +187 -186
- package/dist/SvColorInput.svelte.d.ts +1 -1
- package/dist/SvComboBox.svelte +7 -3
- package/dist/SvCommand.svelte +28 -85
- package/dist/SvContextMenu.svelte +116 -116
- package/dist/SvCountryInput.svelte +1 -1
- package/dist/SvDateRangeInput.svelte +1 -1
- package/dist/SvDateTimePicker.svelte +9 -3
- package/dist/SvDateTimePicker.svelte.d.ts +3 -0
- package/dist/SvDockLayout.svelte +244 -0
- package/dist/SvDockLayout.svelte.d.ts +77 -0
- package/dist/SvDockManager.svelte +922 -0
- package/dist/SvDockManager.svelte.d.ts +106 -0
- package/dist/SvDrawer.svelte +250 -228
- package/dist/SvDrawer.svelte.d.ts +4 -0
- package/dist/SvDropDownList.svelte +85 -13
- package/dist/SvDropDownList.svelte.d.ts +3 -0
- package/dist/SvField.svelte +21 -4
- package/dist/SvField.svelte.d.ts +1 -0
- package/dist/SvForm.svelte +201 -91
- package/dist/SvForm.svelte.d.ts +15 -22
- package/dist/SvGrid.controller.svelte.d.ts +32 -1
- package/dist/SvGrid.controller.svelte.js +156 -27
- package/dist/SvGrid.css +193 -5
- package/dist/SvGrid.svelte +3131 -2786
- package/dist/SvGrid.types.d.ts +452 -1
- package/dist/SvGridBoard.svelte +2339 -2339
- package/dist/SvGridChart.svelte +1724 -1724
- package/dist/SvGridChartPanel.svelte +485 -485
- package/dist/SvGridDropdown.svelte +689 -682
- package/dist/SvGridSelect.svelte +1 -0
- package/dist/SvGroupCell.svelte +109 -109
- package/dist/SvListBox.svelte +36 -14
- package/dist/SvMaskedInput.svelte +4 -3
- package/dist/SvMaskedInput.svelte.d.ts +1 -1
- package/dist/SvMenu.svelte +124 -124
- package/dist/SvMenuList.svelte +117 -165
- package/dist/SvMenuList.svelte.d.ts +2 -13
- package/dist/SvModal.svelte +12 -29
- package/dist/SvMultiSelect.svelte +1 -0
- package/dist/SvNumberInput.svelte +131 -130
- package/dist/SvNumberInput.svelte.d.ts +1 -1
- package/dist/SvOtpInput.svelte +158 -158
- package/dist/SvPagination.svelte +18 -18
- package/dist/SvPasswordInput.svelte +3 -2
- package/dist/SvPasswordInput.svelte.d.ts +1 -1
- package/dist/SvPhoneInput.svelte +3 -2
- package/dist/SvPhoneInput.svelte.d.ts +1 -1
- package/dist/SvPopover.svelte +139 -139
- package/dist/SvRowGroupPanel.svelte +170 -170
- package/dist/SvScrollArea.svelte +61 -61
- package/dist/SvStepper.svelte +6 -9
- package/dist/SvTagsInput.svelte +3 -2
- package/dist/SvTagsInput.svelte.d.ts +1 -1
- package/dist/SvTooltip.svelte +127 -138
- package/dist/SvTour.svelte +204 -176
- package/dist/SvTree.svelte +377 -377
- package/dist/SvTreeSelect.svelte +230 -229
- package/dist/build-api.js +76 -54
- package/dist/cdn/svgrid.js +10913 -6450
- package/dist/cdn/svgrid.svelte-external.js +9628 -5481
- package/dist/chart-export.js +8 -8
- package/dist/columns.js +6 -0
- package/dist/conditional-formatting.d.ts +67 -3
- package/dist/conditional-formatting.js +124 -17
- package/dist/createCarousel.svelte.d.ts +72 -0
- package/dist/createCarousel.svelte.js +80 -0
- package/dist/createCommand.svelte.d.ts +62 -0
- package/dist/createCommand.svelte.js +109 -0
- package/dist/createForm.svelte.d.ts +62 -0
- package/dist/createForm.svelte.js +374 -0
- package/dist/createMenu.svelte.d.ts +88 -0
- package/dist/createMenu.svelte.js +153 -0
- package/dist/createOverlay.svelte.d.ts +38 -0
- package/dist/createOverlay.svelte.js +68 -0
- package/dist/createPagination.d.ts +74 -0
- package/dist/createPagination.js +71 -0
- package/dist/createPopoverSelect.svelte.js +6 -12
- package/dist/createStepper.d.ts +44 -0
- package/dist/createStepper.js +26 -0
- package/dist/createTooltip.svelte.d.ts +32 -0
- package/dist/createTooltip.svelte.js +61 -0
- package/dist/datetime/timezone.d.ts +36 -0
- package/dist/datetime/timezone.js +110 -0
- package/dist/dock-context.d.ts +52 -0
- package/dist/dock-context.js +1 -0
- package/dist/dock-manager-model.d.ts +136 -0
- package/dist/dock-manager-model.js +514 -0
- package/dist/dock-model.d.ts +105 -0
- package/dist/dock-model.js +288 -0
- package/dist/dock-popout.d.ts +30 -0
- package/dist/dock-popout.js +81 -0
- package/dist/editor-contract.d.ts +2 -0
- package/dist/filter-operators.d.ts +6 -0
- package/dist/filter-operators.js +35 -2
- package/dist/filtering/excel-filters.d.ts +18 -1
- package/dist/filtering/excel-filters.js +56 -0
- package/dist/form-field.d.ts +73 -0
- package/dist/form-field.js +15 -0
- package/dist/index.d.ts +25 -5
- package/dist/index.js +40 -4
- package/dist/list-nav.d.ts +18 -0
- package/dist/list-nav.js +30 -0
- package/dist/list-option.d.ts +2 -0
- package/dist/menu-item.d.ts +20 -0
- package/dist/menu-item.js +1 -0
- package/dist/menus.d.ts +5 -0
- package/dist/menus.js +68 -16
- package/dist/panel-resize.d.ts +25 -0
- package/dist/panel-resize.js +40 -0
- package/dist/popover.d.ts +29 -3
- package/dist/popover.js +22 -6
- package/dist/recurrence.d.ts +33 -7
- package/dist/recurrence.js +151 -13
- package/dist/row-drag.d.ts +8 -0
- package/dist/row-drag.js +11 -0
- package/dist/scheduler-ical.d.ts +30 -0
- package/dist/scheduler-ical.js +180 -0
- package/dist/scheduler-model.d.ts +269 -0
- package/dist/scheduler-model.js +602 -0
- package/dist/scheduler-view.svelte.d.ts +22 -0
- package/dist/scheduler-view.svelte.js +13 -0
- package/dist/spreadsheet.js +20 -12
- package/dist/ui-app.types.d.ts +3 -0
- package/package.json +14 -10
- package/src/DockNodeView.svelte +306 -0
- package/src/DockPopoutHost.svelte +17 -0
- package/src/FlexRender.svelte +96 -96
- package/src/GridFooter.svelte +178 -178
- package/src/GridMenus.svelte +83 -3
- package/src/SvAutoComplete.svelte +5 -3
- package/src/SvCarousel.svelte +141 -163
- package/src/SvCarousel.test.ts +68 -0
- package/src/SvColorInput.svelte +187 -186
- package/src/SvComboBox.svelte +7 -3
- package/src/SvCommand.svelte +28 -85
- package/src/SvCommand.test.ts +78 -0
- package/src/SvContextMenu.svelte +116 -116
- package/src/SvCountryInput.svelte +1 -1
- package/src/SvDateRangeInput.svelte +1 -1
- package/src/SvDateTimePicker.svelte +9 -3
- package/src/SvDockLayout.svelte +244 -0
- package/src/SvDockManager.svelte +922 -0
- package/src/SvDrawer.svelte +250 -228
- package/src/SvDropDownList.svelte +85 -13
- package/src/SvField.svelte +21 -4
- package/src/SvForm.svelte +201 -91
- package/src/SvForm.test.ts +299 -0
- package/src/SvGrid.controller.svelte.ts +3158 -3034
- package/src/SvGrid.css +193 -5
- package/src/SvGrid.svelte +3131 -2786
- package/src/SvGrid.types.ts +1489 -1027
- package/src/SvGridBoard.svelte +2339 -2339
- package/src/SvGridChart.svelte +1724 -1724
- package/src/SvGridChartPanel.svelte +485 -485
- package/src/SvGridDropdown.svelte +689 -682
- package/src/SvGridSelect.svelte +1 -0
- package/src/SvGroupCell.svelte +109 -109
- package/src/SvListBox.svelte +36 -14
- package/src/SvMaskedInput.svelte +4 -3
- package/src/SvMenu.svelte +124 -124
- package/src/SvMenu.test.ts +97 -73
- package/src/SvMenuList.svelte +117 -165
- package/src/SvModal.svelte +12 -29
- package/src/SvModal.test.ts +82 -0
- package/src/SvMultiSelect.svelte +1 -0
- package/src/SvNumberInput.svelte +131 -130
- package/src/SvOtpInput.svelte +158 -158
- package/src/SvPagination.svelte +18 -18
- package/src/SvPasswordInput.svelte +3 -2
- package/src/SvPhoneInput.svelte +3 -2
- package/src/SvPopover.svelte +139 -139
- package/src/SvRowGroupPanel.svelte +170 -170
- package/src/SvScrollArea.svelte +61 -61
- package/src/SvStepper.svelte +6 -9
- package/src/SvTagsInput.svelte +3 -2
- package/src/SvTooltip.svelte +127 -138
- package/src/SvTooltip.test.ts +73 -0
- package/src/SvTour.svelte +204 -176
- package/src/SvTree.svelte +377 -377
- package/src/SvTreeSelect.svelte +230 -229
- package/src/a11y.contract.test.ts +49 -49
- package/src/a11y.test.ts +59 -59
- package/src/a11y.ts +61 -61
- package/src/build-api.ts +870 -847
- package/src/cell-formatting.ts +169 -169
- package/src/cell-render.ts +469 -469
- package/src/chart-export.ts +201 -201
- package/src/chart.ts +2296 -2296
- package/src/collaboration.test.ts +104 -104
- package/src/collaboration.ts +167 -167
- package/src/columns.ts +5 -0
- package/src/conditional-formatting.test.ts +104 -0
- package/src/conditional-formatting.ts +176 -19
- package/src/core.performance.test.ts +30 -30
- package/src/core.ts +1111 -1111
- package/src/createAutocomplete.svelte.ts +132 -132
- package/src/createCarousel.svelte.ts +104 -0
- package/src/createCombobox.svelte.ts +179 -179
- package/src/createCommand.svelte.ts +125 -0
- package/src/createCountryInput.svelte.ts +157 -157
- package/src/createDropdownList.svelte.ts +162 -162
- package/src/createForm.svelte.ts +333 -0
- package/src/createGrid.svelte.ts +42 -42
- package/src/createGrid.test.ts +10 -10
- package/src/createGridState.svelte.ts +17 -17
- package/src/createMenu.svelte.ts +202 -0
- package/src/createOverlay.svelte.ts +101 -0
- package/src/createPagination.test.ts +65 -0
- package/src/createPagination.ts +84 -0
- package/src/createPopoverSelect.svelte.ts +206 -210
- package/src/createStepper.test.ts +62 -0
- package/src/createStepper.ts +61 -0
- package/src/createTooltip.svelte.ts +86 -0
- package/src/createTree.svelte.ts +319 -319
- package/src/datetime/timezone.test.ts +69 -0
- package/src/datetime/timezone.ts +134 -0
- package/src/dock-context.ts +47 -0
- package/src/dock-manager-model.test.ts +275 -0
- package/src/dock-manager-model.ts +593 -0
- package/src/dock-model.test.ts +163 -0
- package/src/dock-model.ts +368 -0
- package/src/dock-popout.ts +94 -0
- package/src/editing.test.ts +859 -859
- package/src/editing.ts +675 -675
- package/src/editor-contract.ts +2 -0
- package/src/export-data-api.test.ts +126 -126
- package/src/export-format.test.ts +107 -107
- package/src/export-format.ts +598 -598
- package/src/filter-operators.test.ts +59 -0
- package/src/filter-operators.ts +35 -2
- package/src/filtering/excel-filters.test.ts +86 -1
- package/src/filtering/excel-filters.ts +65 -0
- package/src/flex-render.ts +3 -3
- package/src/form-field.ts +87 -0
- package/src/index.ts +623 -469
- package/src/keyboard.test.ts +59 -59
- package/src/keyboard.ts +97 -97
- package/src/list-nav.test.ts +49 -0
- package/src/list-nav.ts +29 -0
- package/src/list-option.ts +2 -0
- package/src/menu-item.ts +21 -0
- package/src/menus.test.ts +48 -0
- package/src/menus.ts +639 -582
- package/src/merge-objects.ts +48 -48
- package/src/overlays.test.ts +90 -90
- package/src/panel-resize.ts +52 -0
- package/src/popover.bounds.test.ts +93 -0
- package/src/popover.ts +51 -7
- package/src/recurrence.test.ts +88 -1
- package/src/recurrence.ts +166 -15
- package/src/render-component.ts +28 -28
- package/src/row-drag.ts +10 -0
- package/src/scheduler-ical.test.ts +68 -0
- package/src/scheduler-ical.ts +180 -0
- package/src/scheduler-model.test.ts +546 -0
- package/src/scheduler-model.ts +853 -0
- package/src/scheduler-view.svelte.ts +33 -0
- package/src/selection.test.ts +754 -754
- package/src/selection.ts +600 -600
- package/src/server-data-source.test.ts +289 -289
- package/src/server-data-source.ts +413 -413
- package/src/sparkline.test.ts +68 -68
- package/src/sparkline.ts +169 -169
- package/src/spreadsheet.test.ts +489 -489
- package/src/spreadsheet.ts +312 -304
- package/src/static-functions.ts +11 -11
- package/src/subscribe.ts +38 -38
- package/src/svgrid-wrapper.types.ts +501 -501
- package/src/svgrid.behavior.test.ts +706 -706
- package/src/svgrid.charting.test.ts +527 -527
- package/src/svgrid.effect-driven-filter.svelte.test.ts +116 -0
- package/src/svgrid.features.test.ts +157 -157
- package/src/svgrid.new-features.wrapper.test.ts +251 -251
- package/src/svgrid.wrapper.test.ts +40 -40
- package/src/test-setup.ts +62 -62
- package/src/themes/index.ts +159 -159
- package/src/ui-app.types.ts +3 -0
- package/src/virtual.test.ts +6 -4
- 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 +296 -296
package/dist/GridFooter.svelte
CHANGED
|
@@ -1,178 +1,178 @@
|
|
|
1
|
-
<script lang="ts" generics="TFeatures extends TableFeatures = TableFeatures, TData extends RowData = RowData">
|
|
2
|
-
import {
|
|
3
|
-
getGridCellA11yProps,
|
|
4
|
-
getGridCellDomId,
|
|
5
|
-
getGridHeaderA11yProps,
|
|
6
|
-
getGridRootA11yProps,
|
|
7
|
-
getGridRowA11yProps,
|
|
8
|
-
type EditorContext,
|
|
9
|
-
type CellEditorOption,
|
|
10
|
-
type Column,
|
|
11
|
-
type Row,
|
|
12
|
-
type RowData,
|
|
13
|
-
type TableFeatures,
|
|
14
|
-
} from "./index";
|
|
15
|
-
import "./sv-grid-scrollbar";
|
|
16
|
-
import type { Snippet } from "svelte";
|
|
17
|
-
import {
|
|
18
|
-
RenderSnippetConfig,
|
|
19
|
-
RenderComponentConfig,
|
|
20
|
-
} from "./render-component";
|
|
21
|
-
import {
|
|
22
|
-
buildSparkline,
|
|
23
|
-
toSparklineValues,
|
|
24
|
-
} from "./sparkline";
|
|
25
|
-
import SvGridDropdown from "./SvGridDropdown.svelte";
|
|
26
|
-
import type {
|
|
27
|
-
Props,
|
|
28
|
-
SelectionPoint,
|
|
29
|
-
SelectionRange,
|
|
30
|
-
CellEditState,
|
|
31
|
-
FilterOperator,
|
|
32
|
-
FilterOption,
|
|
33
|
-
MenuPosition,
|
|
34
|
-
} from "./SvGrid.types";
|
|
35
|
-
import {
|
|
36
|
-
cfTextStyle,
|
|
37
|
-
fmtStat,
|
|
38
|
-
getEditableInputValue,
|
|
39
|
-
getEditorInputType,
|
|
40
|
-
toValueArray,
|
|
41
|
-
getOptionLabel,
|
|
42
|
-
getOptionColor,
|
|
43
|
-
colorfulChipStyle,
|
|
44
|
-
getEditorClass,
|
|
45
|
-
} from "./SvGrid.helpers";
|
|
46
|
-
import {
|
|
47
|
-
} from "./SvGrid.controller.svelte";
|
|
48
|
-
import type { SvGridController } from "./SvGrid.controller.svelte";
|
|
49
|
-
|
|
50
|
-
let {
|
|
51
|
-
ctrl,
|
|
52
|
-
pager = true,
|
|
53
|
-
showStatus = true,
|
|
54
|
-
top = false,
|
|
55
|
-
pageSizeOptions,
|
|
56
|
-
}: {
|
|
57
|
-
ctrl: SvGridController<TFeatures, TData>;
|
|
58
|
-
/** Render the pagination controls in this instance. */
|
|
59
|
-
pager?: boolean;
|
|
60
|
-
/** Render the status bar in this instance. */
|
|
61
|
-
showStatus?: boolean;
|
|
62
|
-
/** This is a top-positioned footer (styling only). */
|
|
63
|
-
top?: boolean;
|
|
64
|
-
/** Page-size choices for the selector. Defaults to `[10, 25, 50, 100]`. */
|
|
65
|
-
pageSizeOptions?: number[];
|
|
66
|
-
} = $props();
|
|
67
|
-
|
|
68
|
-
// View facade: re-bind the controller's reactive members so the markup
|
|
69
|
-
// (moved verbatim from SvGrid.svelte) stays identical.
|
|
70
|
-
const paginationEnabled = $derived(ctrl.paginationEnabled);
|
|
71
|
-
const grid = $derived(ctrl.grid);
|
|
72
|
-
const paginationState = $derived(ctrl.paginationState);
|
|
73
|
-
const allRowsBeforePagination = $derived(ctrl.allRowsBeforePagination);
|
|
74
|
-
const statusBarEnabled = $derived(ctrl.statusBarEnabled);
|
|
75
|
-
const statusBarAggregates = $derived(ctrl.statusBarAggregates);
|
|
76
|
-
const statusBarStats = $derived(ctrl.statusBarStats);
|
|
77
|
-
const changePage = $derived(ctrl.changePage);
|
|
78
|
-
const goToPage = $derived(ctrl.goToPage);
|
|
79
|
-
const setPageSize = $derived(ctrl.setPageSize);
|
|
80
|
-
</script>
|
|
81
|
-
|
|
82
|
-
{#if showStatus && statusBarEnabled && statusBarStats}
|
|
83
|
-
{@const s = statusBarStats}
|
|
84
|
-
<div class="sv-grid-status-bar" role="status" aria-live="polite">
|
|
85
|
-
{#each statusBarAggregates as agg (agg)}
|
|
86
|
-
{#if agg === "count"}
|
|
87
|
-
<span class="sv-grid-status-item"
|
|
88
|
-
><span class="sv-grid-status-label">Count</span>{fmtStat(s.count)}</span
|
|
89
|
-
>
|
|
90
|
-
{:else if agg === "numericCount"}
|
|
91
|
-
<span class="sv-grid-status-item"
|
|
92
|
-
><span class="sv-grid-status-label">Numeric</span>{fmtStat(s.numericCount)}</span
|
|
93
|
-
>
|
|
94
|
-
{:else if s.numericCount > 0 && agg === "sum"}
|
|
95
|
-
<span class="sv-grid-status-item"
|
|
96
|
-
><span class="sv-grid-status-label">Sum</span>{fmtStat(s.sum)}</span
|
|
97
|
-
>
|
|
98
|
-
{:else if s.numericCount > 0 && agg === "avg"}
|
|
99
|
-
<span class="sv-grid-status-item"
|
|
100
|
-
><span class="sv-grid-status-label">Avg</span>{fmtStat(s.avg)}</span
|
|
101
|
-
>
|
|
102
|
-
{:else if s.numericCount > 0 && agg === "min"}
|
|
103
|
-
<span class="sv-grid-status-item"
|
|
104
|
-
><span class="sv-grid-status-label">Min</span>{fmtStat(s.min)}</span
|
|
105
|
-
>
|
|
106
|
-
{:else if s.numericCount > 0 && agg === "max"}
|
|
107
|
-
<span class="sv-grid-status-item"
|
|
108
|
-
><span class="sv-grid-status-label">Max</span>{fmtStat(s.max)}</span
|
|
109
|
-
>
|
|
110
|
-
{/if}
|
|
111
|
-
{/each}
|
|
112
|
-
</div>
|
|
113
|
-
{/if}
|
|
114
|
-
|
|
115
|
-
{#if pager && paginationEnabled}
|
|
116
|
-
{@const totalRows = ctrl.paginationTotalRows}
|
|
117
|
-
{@const pageSize = ctrl.paginationPageSize}
|
|
118
|
-
{@const pageCount = Math.max(1, Math.ceil(totalRows / pageSize))}
|
|
119
|
-
{@const currentPage = Math.min(ctrl.paginationPageIndex + 1, pageCount)}
|
|
120
|
-
{@const rangeStart =
|
|
121
|
-
totalRows === 0 ? 0 : (currentPage - 1) * pageSize + 1}
|
|
122
|
-
{@const rangeEnd = Math.min(totalRows, currentPage * pageSize)}
|
|
123
|
-
{@const onFirst = currentPage <= 1}
|
|
124
|
-
{@const onLast = currentPage >= pageCount}
|
|
125
|
-
{@const sizes = pageSizeOptions && pageSizeOptions.length ? pageSizeOptions : [10, 25, 50, 100]}
|
|
126
|
-
<div class="sv-grid-pagination" class:sv-grid-pagination-top={top} role="navigation" aria-label="Pagination">
|
|
127
|
-
<div class="sv-grid-pagination-pagesize">
|
|
128
|
-
<span>Page Size:</span>
|
|
129
|
-
<div class="sv-grid-pagination-pagesize-dd">
|
|
130
|
-
<SvGridDropdown
|
|
131
|
-
options={sizes.map((n) => ({ value: n, label: String(n) }))}
|
|
132
|
-
value={pageSize}
|
|
133
|
-
autoOpen={false}
|
|
134
|
-
onChange={(v) => setPageSize(Number(v))}
|
|
135
|
-
/>
|
|
136
|
-
</div>
|
|
137
|
-
</div>
|
|
138
|
-
<span class="sv-grid-pagination-range">
|
|
139
|
-
<strong>{rangeStart.toLocaleString()}</strong> to
|
|
140
|
-
<strong>{rangeEnd.toLocaleString()}</strong> of
|
|
141
|
-
<strong>{totalRows.toLocaleString()}</strong>
|
|
142
|
-
</span>
|
|
143
|
-
<div class="sv-grid-pagination-nav">
|
|
144
|
-
<button
|
|
145
|
-
type="button"
|
|
146
|
-
class="sv-grid-pagination-btn"
|
|
147
|
-
disabled={onFirst}
|
|
148
|
-
onclick={() => goToPage(0)}
|
|
149
|
-
aria-label="First page">⇤</button
|
|
150
|
-
>
|
|
151
|
-
<button
|
|
152
|
-
type="button"
|
|
153
|
-
class="sv-grid-pagination-btn"
|
|
154
|
-
disabled={onFirst}
|
|
155
|
-
onclick={() => changePage(-1)}
|
|
156
|
-
aria-label="Previous page">‹</button
|
|
157
|
-
>
|
|
158
|
-
<span class="sv-grid-pagination-label">
|
|
159
|
-
Page <strong>{currentPage.toLocaleString()}</strong> of
|
|
160
|
-
<strong>{pageCount.toLocaleString()}</strong>
|
|
161
|
-
</span>
|
|
162
|
-
<button
|
|
163
|
-
type="button"
|
|
164
|
-
class="sv-grid-pagination-btn"
|
|
165
|
-
disabled={onLast}
|
|
166
|
-
onclick={() => changePage(1)}
|
|
167
|
-
aria-label="Next page">›</button
|
|
168
|
-
>
|
|
169
|
-
<button
|
|
170
|
-
type="button"
|
|
171
|
-
class="sv-grid-pagination-btn"
|
|
172
|
-
disabled={onLast}
|
|
173
|
-
onclick={() => goToPage(pageCount - 1)}
|
|
174
|
-
aria-label="Last page">⇥</button
|
|
175
|
-
>
|
|
176
|
-
</div>
|
|
177
|
-
</div>
|
|
178
|
-
{/if}
|
|
1
|
+
<script lang="ts" generics="TFeatures extends TableFeatures = TableFeatures, TData extends RowData = RowData">
|
|
2
|
+
import {
|
|
3
|
+
getGridCellA11yProps,
|
|
4
|
+
getGridCellDomId,
|
|
5
|
+
getGridHeaderA11yProps,
|
|
6
|
+
getGridRootA11yProps,
|
|
7
|
+
getGridRowA11yProps,
|
|
8
|
+
type EditorContext,
|
|
9
|
+
type CellEditorOption,
|
|
10
|
+
type Column,
|
|
11
|
+
type Row,
|
|
12
|
+
type RowData,
|
|
13
|
+
type TableFeatures,
|
|
14
|
+
} from "./index";
|
|
15
|
+
import "./sv-grid-scrollbar";
|
|
16
|
+
import type { Snippet } from "svelte";
|
|
17
|
+
import {
|
|
18
|
+
RenderSnippetConfig,
|
|
19
|
+
RenderComponentConfig,
|
|
20
|
+
} from "./render-component";
|
|
21
|
+
import {
|
|
22
|
+
buildSparkline,
|
|
23
|
+
toSparklineValues,
|
|
24
|
+
} from "./sparkline";
|
|
25
|
+
import SvGridDropdown from "./SvGridDropdown.svelte";
|
|
26
|
+
import type {
|
|
27
|
+
Props,
|
|
28
|
+
SelectionPoint,
|
|
29
|
+
SelectionRange,
|
|
30
|
+
CellEditState,
|
|
31
|
+
FilterOperator,
|
|
32
|
+
FilterOption,
|
|
33
|
+
MenuPosition,
|
|
34
|
+
} from "./SvGrid.types";
|
|
35
|
+
import {
|
|
36
|
+
cfTextStyle,
|
|
37
|
+
fmtStat,
|
|
38
|
+
getEditableInputValue,
|
|
39
|
+
getEditorInputType,
|
|
40
|
+
toValueArray,
|
|
41
|
+
getOptionLabel,
|
|
42
|
+
getOptionColor,
|
|
43
|
+
colorfulChipStyle,
|
|
44
|
+
getEditorClass,
|
|
45
|
+
} from "./SvGrid.helpers";
|
|
46
|
+
import {
|
|
47
|
+
} from "./SvGrid.controller.svelte";
|
|
48
|
+
import type { SvGridController } from "./SvGrid.controller.svelte";
|
|
49
|
+
|
|
50
|
+
let {
|
|
51
|
+
ctrl,
|
|
52
|
+
pager = true,
|
|
53
|
+
showStatus = true,
|
|
54
|
+
top = false,
|
|
55
|
+
pageSizeOptions,
|
|
56
|
+
}: {
|
|
57
|
+
ctrl: SvGridController<TFeatures, TData>;
|
|
58
|
+
/** Render the pagination controls in this instance. */
|
|
59
|
+
pager?: boolean;
|
|
60
|
+
/** Render the status bar in this instance. */
|
|
61
|
+
showStatus?: boolean;
|
|
62
|
+
/** This is a top-positioned footer (styling only). */
|
|
63
|
+
top?: boolean;
|
|
64
|
+
/** Page-size choices for the selector. Defaults to `[10, 25, 50, 100]`. */
|
|
65
|
+
pageSizeOptions?: number[];
|
|
66
|
+
} = $props();
|
|
67
|
+
|
|
68
|
+
// View facade: re-bind the controller's reactive members so the markup
|
|
69
|
+
// (moved verbatim from SvGrid.svelte) stays identical.
|
|
70
|
+
const paginationEnabled = $derived(ctrl.paginationEnabled);
|
|
71
|
+
const grid = $derived(ctrl.grid);
|
|
72
|
+
const paginationState = $derived(ctrl.paginationState);
|
|
73
|
+
const allRowsBeforePagination = $derived(ctrl.allRowsBeforePagination);
|
|
74
|
+
const statusBarEnabled = $derived(ctrl.statusBarEnabled);
|
|
75
|
+
const statusBarAggregates = $derived(ctrl.statusBarAggregates);
|
|
76
|
+
const statusBarStats = $derived(ctrl.statusBarStats);
|
|
77
|
+
const changePage = $derived(ctrl.changePage);
|
|
78
|
+
const goToPage = $derived(ctrl.goToPage);
|
|
79
|
+
const setPageSize = $derived(ctrl.setPageSize);
|
|
80
|
+
</script>
|
|
81
|
+
|
|
82
|
+
{#if showStatus && statusBarEnabled && statusBarStats}
|
|
83
|
+
{@const s = statusBarStats}
|
|
84
|
+
<div class="sv-grid-status-bar" role="status" aria-live="polite">
|
|
85
|
+
{#each statusBarAggregates as agg (agg)}
|
|
86
|
+
{#if agg === "count"}
|
|
87
|
+
<span class="sv-grid-status-item"
|
|
88
|
+
><span class="sv-grid-status-label">Count</span>{fmtStat(s.count)}</span
|
|
89
|
+
>
|
|
90
|
+
{:else if agg === "numericCount"}
|
|
91
|
+
<span class="sv-grid-status-item"
|
|
92
|
+
><span class="sv-grid-status-label">Numeric</span>{fmtStat(s.numericCount)}</span
|
|
93
|
+
>
|
|
94
|
+
{:else if s.numericCount > 0 && agg === "sum"}
|
|
95
|
+
<span class="sv-grid-status-item"
|
|
96
|
+
><span class="sv-grid-status-label">Sum</span>{fmtStat(s.sum)}</span
|
|
97
|
+
>
|
|
98
|
+
{:else if s.numericCount > 0 && agg === "avg"}
|
|
99
|
+
<span class="sv-grid-status-item"
|
|
100
|
+
><span class="sv-grid-status-label">Avg</span>{fmtStat(s.avg)}</span
|
|
101
|
+
>
|
|
102
|
+
{:else if s.numericCount > 0 && agg === "min"}
|
|
103
|
+
<span class="sv-grid-status-item"
|
|
104
|
+
><span class="sv-grid-status-label">Min</span>{fmtStat(s.min)}</span
|
|
105
|
+
>
|
|
106
|
+
{:else if s.numericCount > 0 && agg === "max"}
|
|
107
|
+
<span class="sv-grid-status-item"
|
|
108
|
+
><span class="sv-grid-status-label">Max</span>{fmtStat(s.max)}</span
|
|
109
|
+
>
|
|
110
|
+
{/if}
|
|
111
|
+
{/each}
|
|
112
|
+
</div>
|
|
113
|
+
{/if}
|
|
114
|
+
|
|
115
|
+
{#if pager && paginationEnabled}
|
|
116
|
+
{@const totalRows = ctrl.paginationTotalRows}
|
|
117
|
+
{@const pageSize = ctrl.paginationPageSize}
|
|
118
|
+
{@const pageCount = Math.max(1, Math.ceil(totalRows / pageSize))}
|
|
119
|
+
{@const currentPage = Math.min(ctrl.paginationPageIndex + 1, pageCount)}
|
|
120
|
+
{@const rangeStart =
|
|
121
|
+
totalRows === 0 ? 0 : (currentPage - 1) * pageSize + 1}
|
|
122
|
+
{@const rangeEnd = Math.min(totalRows, currentPage * pageSize)}
|
|
123
|
+
{@const onFirst = currentPage <= 1}
|
|
124
|
+
{@const onLast = currentPage >= pageCount}
|
|
125
|
+
{@const sizes = pageSizeOptions && pageSizeOptions.length ? pageSizeOptions : [10, 25, 50, 100]}
|
|
126
|
+
<div class="sv-grid-pagination" class:sv-grid-pagination-top={top} role="navigation" aria-label="Pagination">
|
|
127
|
+
<div class="sv-grid-pagination-pagesize">
|
|
128
|
+
<span>Page Size:</span>
|
|
129
|
+
<div class="sv-grid-pagination-pagesize-dd">
|
|
130
|
+
<SvGridDropdown
|
|
131
|
+
options={sizes.map((n) => ({ value: n, label: String(n) }))}
|
|
132
|
+
value={pageSize}
|
|
133
|
+
autoOpen={false}
|
|
134
|
+
onChange={(v) => setPageSize(Number(v))}
|
|
135
|
+
/>
|
|
136
|
+
</div>
|
|
137
|
+
</div>
|
|
138
|
+
<span class="sv-grid-pagination-range">
|
|
139
|
+
<strong>{rangeStart.toLocaleString()}</strong> to
|
|
140
|
+
<strong>{rangeEnd.toLocaleString()}</strong> of
|
|
141
|
+
<strong>{totalRows.toLocaleString()}</strong>
|
|
142
|
+
</span>
|
|
143
|
+
<div class="sv-grid-pagination-nav">
|
|
144
|
+
<button
|
|
145
|
+
type="button"
|
|
146
|
+
class="sv-grid-pagination-btn"
|
|
147
|
+
disabled={onFirst}
|
|
148
|
+
onclick={() => goToPage(0)}
|
|
149
|
+
aria-label="First page">⇤</button
|
|
150
|
+
>
|
|
151
|
+
<button
|
|
152
|
+
type="button"
|
|
153
|
+
class="sv-grid-pagination-btn"
|
|
154
|
+
disabled={onFirst}
|
|
155
|
+
onclick={() => changePage(-1)}
|
|
156
|
+
aria-label="Previous page">‹</button
|
|
157
|
+
>
|
|
158
|
+
<span class="sv-grid-pagination-label">
|
|
159
|
+
Page <strong>{currentPage.toLocaleString()}</strong> of
|
|
160
|
+
<strong>{pageCount.toLocaleString()}</strong>
|
|
161
|
+
</span>
|
|
162
|
+
<button
|
|
163
|
+
type="button"
|
|
164
|
+
class="sv-grid-pagination-btn"
|
|
165
|
+
disabled={onLast}
|
|
166
|
+
onclick={() => changePage(1)}
|
|
167
|
+
aria-label="Next page">›</button
|
|
168
|
+
>
|
|
169
|
+
<button
|
|
170
|
+
type="button"
|
|
171
|
+
class="sv-grid-pagination-btn"
|
|
172
|
+
disabled={onLast}
|
|
173
|
+
onclick={() => goToPage(pageCount - 1)}
|
|
174
|
+
aria-label="Last page">⇥</button
|
|
175
|
+
>
|
|
176
|
+
</div>
|
|
177
|
+
</div>
|
|
178
|
+
{/if}
|
package/dist/GridMenus.svelte
CHANGED
|
@@ -2,6 +2,7 @@
|
|
|
2
2
|
import {
|
|
3
3
|
applyExcelFilter,
|
|
4
4
|
normalizeForFilter,
|
|
5
|
+
splitInTokens,
|
|
5
6
|
createColumnVirtualizer,
|
|
6
7
|
createCoreRowModel,
|
|
7
8
|
createExpandedRowModel,
|
|
@@ -124,6 +125,12 @@
|
|
|
124
125
|
const operatorsForColumn = $derived(ctrl.operatorsForColumn);
|
|
125
126
|
const defaultOperatorFor = $derived(ctrl.defaultOperatorFor);
|
|
126
127
|
const operatorLabelFor = $derived(ctrl.operatorLabelFor);
|
|
128
|
+
const filterRowValues = $derived(ctrl.filterRowValues);
|
|
129
|
+
const inSuggestFor = $derived(ctrl.inSuggestFor);
|
|
130
|
+
const inSuggestPos = $derived(ctrl.inSuggestPos);
|
|
131
|
+
const inSuggestValues = $derived(ctrl.inSuggestValues);
|
|
132
|
+
const toggleFilterToken = $derived(ctrl.toggleFilterToken);
|
|
133
|
+
const facetValuesForColumn = $derived(ctrl.facetValuesForColumn);
|
|
127
134
|
|
|
128
135
|
// Patch a column's menu filter (used for the optional 2nd condition + join
|
|
129
136
|
// of multi-condition filtering). Merges into the existing entry, creating a
|
|
@@ -135,6 +142,22 @@
|
|
|
135
142
|
}
|
|
136
143
|
const isColumnFiltered = $derived(ctrl.isColumnFiltered);
|
|
137
144
|
const closeMenus = $derived(ctrl.closeMenus);
|
|
145
|
+
|
|
146
|
+
// Column/filter/operator menus are position:fixed and anchored to their
|
|
147
|
+
// trigger by a one-time measurement taken when they open. On scroll they'd
|
|
148
|
+
// otherwise detach and float over the wrong place (#88), so close them on any
|
|
149
|
+
// scroll (capture phase, to catch inner scroll containers) or resize.
|
|
150
|
+
$effect(() => {
|
|
151
|
+
if (!(columnMenuFor || filterMenuFor || operatorMenuFor || chooseColumnsPos)) return;
|
|
152
|
+
const close = () => closeMenus();
|
|
153
|
+
window.addEventListener('scroll', close, true);
|
|
154
|
+
window.addEventListener('resize', close);
|
|
155
|
+
return () => {
|
|
156
|
+
window.removeEventListener('scroll', close, true);
|
|
157
|
+
window.removeEventListener('resize', close);
|
|
158
|
+
};
|
|
159
|
+
});
|
|
160
|
+
|
|
138
161
|
const autosizeColumn = $derived(ctrl.autosizeColumn);
|
|
139
162
|
const autosizeAllColumns = $derived(ctrl.autosizeAllColumns);
|
|
140
163
|
const resetColumns = $derived(ctrl.resetColumns);
|
|
@@ -202,14 +225,30 @@
|
|
|
202
225
|
<option value={option.value}>{operatorLabelFor(option, menuColumn)}</option>
|
|
203
226
|
{/each}
|
|
204
227
|
</select>
|
|
205
|
-
{#if menuActiveOperator !== "isBlank"}
|
|
228
|
+
{#if menuActiveOperator !== "isBlank" && menuActiveOperator !== "isNotBlank"}
|
|
229
|
+
{@const isSetOp =
|
|
230
|
+
menuActiveOperator === "in" || menuActiveOperator === "notIn"}
|
|
206
231
|
<input
|
|
207
232
|
class="sv-grid-menu-condition-value"
|
|
208
|
-
type={menuInputType}
|
|
233
|
+
type={menuActiveOperator === "regex" ? "text" : menuInputType}
|
|
234
|
+
list={isSetOp ? `sv-in-list-${colId}` : undefined}
|
|
209
235
|
value={filterMenuValues[colId]?.value ?? ""}
|
|
210
|
-
placeholder={menuActiveOperator === "between"
|
|
236
|
+
placeholder={menuActiveOperator === "between"
|
|
237
|
+
? "From"
|
|
238
|
+
: isSetOp
|
|
239
|
+
? "value, value..."
|
|
240
|
+
: menuActiveOperator === "regex"
|
|
241
|
+
? "Pattern..."
|
|
242
|
+
: "Filter value..."}
|
|
211
243
|
oninput={(event) => updateFilterMenuValue(colId, (event.currentTarget as HTMLInputElement).value)}
|
|
212
244
|
/>
|
|
245
|
+
{#if isSetOp}
|
|
246
|
+
<datalist id={`sv-in-list-${colId}`}>
|
|
247
|
+
{#each facetValuesForColumn(colId).slice(0, 200) as v (v)}
|
|
248
|
+
<option value={v}></option>
|
|
249
|
+
{/each}
|
|
250
|
+
</datalist>
|
|
251
|
+
{/if}
|
|
213
252
|
{#if menuActiveOperator === "between"}
|
|
214
253
|
<input
|
|
215
254
|
class="sv-grid-menu-condition-value"
|
|
@@ -585,6 +624,47 @@
|
|
|
585
624
|
</div>
|
|
586
625
|
{/if}
|
|
587
626
|
|
|
627
|
+
{#if inSuggestFor}
|
|
628
|
+
{@const suggestColId = inSuggestFor}
|
|
629
|
+
{@const selectedTokens = new Set(
|
|
630
|
+
splitInTokens(filterRowValues[suggestColId] ?? ""),
|
|
631
|
+
)}
|
|
632
|
+
<!-- Value suggestions for an `in` / `notIn` chip input. Items use
|
|
633
|
+
`onmousedown` (preventDefault) so clicking one keeps focus in the
|
|
634
|
+
chip input and the dropdown stays open for multi-select; the input's
|
|
635
|
+
own blur handler closes it when focus truly leaves. -->
|
|
636
|
+
<div
|
|
637
|
+
class="sv-grid-menu sv-grid-in-suggest"
|
|
638
|
+
role="listbox"
|
|
639
|
+
aria-multiselectable="true"
|
|
640
|
+
aria-label="Filter values"
|
|
641
|
+
style={`left: ${inSuggestPos.x}px; top: ${inSuggestPos.y}px;`}
|
|
642
|
+
>
|
|
643
|
+
{#each inSuggestValues as value (value)}
|
|
644
|
+
{@const checked = selectedTokens.has(value)}
|
|
645
|
+
<button
|
|
646
|
+
type="button"
|
|
647
|
+
class="sv-grid-menu-item sv-grid-in-suggest-item"
|
|
648
|
+
role="option"
|
|
649
|
+
aria-selected={checked}
|
|
650
|
+
onmousedown={(event) => {
|
|
651
|
+
event.preventDefault();
|
|
652
|
+
toggleFilterToken(suggestColId, value);
|
|
653
|
+
}}
|
|
654
|
+
>
|
|
655
|
+
<span class="sv-grid-in-suggest-check" aria-hidden="true"
|
|
656
|
+
>{checked ? "✓" : ""}</span
|
|
657
|
+
>
|
|
658
|
+
<span class="sv-grid-in-suggest-label"
|
|
659
|
+
>{value === "" ? "(Blanks)" : value}</span
|
|
660
|
+
>
|
|
661
|
+
</button>
|
|
662
|
+
{:else}
|
|
663
|
+
<div class="sv-grid-facet-empty">No values</div>
|
|
664
|
+
{/each}
|
|
665
|
+
</div>
|
|
666
|
+
{/if}
|
|
667
|
+
|
|
588
668
|
{#if contextMenuFor}
|
|
589
669
|
<div
|
|
590
670
|
class="sv-grid-menu-backdrop"
|
|
@@ -47,7 +47,7 @@
|
|
|
47
47
|
|
|
48
48
|
let fieldEl = $state<HTMLInputElement | null>(null)
|
|
49
49
|
let panelEl = $state<HTMLDivElement | null>(null)
|
|
50
|
-
let rect = $state<AnchoredRect>({ top: 0, left: 0, width: 0, openUpward: false })
|
|
50
|
+
let rect = $state<AnchoredRect>({ top: 0, left: 0, width: 0, openUpward: false, maxHeight: 0, availHeight: 0 })
|
|
51
51
|
|
|
52
52
|
const ac = createAutocomplete({
|
|
53
53
|
value: () => value,
|
|
@@ -66,7 +66,9 @@
|
|
|
66
66
|
|
|
67
67
|
function updatePos() {
|
|
68
68
|
if (!fieldEl) return
|
|
69
|
-
|
|
69
|
+
// estimatedHeight only picks the flip direction; real max-height is availHeight
|
|
70
|
+
// below, so the panel takes its natural content height. See SvComboBox.
|
|
71
|
+
rect = anchoredRect(fieldEl.getBoundingClientRect(), { estimatedHeight: Math.min(ac.filtered.length, 8) * 34 + 12 })
|
|
70
72
|
}
|
|
71
73
|
|
|
72
74
|
$effect(() => {
|
|
@@ -92,7 +94,7 @@
|
|
|
92
94
|
</SvField>
|
|
93
95
|
|
|
94
96
|
{#if ac.open}
|
|
95
|
-
<div bind:this={panelEl} class="sv-ddl__panel" use:portalToBody use:popIn={{ up: rect.openUpward }} style:position="fixed" style:top={`${rect.top}px`} style:left={`${rect.left}px`} style:min-width={`${rect.width}px`} {...ac.listboxProps()}>
|
|
97
|
+
<div bind:this={panelEl} class="sv-ddl__panel" use:portalToBody use:popIn={{ up: rect.openUpward }} style:position="fixed" style:top={rect.openUpward ? undefined : `${rect.top}px`} style:bottom={rect.openUpward ? `${rect.bottom}px` : undefined} style:left={`${rect.left}px`} style:min-width={`${rect.width}px`} style:max-height={`${Math.min(rect.availHeight, 288)}px`} {...ac.listboxProps()}>
|
|
96
98
|
{#each ac.filtered as opt, i (opt.value)}
|
|
97
99
|
<!-- svelte-ignore a11y_click_events_have_key_events a11y_interactive_supports_focus -->
|
|
98
100
|
<div class="sv-ddl__opt" class:is-active={ac.isActive(i)} {...ac.optionProps(i)}>{opt.label}</div>
|