@svgrid/grid 2.2.16 → 2.2.18
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 +1 -1
- package/dist/GridFooter.svelte +12 -11
- package/dist/SvAnchor.svelte +65 -0
- package/dist/SvAnchor.svelte.d.ts +24 -0
- package/dist/SvAspectRatio.svelte +38 -0
- package/dist/SvAspectRatio.svelte.d.ts +16 -0
- package/dist/SvAutoComplete.svelte +52 -7
- package/dist/SvAutoComplete.svelte.d.ts +4 -1
- package/dist/SvBlockquote.svelte +43 -0
- package/dist/SvBlockquote.svelte.d.ts +16 -0
- package/dist/SvCalendar.svelte +33 -2
- package/dist/SvCalendar.svelte.d.ts +8 -1
- package/dist/SvCheckBox.svelte +6 -2
- package/dist/SvCode.svelte +52 -0
- package/dist/SvCode.svelte.d.ts +19 -0
- package/dist/SvCollapsible.svelte +75 -0
- package/dist/SvCollapsible.svelte.d.ts +27 -0
- package/dist/SvColorInput.svelte +11 -17
- package/dist/SvColorInput.svelte.d.ts +2 -0
- package/dist/SvComboBox.svelte +85 -8
- package/dist/SvComboBox.svelte.d.ts +14 -0
- package/dist/SvCountryInput.svelte +2 -2
- package/dist/SvCountryInput.svelte.d.ts +1 -1
- package/dist/SvDropDownList.svelte +154 -51
- package/dist/SvDropDownList.svelte.d.ts +17 -3
- package/dist/SvDurationInput.svelte +59 -41
- package/dist/SvDurationInput.svelte.d.ts +18 -0
- package/dist/SvField.svelte +203 -12
- package/dist/SvField.svelte.d.ts +45 -8
- package/dist/SvForm.svelte +195 -21
- package/dist/SvForm.svelte.d.ts +23 -0
- package/dist/SvGrid.controller.svelte.d.ts +12 -1
- package/dist/SvGrid.controller.svelte.js +87 -7
- package/dist/SvGrid.svelte +383 -181
- package/dist/SvGrid.types.d.ts +123 -2
- package/dist/SvGridChartView.svelte +70 -0
- package/dist/SvGridChartView.svelte.d.ts +11 -0
- package/dist/SvGridDropdown.svelte +9 -2
- package/dist/SvGridSelect.svelte +5 -2
- package/dist/SvGridSelect.svelte.d.ts +1 -1
- package/dist/SvGroup.svelte +41 -0
- package/dist/SvGroup.svelte.d.ts +27 -0
- package/dist/SvHoverCard.svelte +70 -0
- package/dist/SvHoverCard.svelte.d.ts +41 -0
- package/dist/SvKbd.svelte +51 -0
- package/dist/SvKbd.svelte.d.ts +18 -0
- package/dist/SvList.svelte +55 -0
- package/dist/SvList.svelte.d.ts +23 -0
- package/dist/SvListBox.svelte +166 -77
- package/dist/SvListBox.svelte.d.ts +17 -4
- package/dist/SvLoadingOverlay.svelte +53 -0
- package/dist/SvLoadingOverlay.svelte.d.ts +28 -0
- package/dist/SvMark.svelte +36 -0
- package/dist/SvMark.svelte.d.ts +14 -0
- package/dist/SvMaskedInput.svelte +50 -35
- package/dist/SvMaskedInput.svelte.d.ts +17 -2
- package/dist/SvMenuList.svelte +32 -3
- package/dist/SvMenubar.svelte +200 -0
- package/dist/SvMenubar.svelte.d.ts +18 -0
- package/dist/SvMultiSelect.svelte +7 -4
- package/dist/SvMultiSelect.svelte.d.ts +1 -1
- package/dist/SvNumberInput.svelte +79 -42
- package/dist/SvNumberInput.svelte.d.ts +25 -0
- package/dist/SvOtpInput.svelte +2 -2
- package/dist/SvPasswordInput.svelte +51 -31
- package/dist/SvPasswordInput.svelte.d.ts +17 -0
- package/dist/SvPhoneInput.svelte +39 -28
- package/dist/SvPhoneInput.svelte.d.ts +4 -0
- package/dist/SvPopconfirm.svelte +79 -0
- package/dist/SvPopconfirm.svelte.d.ts +42 -0
- package/dist/SvPopover.svelte +87 -29
- package/dist/SvPopover.svelte.d.ts +18 -4
- package/dist/SvRadioGroup.svelte +5 -1
- package/dist/SvResult.svelte +73 -0
- package/dist/SvResult.svelte.d.ts +28 -0
- package/dist/SvSegmented.svelte +114 -0
- package/dist/SvSegmented.svelte.d.ts +29 -0
- package/dist/SvSimpleGrid.svelte +41 -0
- package/dist/SvSimpleGrid.svelte.d.ts +25 -0
- package/dist/SvSlider.svelte +23 -10
- package/dist/SvSpinner.svelte +43 -0
- package/dist/SvSpinner.svelte.d.ts +20 -0
- package/dist/SvStack.svelte +37 -0
- package/dist/SvStack.svelte.d.ts +24 -0
- package/dist/SvSwitchButton.svelte +6 -1
- package/dist/SvTagsInput.svelte +9 -5
- package/dist/SvText.svelte +76 -0
- package/dist/SvText.svelte.d.ts +31 -0
- package/dist/SvTextInput.svelte +75 -43
- package/dist/SvTextInput.svelte.d.ts +28 -1
- package/dist/SvTimePicker.svelte +32 -2
- package/dist/SvTimePicker.svelte.d.ts +8 -9
- package/dist/SvTitle.svelte +57 -0
- package/dist/SvTitle.svelte.d.ts +24 -0
- package/dist/SvToaster.svelte +41 -6
- package/dist/SvToggleButton.svelte +4 -1
- package/dist/SvTooltip.svelte +68 -34
- package/dist/SvTooltip.svelte.d.ts +14 -2
- package/dist/SvTree.svelte +81 -21
- package/dist/SvTree.svelte.d.ts +3 -2
- package/dist/SvTreeSelect.svelte +5 -2
- package/dist/SvTreeSelect.svelte.d.ts +1 -1
- package/dist/SvVisuallyHidden.svelte +49 -0
- package/dist/SvVisuallyHidden.svelte.d.ts +19 -0
- package/dist/ai.d.ts +289 -0
- package/dist/ai.js +1013 -0
- package/dist/board-view.svelte.d.ts +22 -0
- package/dist/board-view.svelte.js +13 -0
- package/dist/build-api.js +36 -6
- package/dist/cdn/GridMenus-0AK9O7qG.js +420 -0
- package/dist/cdn/GridMenus-BjUoCXoD.js +416 -0
- package/dist/cdn/SvDateTimePicker-CYC7gRER.js +2176 -0
- package/dist/cdn/SvDateTimePicker-DtQKd4Ns.js +2198 -0
- package/dist/cdn/SvGridChart-BcLCYvw9.js +1195 -0
- package/dist/cdn/SvGridChart-BhnFdLd0.js +1203 -0
- package/dist/cdn/SvGridChartPanel-Cmx9DHAS.js +561 -0
- package/dist/cdn/SvGridChartPanel-DvjwxLvK.js +577 -0
- package/dist/cdn/SvGridChartView-B40DTJSX.js +54 -0
- package/dist/cdn/SvGridChartView-PwqI4s02.js +53 -0
- package/dist/cdn/SvGridDropdown-DjALc_4f.js +255 -0
- package/dist/cdn/SvGridDropdown-hpnHvOGt.js +254 -0
- package/dist/cdn/chart-T1usDN0o.js +1212 -0
- package/dist/cdn/disclose-version-DoD9AFD_.js +2958 -0
- package/dist/cdn/export-format-JT5pWVT8.js +561 -0
- package/dist/cdn/popover-P-9P2YYn.js +69 -0
- package/dist/cdn/rolldown-runtime-Dy4uBu1J.js +11 -0
- package/dist/cdn/src-BLhdLmoN.js +25707 -0
- package/dist/cdn/src-BwnUVj3T.js +25623 -0
- package/dist/cdn/svgrid.js +9 -32897
- package/dist/cdn/svgrid.svelte-external.js +9 -30052
- package/dist/cell-formatting.d.ts +2 -2
- package/dist/cell-render.js +4 -4
- package/dist/chart-view.svelte.d.ts +25 -0
- package/dist/chart-view.svelte.js +14 -0
- package/dist/createCombobox.svelte.d.ts +5 -0
- package/dist/createCombobox.svelte.js +21 -5
- package/dist/createDropdownList.svelte.d.ts +3 -0
- package/dist/createDropdownList.svelte.js +8 -2
- package/dist/createForm.svelte.d.ts +18 -0
- package/dist/createForm.svelte.js +51 -6
- package/dist/createMenu.svelte.js +27 -0
- package/dist/createPopoverSelect.svelte.d.ts +3 -0
- package/dist/createPopoverSelect.svelte.js +9 -1
- package/dist/createSlider.svelte.d.ts +8 -21
- package/dist/createSlider.svelte.js +34 -0
- package/dist/createTooltip.svelte.d.ts +12 -0
- package/dist/createTooltip.svelte.js +72 -9
- package/dist/editor-contract.d.ts +15 -0
- package/dist/export-provider.d.ts +27 -0
- package/dist/export-provider.js +9 -0
- package/dist/filter-operators.d.ts +6 -0
- package/dist/filter-operators.js +33 -0
- package/dist/form-field.d.ts +45 -2
- package/dist/grid-messages.d.ts +61 -0
- package/dist/grid-messages.js +72 -0
- package/dist/group-display.d.ts +62 -0
- package/dist/group-display.js +78 -0
- package/dist/index.d.ts +36 -4
- package/dist/index.js +43 -2
- package/dist/js-scroller.svelte.d.ts +35 -0
- package/dist/js-scroller.svelte.js +154 -0
- package/dist/list-option.d.ts +46 -0
- package/dist/list-option.js +53 -0
- package/dist/menus.js +25 -11
- package/dist/pivot-view.svelte.d.ts +72 -0
- package/dist/pivot-view.svelte.js +13 -0
- package/dist/positioning.d.ts +111 -0
- package/dist/positioning.js +191 -0
- package/dist/scheduler-model.d.ts +3 -0
- package/dist/scheduler-model.js +22 -5
- package/dist/svgrid-wrapper.types.d.ts +18 -0
- package/dist/toast-store.svelte.d.ts +54 -0
- package/dist/toast-store.svelte.js +65 -15
- package/package.json +9 -1
- package/src/GridFooter.svelte +12 -11
- package/src/SvAnchor.svelte +65 -0
- package/src/SvAspectRatio.svelte +38 -0
- package/src/SvAutoComplete.svelte +52 -7
- package/src/SvBlockquote.svelte +43 -0
- package/src/SvCalendar.svelte +33 -2
- package/src/SvCalendar.test.ts +15 -0
- package/src/SvCheckBox.svelte +6 -2
- package/src/SvCode.svelte +52 -0
- package/src/SvCollapsible.svelte +75 -0
- package/src/SvColorInput.svelte +11 -17
- package/src/SvComboBox.svelte +85 -8
- package/src/SvCountryInput.svelte +2 -2
- package/src/SvDropDownList.svelte +154 -51
- package/src/SvDurationInput.svelte +59 -41
- package/src/SvField.svelte +203 -12
- package/src/SvForm.svelte +195 -21
- package/src/SvForm.test.ts +112 -0
- package/src/SvGrid.controller.svelte.ts +88 -7
- package/src/SvGrid.svelte +383 -181
- package/src/SvGrid.types.ts +125 -1
- package/src/SvGridChartView.svelte +70 -0
- package/src/SvGridDropdown.svelte +9 -2
- package/src/SvGridSelect.svelte +5 -2
- package/src/SvGroup.svelte +41 -0
- package/src/SvHoverCard.svelte +70 -0
- package/src/SvKbd.svelte +51 -0
- package/src/SvList.svelte +55 -0
- package/src/SvListBox.svelte +166 -77
- package/src/SvLoadingOverlay.svelte +53 -0
- package/src/SvMark.svelte +36 -0
- package/src/SvMaskedInput.svelte +50 -35
- package/src/SvMenuList.svelte +32 -3
- package/src/SvMenubar.svelte +200 -0
- package/src/SvMultiSelect.svelte +7 -4
- package/src/SvNumberInput.svelte +79 -42
- package/src/SvOtpInput.svelte +2 -2
- package/src/SvPasswordInput.svelte +51 -31
- package/src/SvPhoneInput.svelte +39 -28
- package/src/SvPopconfirm.svelte +79 -0
- package/src/SvPopover.svelte +87 -29
- package/src/SvRadioGroup.svelte +5 -1
- package/src/SvResult.svelte +73 -0
- package/src/SvSegmented.svelte +114 -0
- package/src/SvSimpleGrid.svelte +41 -0
- package/src/SvSlider.svelte +23 -10
- package/src/SvSpinner.svelte +43 -0
- package/src/SvStack.svelte +37 -0
- package/src/SvSwitchButton.svelte +6 -1
- package/src/SvTagsInput.svelte +9 -5
- package/src/SvText.svelte +76 -0
- package/src/SvTextInput.svelte +75 -43
- package/src/SvTimePicker.svelte +32 -2
- package/src/SvTitle.svelte +57 -0
- package/src/SvToaster.svelte +41 -6
- package/src/SvToaster.test.ts +32 -0
- package/src/SvToggleButton.svelte +4 -1
- package/src/SvTooltip.svelte +68 -34
- package/src/SvTree.svelte +81 -21
- package/src/SvTreeSelect.svelte +5 -2
- package/src/SvVisuallyHidden.svelte +49 -0
- package/src/ai.test.ts +502 -0
- package/src/ai.ts +1391 -0
- package/src/board-view.svelte.ts +33 -0
- package/src/build-api.coverage.test.ts +101 -0
- package/src/build-api.ts +43 -18
- package/src/builtin-editors.grid.test.ts +1 -1
- package/src/cell-formatting.ts +5 -5
- package/src/cell-render.ts +4 -4
- package/src/chart-view.svelte.ts +36 -0
- package/src/createCombobox.svelte.ts +17 -5
- package/src/createDropdownList.svelte.ts +8 -2
- package/src/createForm.svelte.ts +59 -6
- package/src/createMenu.svelte.ts +23 -0
- package/src/createPopoverSelect.svelte.ts +8 -1
- package/src/createSlider.svelte.ts +20 -0
- package/src/createTooltip.svelte.ts +67 -9
- package/src/editor-contract.ts +16 -0
- package/src/export-provider.ts +40 -0
- package/src/filter-operators.ts +37 -0
- package/src/form-field.ts +42 -2
- package/src/grid-messages.test.ts +24 -0
- package/src/grid-messages.ts +137 -0
- package/src/group-display.test.ts +77 -0
- package/src/group-display.ts +117 -0
- package/src/i18n.grid.test.ts +73 -0
- package/src/index.ts +91 -2
- package/src/js-scroller.svelte.ts +173 -0
- package/src/list-option.test.ts +56 -0
- package/src/list-option.ts +81 -0
- package/src/menus.test.ts +32 -0
- package/src/menus.ts +25 -12
- package/src/pivot-view.svelte.ts +90 -0
- package/src/pivot-view.test.ts +38 -0
- package/src/pivot.grid.test.ts +102 -0
- package/src/positioning.test.ts +141 -0
- package/src/positioning.ts +266 -0
- package/src/scheduler-model.test.ts +16 -0
- package/src/scheduler-model.ts +24 -5
- package/src/svgrid-wrapper.types.ts +23 -0
- package/src/svgrid.charting.test.ts +8 -1
- package/src/svgrid.comments-autocomplete.test.ts +7 -2
- package/src/svgrid.context-menu.test.ts +8 -3
- package/src/toast-store.svelte.ts +98 -0
- package/src/toast-store.test.ts +62 -1
- package/src/ui-breadth.test.ts +138 -0
- package/src/ui-buttons.test.ts +39 -0
- package/src/ui-inputs.test.ts +2 -2
- package/src/ui-range.test.ts +9 -0
- package/src/ui-selection.test.ts +36 -0
- package/src/ui-tier1.test.ts +1 -1
- package/src/virtual.test.ts +20 -6
- package/dist/SvGridBoard.svelte +0 -2339
- package/dist/SvGridBoard.svelte.d.ts +0 -31
- package/src/SvGridBoard.svelte +0 -2339
- package/src/board.test.ts +0 -927
|
@@ -5,6 +5,14 @@ export type TooltipConfig = {
|
|
|
5
5
|
disabled?: () => boolean;
|
|
6
6
|
/** Show delay in ms after hover/focus. Default 300. */
|
|
7
7
|
delay?: () => number;
|
|
8
|
+
/** Hide delay in ms after leave/blur. Default 0. Give it room for interactive tips. */
|
|
9
|
+
closeDelay?: () => number;
|
|
10
|
+
/**
|
|
11
|
+
* Delay-group id. Tooltips sharing a group open INSTANTLY while any group
|
|
12
|
+
* member is open or was open within a short grace window - so scanning a
|
|
13
|
+
* toolbar of icon buttons does not re-wait the show delay each time.
|
|
14
|
+
*/
|
|
15
|
+
group?: () => string | undefined;
|
|
8
16
|
};
|
|
9
17
|
export type TooltipAnchorProps = {
|
|
10
18
|
'aria-describedby': string | undefined;
|
|
@@ -23,6 +31,10 @@ export declare function createTooltip(config?: TooltipConfig): {
|
|
|
23
31
|
tipId: string;
|
|
24
32
|
show: () => void;
|
|
25
33
|
hide: () => void;
|
|
34
|
+
/** Keep an interactive tip open while the pointer is over it. */
|
|
35
|
+
keepOpen: () => void;
|
|
36
|
+
/** Delayed hide honoring `closeDelay` (pointer/focus leave). */
|
|
37
|
+
scheduleHide: () => void;
|
|
26
38
|
/** Spread onto the anchor/trigger wrapper. Also mirror `tipId` onto the real
|
|
27
39
|
* focusable child's `aria-describedby` so AT announces it on focus. */
|
|
28
40
|
anchorProps: () => TooltipAnchorProps;
|
|
@@ -1,9 +1,10 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* createTooltip - the HEADLESS core behind <SvTooltip>: the hover/focus open
|
|
3
|
-
* state machine with a show delay,
|
|
4
|
-
*
|
|
5
|
-
*
|
|
6
|
-
*
|
|
3
|
+
* state machine with a show delay, an optional close delay, a shared delay-group
|
|
4
|
+
* (so moving between grouped tooltips skips the re-delay), Escape-to-hide, and the
|
|
5
|
+
* `aria-describedby` / `role="tooltip"` wiring - as prop-getters you spread onto
|
|
6
|
+
* your own anchor and tooltip elements. No styles, no positioning (that is a DOM
|
|
7
|
+
* concern the renderer owns), like `createListbox`.
|
|
7
8
|
*
|
|
8
9
|
* ```svelte
|
|
9
10
|
* <script lang="ts">
|
|
@@ -17,20 +18,78 @@
|
|
|
17
18
|
* ```
|
|
18
19
|
*/
|
|
19
20
|
import { nextEditorId } from './editor-contract';
|
|
21
|
+
/** Grace window (ms) after a group tooltip closes during which the next opens instantly. */
|
|
22
|
+
const GROUP_SKIP_WINDOW = 300;
|
|
23
|
+
const groupRegistry = new Map();
|
|
24
|
+
function groupEntry(id) {
|
|
25
|
+
let e = groupRegistry.get(id);
|
|
26
|
+
if (!e) {
|
|
27
|
+
e = { openCount: 0, lastCloseAt: 0 };
|
|
28
|
+
groupRegistry.set(id, e);
|
|
29
|
+
}
|
|
30
|
+
return e;
|
|
31
|
+
}
|
|
32
|
+
const now = () => (typeof Date !== 'undefined' ? Date.now() : 0);
|
|
20
33
|
export function createTooltip(config = {}) {
|
|
21
34
|
const id = nextEditorId('sv-tip');
|
|
22
35
|
let open = $state(false);
|
|
23
36
|
let showTimer;
|
|
37
|
+
let hideTimer;
|
|
38
|
+
let counted = false; // whether this instance is currently counted in its group
|
|
39
|
+
function groupId() { return config.group?.(); }
|
|
40
|
+
/** Effective show delay: 0 when the group is warm (a member open / just closed). */
|
|
41
|
+
function effectiveDelay() {
|
|
42
|
+
const base = config.delay?.() ?? 300;
|
|
43
|
+
const g = groupId();
|
|
44
|
+
if (!g)
|
|
45
|
+
return base;
|
|
46
|
+
const e = groupEntry(g);
|
|
47
|
+
if (e.openCount > 0 || now() - e.lastCloseAt < GROUP_SKIP_WINDOW)
|
|
48
|
+
return 0;
|
|
49
|
+
return base;
|
|
50
|
+
}
|
|
51
|
+
function markOpen() {
|
|
52
|
+
open = true;
|
|
53
|
+
const g = groupId();
|
|
54
|
+
if (g && !counted) {
|
|
55
|
+
counted = true;
|
|
56
|
+
groupEntry(g).openCount++;
|
|
57
|
+
}
|
|
58
|
+
}
|
|
59
|
+
function reallyHide() {
|
|
60
|
+
open = false;
|
|
61
|
+
clearTimeout(showTimer);
|
|
62
|
+
clearTimeout(hideTimer);
|
|
63
|
+
const g = groupId();
|
|
64
|
+
if (g && counted) {
|
|
65
|
+
counted = false;
|
|
66
|
+
const e = groupEntry(g);
|
|
67
|
+
e.openCount--;
|
|
68
|
+
e.lastCloseAt = now();
|
|
69
|
+
}
|
|
70
|
+
}
|
|
24
71
|
function show() {
|
|
25
72
|
if ((config.disabled?.() ?? false) || !(config.text?.() ?? ''))
|
|
26
73
|
return;
|
|
74
|
+
clearTimeout(hideTimer);
|
|
75
|
+
if (open)
|
|
76
|
+
return;
|
|
27
77
|
clearTimeout(showTimer);
|
|
28
|
-
showTimer = setTimeout(
|
|
78
|
+
showTimer = setTimeout(markOpen, effectiveDelay());
|
|
29
79
|
}
|
|
30
|
-
|
|
80
|
+
/** Delayed hide (honors `closeDelay`) - used by pointer/focus leave. */
|
|
81
|
+
function scheduleHide() {
|
|
31
82
|
clearTimeout(showTimer);
|
|
32
|
-
|
|
83
|
+
const cd = config.closeDelay?.() ?? 0;
|
|
84
|
+
if (cd > 0 && open) {
|
|
85
|
+
clearTimeout(hideTimer);
|
|
86
|
+
hideTimer = setTimeout(reallyHide, cd);
|
|
87
|
+
}
|
|
88
|
+
else
|
|
89
|
+
reallyHide();
|
|
33
90
|
}
|
|
91
|
+
/** Immediate hide - used by Escape and imperative callers. */
|
|
92
|
+
function hide() { reallyHide(); }
|
|
34
93
|
// Escape hides the tooltip while it is open (WAI-ARIA tooltip pattern).
|
|
35
94
|
$effect(() => {
|
|
36
95
|
if (!open)
|
|
@@ -46,14 +105,18 @@ export function createTooltip(config = {}) {
|
|
|
46
105
|
tipId: id,
|
|
47
106
|
show,
|
|
48
107
|
hide,
|
|
108
|
+
/** Keep an interactive tip open while the pointer is over it. */
|
|
109
|
+
keepOpen: show,
|
|
110
|
+
/** Delayed hide honoring `closeDelay` (pointer/focus leave). */
|
|
111
|
+
scheduleHide,
|
|
49
112
|
/** Spread onto the anchor/trigger wrapper. Also mirror `tipId` onto the real
|
|
50
113
|
* focusable child's `aria-describedby` so AT announces it on focus. */
|
|
51
114
|
anchorProps: () => ({
|
|
52
115
|
'aria-describedby': open ? id : undefined,
|
|
53
116
|
onpointerenter: show,
|
|
54
|
-
onpointerleave:
|
|
117
|
+
onpointerleave: scheduleHide,
|
|
55
118
|
onfocusin: show,
|
|
56
|
-
onfocusout:
|
|
119
|
+
onfocusout: scheduleHide,
|
|
57
120
|
}),
|
|
58
121
|
/** Spread onto the tooltip element. */
|
|
59
122
|
tooltipProps: () => ({ id, role: 'tooltip' }),
|
|
@@ -10,6 +10,21 @@
|
|
|
10
10
|
* Framework-free (no Svelte, no DOM) so it can be unit-tested and reused.
|
|
11
11
|
*/
|
|
12
12
|
export type EditorSize = 'sm' | 'md' | 'lg';
|
|
13
|
+
/**
|
|
14
|
+
* A small action button rendered inside a framed field (via `SvField`'s
|
|
15
|
+
* `actions`) - the generalized form of the clear / reveal buttons, for a lookup,
|
|
16
|
+
* a generate, a copy, etc. `icon` is a Svelte snippet; when absent the `label`
|
|
17
|
+
* text is shown. (Type-only Svelte import, so this module stays runtime-free.)
|
|
18
|
+
*/
|
|
19
|
+
export type EditorAction = {
|
|
20
|
+
/** Accessible name + tooltip for the button. */
|
|
21
|
+
label: string;
|
|
22
|
+
/** Invoked when the button is pressed. */
|
|
23
|
+
onClick: () => void;
|
|
24
|
+
/** Optional icon snippet; falls back to the `label` text. */
|
|
25
|
+
icon?: import('svelte').Snippet;
|
|
26
|
+
disabled?: boolean;
|
|
27
|
+
};
|
|
13
28
|
/** Text direction. `'auto'` defers to the surrounding document/CSS. */
|
|
14
29
|
export type EditorDir = 'ltr' | 'rtl' | 'auto';
|
|
15
30
|
/** Props shared by every value-bearing editor in the kit. */
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* export-provider seam. The free grid ships built-in text export (CSV / TSV /
|
|
3
|
+
* JSON via the api) but the rich Excel / PDF / HTML export engine lives in
|
|
4
|
+
* `@svgrid/enterprise`. `aiExport` (a free, built-in AI feature) plans an export
|
|
5
|
+
* and, when it needs to actually WRITE an enterprise format, delegates to the
|
|
6
|
+
* engine registered here. Enterprise registers `exportGrid` at install time; if
|
|
7
|
+
* it is absent, `aiExport` returns the plan without running the download.
|
|
8
|
+
*
|
|
9
|
+
* ```ts
|
|
10
|
+
* // in @svgrid/enterprise, at install:
|
|
11
|
+
* import { registerExportProvider } from '@svgrid/grid'
|
|
12
|
+
* import { exportGrid } from './export'
|
|
13
|
+
* registerExportProvider(exportGrid)
|
|
14
|
+
* ```
|
|
15
|
+
*/
|
|
16
|
+
import type { SvGridApi } from './index';
|
|
17
|
+
export type GridExportRunOptions = {
|
|
18
|
+
format: string;
|
|
19
|
+
filename?: string;
|
|
20
|
+
rows?: ReadonlyArray<Record<string, unknown>>;
|
|
21
|
+
groupBy?: string[];
|
|
22
|
+
};
|
|
23
|
+
export type GridExportProvider = (api: SvGridApi<any, any>, opts: GridExportRunOptions) => Promise<unknown>;
|
|
24
|
+
/** Register the export engine that runs AI-planned exports. Enterprise calls this. */
|
|
25
|
+
export declare function registerExportProvider(fn: GridExportProvider | null): void;
|
|
26
|
+
/** The registered export engine, or null when @svgrid/enterprise is not installed. */
|
|
27
|
+
export declare function getExportProvider(): GridExportProvider | null;
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
let provider = null;
|
|
2
|
+
/** Register the export engine that runs AI-planned exports. Enterprise calls this. */
|
|
3
|
+
export function registerExportProvider(fn) {
|
|
4
|
+
provider = fn;
|
|
5
|
+
}
|
|
6
|
+
/** The registered export engine, or null when @svgrid/enterprise is not installed. */
|
|
7
|
+
export function getExportProvider() {
|
|
8
|
+
return provider;
|
|
9
|
+
}
|
|
@@ -20,3 +20,9 @@ export declare function operatorsForColumn<TData extends RowData>(column: Column
|
|
|
20
20
|
export declare function defaultOperatorFor<TData extends RowData>(column: Column<TData> | undefined): FilterOperator;
|
|
21
21
|
/** Date columns get friendlier labels for "less / greater than". */
|
|
22
22
|
export declare function operatorLabelFor<TData extends RowData>(option: FilterOption, column: Column<TData> | undefined): string;
|
|
23
|
+
/**
|
|
24
|
+
* Localized operator label: honors date `Before`/`After` relabels, then the
|
|
25
|
+
* `localeText` override for the operator, falling back to the English
|
|
26
|
+
* `option.label`. `messages` is a loose string map to avoid a type cycle.
|
|
27
|
+
*/
|
|
28
|
+
export declare function localizeOperatorLabel<TData extends RowData>(option: FilterOption, column: Column<TData> | undefined, messages?: Record<string, string> | null): string;
|
package/dist/filter-operators.js
CHANGED
|
@@ -100,3 +100,36 @@ export function operatorLabelFor(option, column) {
|
|
|
100
100
|
}
|
|
101
101
|
return option.label;
|
|
102
102
|
}
|
|
103
|
+
/** GridMessages key for each operator's label (see grid-messages.ts). */
|
|
104
|
+
const OPERATOR_MESSAGE_KEY = {
|
|
105
|
+
contains: "opContains",
|
|
106
|
+
notContains: "opNotContains",
|
|
107
|
+
equals: "opEquals",
|
|
108
|
+
notEquals: "opNotEquals",
|
|
109
|
+
startsWith: "opStartsWith",
|
|
110
|
+
endsWith: "opEndsWith",
|
|
111
|
+
regex: "opRegex",
|
|
112
|
+
in: "opIn",
|
|
113
|
+
notIn: "opNotIn",
|
|
114
|
+
greaterThan: "opGreaterThan",
|
|
115
|
+
lessThan: "opLessThan",
|
|
116
|
+
between: "opBetween",
|
|
117
|
+
isBlank: "opIsBlank",
|
|
118
|
+
isNotBlank: "opIsNotBlank",
|
|
119
|
+
};
|
|
120
|
+
/**
|
|
121
|
+
* Localized operator label: honors date `Before`/`After` relabels, then the
|
|
122
|
+
* `localeText` override for the operator, falling back to the English
|
|
123
|
+
* `option.label`. `messages` is a loose string map to avoid a type cycle.
|
|
124
|
+
*/
|
|
125
|
+
export function localizeOperatorLabel(option, column, messages) {
|
|
126
|
+
const editorType = column?.columnDef.editorType;
|
|
127
|
+
if (editorType === "date" || editorType === "datetime") {
|
|
128
|
+
if (option.value === "lessThan")
|
|
129
|
+
return messages?.opBefore || "Before";
|
|
130
|
+
if (option.value === "greaterThan")
|
|
131
|
+
return messages?.opAfter || "After";
|
|
132
|
+
}
|
|
133
|
+
const key = OPERATOR_MESSAGE_KEY[option.value];
|
|
134
|
+
return (key && messages?.[key]) || option.label;
|
|
135
|
+
}
|
package/dist/form-field.d.ts
CHANGED
|
@@ -5,18 +5,59 @@ import type { Validator } from './validators';
|
|
|
5
5
|
* `.svelte` component (which would create a `.svelte.ts` -> `.svelte` import
|
|
6
6
|
* cycle Vite's dev import-analysis fails to resolve).
|
|
7
7
|
*/
|
|
8
|
-
export type FormFieldType = 'text' | 'email' | 'tel' | 'textarea' | 'number' | 'password' | 'select' | 'checkbox' | 'switch' | 'date' | 'color' | 'rating' | 'array';
|
|
8
|
+
export type FormFieldType = 'text' | 'email' | 'tel' | 'textarea' | 'number' | 'password' | 'select' | 'multiselect' | 'checkbox' | 'switch' | 'date' | 'color' | 'rating' | 'radio' | 'slider' | 'tags' | 'phone' | 'country' | 'mask' | 'datetime' | 'time' | 'daterange' | 'combobox' | 'file' | 'array';
|
|
9
9
|
export type FormField = {
|
|
10
10
|
name: string;
|
|
11
11
|
label: string;
|
|
12
12
|
type?: FormFieldType;
|
|
13
13
|
required?: boolean;
|
|
14
|
+
/** Show the field but block edits (still submitted, unlike hidden fields). */
|
|
15
|
+
readonly?: boolean;
|
|
16
|
+
/** Helper text shown under the control (distinct from a validation error). */
|
|
17
|
+
help?: string;
|
|
14
18
|
placeholder?: string;
|
|
19
|
+
/**
|
|
20
|
+
* Options for select/combobox/radio/multiselect. A function makes them CASCADE:
|
|
21
|
+
* the list is derived from the current form values (e.g. cities for the picked
|
|
22
|
+
* country). Pair with `dependsOn` so the child clears when the parent changes.
|
|
23
|
+
*/
|
|
15
24
|
options?: Array<{
|
|
16
25
|
value: string | number;
|
|
17
26
|
label: string;
|
|
18
27
|
color?: string;
|
|
19
|
-
}
|
|
28
|
+
}> | ((values: Record<string, any>) => Array<{
|
|
29
|
+
value: string | number;
|
|
30
|
+
label: string;
|
|
31
|
+
color?: string;
|
|
32
|
+
}>);
|
|
33
|
+
/** Field name(s) this one depends on; when a parent changes, this field's value
|
|
34
|
+
* is cleared (cascading selects). */
|
|
35
|
+
dependsOn?: string | string[];
|
|
36
|
+
/** Mask pattern for `type: 'mask'` (`#`=digit, `A`=letter, `*`=alnum). */
|
|
37
|
+
mask?: string;
|
|
38
|
+
/** Numeric bounds for `type: 'number'` / `'slider'`. */
|
|
39
|
+
min?: number;
|
|
40
|
+
max?: number;
|
|
41
|
+
step?: number;
|
|
42
|
+
precision?: number;
|
|
43
|
+
/** Text affixes for `type: 'number'` (e.g. `$` / `%`). */
|
|
44
|
+
prefix?: string;
|
|
45
|
+
suffix?: string;
|
|
46
|
+
/** Remote option loader for `type: 'combobox'` (debounced typeahead). The
|
|
47
|
+
* current form `values` are passed so it can depend on other fields. */
|
|
48
|
+
loadOptions?: (query: string, values: Record<string, any>) => Promise<Array<{
|
|
49
|
+
value: string | number;
|
|
50
|
+
label: string;
|
|
51
|
+
}>>;
|
|
52
|
+
/** File input hints for `type: 'file'`. */
|
|
53
|
+
accept?: string;
|
|
54
|
+
multiple?: boolean;
|
|
55
|
+
/**
|
|
56
|
+
* Derive this field's value from the other form values (e.g. a total). A
|
|
57
|
+
* computed field is read-only, recomputes reactively, is not user-validated,
|
|
58
|
+
* and its derived value is included in the submitted payload.
|
|
59
|
+
*/
|
|
60
|
+
computed?: (values: Record<string, any>) => any;
|
|
20
61
|
/** Declarative validation rules (see `rules` - email/pattern/min/compare...). */
|
|
21
62
|
rules?: ReadonlyArray<Validator>;
|
|
22
63
|
/** Return an error message, or null/undefined when valid. */
|
|
@@ -32,6 +73,8 @@ export type FormField = {
|
|
|
32
73
|
asyncDebounce?: number;
|
|
33
74
|
/** Span full width in the grid. */
|
|
34
75
|
full?: boolean;
|
|
76
|
+
/** Columns to span (generalizes `full`); `2`+ widens the field in a grid. */
|
|
77
|
+
span?: number;
|
|
35
78
|
/**
|
|
36
79
|
* Show the field only when this is `true` / returns `true` (default: always).
|
|
37
80
|
* A field derived from other values, e.g. `visible: (v) => v.hasAddress`.
|
|
@@ -0,0 +1,61 @@
|
|
|
1
|
+
/** Every localizable chrome string, grouped by area in the comments. */
|
|
2
|
+
export type GridMessages = {
|
|
3
|
+
noRows: string;
|
|
4
|
+
loading: string;
|
|
5
|
+
columns: string;
|
|
6
|
+
filters: string;
|
|
7
|
+
clearFilter: string;
|
|
8
|
+
pageSize: string;
|
|
9
|
+
page: string;
|
|
10
|
+
of: string;
|
|
11
|
+
firstPage: string;
|
|
12
|
+
prevPage: string;
|
|
13
|
+
nextPage: string;
|
|
14
|
+
lastPage: string;
|
|
15
|
+
statCount: string;
|
|
16
|
+
statSum: string;
|
|
17
|
+
statAvg: string;
|
|
18
|
+
statMin: string;
|
|
19
|
+
statMax: string;
|
|
20
|
+
group: string;
|
|
21
|
+
grandTotal: string;
|
|
22
|
+
total: string;
|
|
23
|
+
rowsSuffix: string;
|
|
24
|
+
rowSuffix: string;
|
|
25
|
+
opContains: string;
|
|
26
|
+
opNotContains: string;
|
|
27
|
+
opEquals: string;
|
|
28
|
+
opNotEquals: string;
|
|
29
|
+
opStartsWith: string;
|
|
30
|
+
opEndsWith: string;
|
|
31
|
+
opRegex: string;
|
|
32
|
+
opIn: string;
|
|
33
|
+
opNotIn: string;
|
|
34
|
+
opGreaterThan: string;
|
|
35
|
+
opLessThan: string;
|
|
36
|
+
opBetween: string;
|
|
37
|
+
opIsBlank: string;
|
|
38
|
+
opIsNotBlank: string;
|
|
39
|
+
opBefore: string;
|
|
40
|
+
opAfter: string;
|
|
41
|
+
menuCopy: string;
|
|
42
|
+
menuCut: string;
|
|
43
|
+
menuPaste: string;
|
|
44
|
+
menuClear: string;
|
|
45
|
+
menuInsertRowAbove: string;
|
|
46
|
+
menuInsertRowBelow: string;
|
|
47
|
+
menuRemoveRow: string;
|
|
48
|
+
menuRemoveColumn: string;
|
|
49
|
+
menuEditComment: string;
|
|
50
|
+
chartRange: string;
|
|
51
|
+
pivotUpsellTitle: string;
|
|
52
|
+
pivotUpsellBody: string;
|
|
53
|
+
};
|
|
54
|
+
/** English defaults - the literal strings the grid shipped before localization. */
|
|
55
|
+
export declare const defaultGridMessages: GridMessages;
|
|
56
|
+
/**
|
|
57
|
+
* Merge a consumer's `localeText` over the English defaults. Undefined/empty
|
|
58
|
+
* values fall back to the default (via `resolveMessages`), so a partial map only
|
|
59
|
+
* replaces the keys it sets.
|
|
60
|
+
*/
|
|
61
|
+
export declare function resolveGridMessages(overrides?: Partial<GridMessages> | null): GridMessages;
|
|
@@ -0,0 +1,72 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Grid chrome localization. Every user-visible UI string the grid renders itself
|
|
3
|
+
* (empty state, tool panel, pager, status bar, group labels, filter operators,
|
|
4
|
+
* context-menu items, upsell notes) lives here as a flat message map with English
|
|
5
|
+
* defaults. Pass `localeText` on `<SvGrid>` to override any subset; unset keys
|
|
6
|
+
* fall back to English, so omitting `localeText` is a no-op.
|
|
7
|
+
*
|
|
8
|
+
* This mirrors the editor kit's `resolveMessages` pattern (editor-contract.ts) so
|
|
9
|
+
* chrome and editors share one localization idiom.
|
|
10
|
+
*/
|
|
11
|
+
import { resolveMessages } from './editor-contract';
|
|
12
|
+
/** English defaults - the literal strings the grid shipped before localization. */
|
|
13
|
+
export const defaultGridMessages = {
|
|
14
|
+
noRows: 'No rows to display.',
|
|
15
|
+
loading: 'Loading grid data...',
|
|
16
|
+
columns: 'Columns',
|
|
17
|
+
filters: 'Filters',
|
|
18
|
+
clearFilter: 'Clear filter',
|
|
19
|
+
pageSize: 'Page Size:',
|
|
20
|
+
page: 'Page',
|
|
21
|
+
of: 'of',
|
|
22
|
+
firstPage: 'First page',
|
|
23
|
+
prevPage: 'Previous page',
|
|
24
|
+
nextPage: 'Next page',
|
|
25
|
+
lastPage: 'Last page',
|
|
26
|
+
statCount: 'Count',
|
|
27
|
+
statSum: 'Sum',
|
|
28
|
+
statAvg: 'Avg',
|
|
29
|
+
statMin: 'Min',
|
|
30
|
+
statMax: 'Max',
|
|
31
|
+
group: 'Group',
|
|
32
|
+
grandTotal: 'Grand total',
|
|
33
|
+
total: 'Total',
|
|
34
|
+
rowsSuffix: 'rows',
|
|
35
|
+
rowSuffix: 'row',
|
|
36
|
+
menuCopy: 'Copy',
|
|
37
|
+
menuCut: 'Cut',
|
|
38
|
+
menuPaste: 'Paste',
|
|
39
|
+
menuClear: 'Clear',
|
|
40
|
+
menuInsertRowAbove: 'Insert row above',
|
|
41
|
+
menuInsertRowBelow: 'Insert row below',
|
|
42
|
+
menuRemoveRow: 'Remove row',
|
|
43
|
+
menuRemoveColumn: 'Remove column',
|
|
44
|
+
menuEditComment: 'Edit comment',
|
|
45
|
+
opContains: 'Contains',
|
|
46
|
+
opNotContains: 'Not contains',
|
|
47
|
+
opEquals: 'Equals',
|
|
48
|
+
opNotEquals: 'Not equals',
|
|
49
|
+
opStartsWith: 'Starts with',
|
|
50
|
+
opEndsWith: 'Ends with',
|
|
51
|
+
opRegex: 'Regex',
|
|
52
|
+
opIn: 'In',
|
|
53
|
+
opNotIn: 'Not in',
|
|
54
|
+
opGreaterThan: 'Greater than',
|
|
55
|
+
opLessThan: 'Less than',
|
|
56
|
+
opBetween: 'Between',
|
|
57
|
+
opIsBlank: 'Blank',
|
|
58
|
+
opIsNotBlank: 'Not blank',
|
|
59
|
+
opBefore: 'Before',
|
|
60
|
+
opAfter: 'After',
|
|
61
|
+
chartRange: 'Chart selected range',
|
|
62
|
+
pivotUpsellTitle: 'Pivot mode',
|
|
63
|
+
pivotUpsellBody: 'Pivot mode is an Enterprise feature. Install @svgrid/enterprise and call enablePivot() to use it.',
|
|
64
|
+
};
|
|
65
|
+
/**
|
|
66
|
+
* Merge a consumer's `localeText` over the English defaults. Undefined/empty
|
|
67
|
+
* values fall back to the default (via `resolveMessages`), so a partial map only
|
|
68
|
+
* replaces the keys it sets.
|
|
69
|
+
*/
|
|
70
|
+
export function resolveGridMessages(overrides) {
|
|
71
|
+
return resolveMessages(defaultGridMessages, overrides);
|
|
72
|
+
}
|
|
@@ -0,0 +1,62 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Row-grouping display helpers. Two pure, framework-free transforms:
|
|
3
|
+
*
|
|
4
|
+
* - `insertGroupFooters` inserts a footer/total row after each group's children
|
|
5
|
+
* (and optionally a grand-total row at the end), carrying the group's already
|
|
6
|
+
* computed aggregate values. Mirrors the server model's footer shape
|
|
7
|
+
* (`server-group-model.ts`) client-side.
|
|
8
|
+
* - `buildAutoGroupColumns` decides, for a grouping display mode, which synthetic
|
|
9
|
+
* "auto group" columns to show and which grouped source columns to hide - the
|
|
10
|
+
* groundwork for `singleColumn` / `multipleColumns` display types (the current
|
|
11
|
+
* default `groupRows` renders a full-width banner and needs neither).
|
|
12
|
+
*
|
|
13
|
+
* Both are generic over the row / column shape (via small accessor callbacks) so
|
|
14
|
+
* they are trivially unit-testable and carry no dependency on the grid runtime.
|
|
15
|
+
*/
|
|
16
|
+
/** AG-Grid-style grouping display variants. */
|
|
17
|
+
export type GroupDisplayType = 'groupRows' | 'singleColumn' | 'multipleColumns';
|
|
18
|
+
export type GroupFooterOptions<R> = {
|
|
19
|
+
/** Depth of a row (group rows and their descendants). */
|
|
20
|
+
getDepth: (row: R) => number;
|
|
21
|
+
/** True when a row is a group (banner) row. */
|
|
22
|
+
isGroup: (row: R) => boolean;
|
|
23
|
+
/** Build a footer row from the group row it closes (carries its aggregates). */
|
|
24
|
+
makeFooter: (groupRow: R) => R;
|
|
25
|
+
/** Insert a footer after each group's children. */
|
|
26
|
+
includeGroupFooter?: boolean;
|
|
27
|
+
/** Append a grand-total footer at the very end. */
|
|
28
|
+
includeGrandTotalFooter?: boolean;
|
|
29
|
+
/** Build the grand-total footer (over the whole set). Return null to skip. */
|
|
30
|
+
makeGrandTotal?: () => R | null;
|
|
31
|
+
};
|
|
32
|
+
/**
|
|
33
|
+
* Insert group footer rows after each group's descendants. A group opened at
|
|
34
|
+
* depth d closes when a later row appears at depth <= d (a sibling group or an
|
|
35
|
+
* ancestor-level row); its footer is emitted at that point. Order is otherwise
|
|
36
|
+
* preserved. No-op when neither footer flag is set.
|
|
37
|
+
*/
|
|
38
|
+
export declare function insertGroupFooters<R>(rows: ReadonlyArray<R>, opts: GroupFooterOptions<R>): R[];
|
|
39
|
+
export type AutoGroupColumnSpec = {
|
|
40
|
+
/** Synthetic column id (e.g. `__autoGroup` or `__group_<field>`). */
|
|
41
|
+
id: string;
|
|
42
|
+
/** The grouped field this auto column stands in for (null for the single
|
|
43
|
+
* combined auto-group column). */
|
|
44
|
+
field: string | null;
|
|
45
|
+
/** Nesting level this column represents (0-based), for indentation. */
|
|
46
|
+
level: number;
|
|
47
|
+
};
|
|
48
|
+
export type AutoGroupResult = {
|
|
49
|
+
/** Synthetic auto-group column specs to prepend to the visible columns. */
|
|
50
|
+
autoColumns: AutoGroupColumnSpec[];
|
|
51
|
+
/** Ids of the grouped SOURCE columns to hide (rolled into the auto columns). */
|
|
52
|
+
hiddenSourceIds: Set<string>;
|
|
53
|
+
};
|
|
54
|
+
/**
|
|
55
|
+
* Decide the synthetic auto-group columns for a grouping display mode:
|
|
56
|
+
* - `groupRows`: none (the banner path handles display) - `{ [], {} }`.
|
|
57
|
+
* - `singleColumn`: one combined auto-group column; every grouped source column
|
|
58
|
+
* is hidden.
|
|
59
|
+
* - `multipleColumns`: one auto column per grouped field; the grouped source
|
|
60
|
+
* columns are hidden.
|
|
61
|
+
*/
|
|
62
|
+
export declare function buildAutoGroupColumns(grouping: ReadonlyArray<string>, displayType: GroupDisplayType): AutoGroupResult;
|
|
@@ -0,0 +1,78 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Row-grouping display helpers. Two pure, framework-free transforms:
|
|
3
|
+
*
|
|
4
|
+
* - `insertGroupFooters` inserts a footer/total row after each group's children
|
|
5
|
+
* (and optionally a grand-total row at the end), carrying the group's already
|
|
6
|
+
* computed aggregate values. Mirrors the server model's footer shape
|
|
7
|
+
* (`server-group-model.ts`) client-side.
|
|
8
|
+
* - `buildAutoGroupColumns` decides, for a grouping display mode, which synthetic
|
|
9
|
+
* "auto group" columns to show and which grouped source columns to hide - the
|
|
10
|
+
* groundwork for `singleColumn` / `multipleColumns` display types (the current
|
|
11
|
+
* default `groupRows` renders a full-width banner and needs neither).
|
|
12
|
+
*
|
|
13
|
+
* Both are generic over the row / column shape (via small accessor callbacks) so
|
|
14
|
+
* they are trivially unit-testable and carry no dependency on the grid runtime.
|
|
15
|
+
*/
|
|
16
|
+
/**
|
|
17
|
+
* Insert group footer rows after each group's descendants. A group opened at
|
|
18
|
+
* depth d closes when a later row appears at depth <= d (a sibling group or an
|
|
19
|
+
* ancestor-level row); its footer is emitted at that point. Order is otherwise
|
|
20
|
+
* preserved. No-op when neither footer flag is set.
|
|
21
|
+
*/
|
|
22
|
+
export function insertGroupFooters(rows, opts) {
|
|
23
|
+
const { getDepth, isGroup, makeFooter, includeGroupFooter, includeGrandTotalFooter, makeGrandTotal } = opts;
|
|
24
|
+
if (!includeGroupFooter && !includeGrandTotalFooter)
|
|
25
|
+
return [...rows];
|
|
26
|
+
const out = [];
|
|
27
|
+
const openGroups = [];
|
|
28
|
+
const closeTo = (depth) => {
|
|
29
|
+
while (openGroups.length > 0) {
|
|
30
|
+
const top = openGroups[openGroups.length - 1];
|
|
31
|
+
if (getDepth(top) < depth)
|
|
32
|
+
break;
|
|
33
|
+
openGroups.pop();
|
|
34
|
+
if (includeGroupFooter)
|
|
35
|
+
out.push(makeFooter(top));
|
|
36
|
+
}
|
|
37
|
+
};
|
|
38
|
+
for (const row of rows) {
|
|
39
|
+
// Before adding this row, close any groups it ends (same-or-shallower depth).
|
|
40
|
+
closeTo(getDepth(row));
|
|
41
|
+
out.push(row);
|
|
42
|
+
if (isGroup(row))
|
|
43
|
+
openGroups.push(row);
|
|
44
|
+
}
|
|
45
|
+
// Close everything still open at the end.
|
|
46
|
+
closeTo(Number.NEGATIVE_INFINITY);
|
|
47
|
+
if (includeGrandTotalFooter && makeGrandTotal) {
|
|
48
|
+
const gt = makeGrandTotal();
|
|
49
|
+
if (gt != null)
|
|
50
|
+
out.push(gt);
|
|
51
|
+
}
|
|
52
|
+
return out;
|
|
53
|
+
}
|
|
54
|
+
/**
|
|
55
|
+
* Decide the synthetic auto-group columns for a grouping display mode:
|
|
56
|
+
* - `groupRows`: none (the banner path handles display) - `{ [], {} }`.
|
|
57
|
+
* - `singleColumn`: one combined auto-group column; every grouped source column
|
|
58
|
+
* is hidden.
|
|
59
|
+
* - `multipleColumns`: one auto column per grouped field; the grouped source
|
|
60
|
+
* columns are hidden.
|
|
61
|
+
*/
|
|
62
|
+
export function buildAutoGroupColumns(grouping, displayType) {
|
|
63
|
+
if (displayType === 'groupRows' || grouping.length === 0) {
|
|
64
|
+
return { autoColumns: [], hiddenSourceIds: new Set() };
|
|
65
|
+
}
|
|
66
|
+
const hiddenSourceIds = new Set(grouping);
|
|
67
|
+
if (displayType === 'singleColumn') {
|
|
68
|
+
return {
|
|
69
|
+
autoColumns: [{ id: '__autoGroup', field: null, level: 0 }],
|
|
70
|
+
hiddenSourceIds,
|
|
71
|
+
};
|
|
72
|
+
}
|
|
73
|
+
// multipleColumns
|
|
74
|
+
return {
|
|
75
|
+
autoColumns: grouping.map((field, level) => ({ id: `__group_${field}`, field, level })),
|
|
76
|
+
hiddenSourceIds,
|
|
77
|
+
};
|
|
78
|
+
}
|