@svgrid/grid 2.6.21 → 2.6.23
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 +62 -0
- package/README.md +22 -0
- package/dist/GridMenus.svelte +201 -18
- package/dist/SvAutoComplete.svelte +4 -0
- package/dist/SvComboBox.svelte +5 -1
- package/dist/SvDateRangeInput.svelte +25 -3
- package/dist/SvDropDownList.svelte +4 -0
- package/dist/SvForm.svelte +8 -8
- package/dist/SvGrid.controller.svelte.d.ts +61 -9
- package/dist/SvGrid.controller.svelte.js +363 -123
- package/dist/SvGrid.css +222 -1
- package/dist/SvGrid.helpers.d.ts +55 -0
- package/dist/SvGrid.helpers.js +83 -0
- package/dist/SvGrid.svelte +255 -56
- package/dist/SvGrid.types.d.ts +146 -1
- package/dist/SvGridCellEditor.svelte +99 -17
- package/dist/SvGridSelect.svelte +6 -2
- package/dist/SvGridSelect.svelte.d.ts +1 -1
- package/dist/SvListBox.svelte +8 -0
- package/dist/SvMultiSelect.svelte +6 -2
- package/dist/SvMultiSelect.svelte.d.ts +1 -1
- package/dist/SvNumberInput.svelte +4 -0
- package/dist/SvRichCell.svelte +125 -0
- package/dist/SvRichCell.svelte.d.ts +15 -0
- package/dist/SvTextArea.svelte +5 -1
- package/dist/SvTreeSelect.svelte +6 -2
- package/dist/SvTreeSelect.svelte.d.ts +1 -1
- package/dist/builtin-editors.d.ts +2 -2
- package/dist/builtin-editors.js +19 -3
- package/dist/cdn/GridMenus-BzWXQjv3.js +600 -0
- package/dist/cdn/GridMenus-xr_rHx8F.js +601 -0
- package/dist/cdn/SvDateRangeInput-CaOuMs8O.js +198 -0
- package/dist/cdn/SvDateRangeInput-DMLKmGEc.js +199 -0
- package/dist/cdn/SvDateTimePicker-CCbDZNZB.js +816 -0
- package/dist/cdn/SvDateTimePicker-sonaH0oh.js +812 -0
- package/dist/cdn/SvGridCellEditor-BAPSC7EL.js +550 -0
- package/dist/cdn/SvGridCellEditor-BwzmUWtL.js +549 -0
- package/dist/cdn/column-resize-DsfNXMom.js +102 -0
- package/dist/cdn/date-format-BNii4zeD.js +1393 -0
- package/dist/cdn/date-format-BnnHlqGw.js +1395 -0
- package/dist/cdn/{editor-registry-CiI0xlKg.js → editor-registry-BhgE3S84.js} +51 -25
- package/dist/cdn/row-resize-BRcimkUT.js +95 -0
- package/dist/cdn/{src-DBel9wRZ.js → src-DGo7IHug.js} +10017 -9488
- package/dist/cdn/{src-BYq-qyrp.js → src-skQN5eqh.js} +7829 -7300
- package/dist/cdn/svgrid.js +14 -10
- package/dist/cdn/svgrid.svelte-external.js +14 -10
- package/dist/cell-values.d.ts +16 -0
- package/dist/cell-values.js +28 -0
- package/dist/clipboard.d.ts +22 -0
- package/dist/clipboard.js +405 -27
- package/dist/column-groups.js +1 -1
- package/dist/column-resize.d.ts +46 -0
- package/dist/column-resize.js +205 -0
- package/dist/columns.d.ts +0 -3
- package/dist/columns.js +0 -57
- package/dist/core.d.ts +19 -4
- package/dist/core.js +460 -119
- package/dist/editing.js +12 -7
- package/dist/editors/cell-editors.d.ts +11 -0
- package/dist/editors/cell-editors.js +18 -1
- package/dist/filtering/excel-filters.js +28 -0
- package/dist/grid-messages.d.ts +15 -0
- package/dist/grid-messages.js +15 -0
- package/dist/group-display.d.ts +1 -1
- package/dist/index.d.ts +6 -1
- package/dist/index.js +10 -0
- package/dist/list-option.d.ts +6 -0
- package/dist/menus.js +41 -8
- package/dist/row-resize.d.ts +11 -0
- package/dist/row-resize.js +7 -1
- package/dist/sanitize-html.d.ts +37 -0
- package/dist/sanitize-html.js +234 -0
- package/dist/selection-bar-view.svelte.d.ts +25 -0
- package/dist/selection-bar-view.svelte.js +13 -0
- package/dist/selection.d.ts +2 -1
- package/dist/selection.js +133 -8
- package/dist/spreadsheet.d.ts +1 -1
- package/dist/spreadsheet.js +1 -1
- package/package.json +1 -1
- package/src/GridMenus.svelte +201 -18
- package/src/SvAutoComplete.svelte +4 -0
- package/src/SvComboBox.svelte +5 -1
- package/src/SvDateRangeInput.svelte +25 -3
- package/src/SvDropDownList.svelte +4 -0
- package/src/SvForm.svelte +8 -8
- package/src/SvGrid.controller.svelte.ts +404 -133
- package/src/SvGrid.css +222 -1
- package/src/SvGrid.helpers.ts +87 -0
- package/src/SvGrid.svelte +255 -56
- package/src/SvGrid.types.ts +153 -1
- package/src/SvGridCellEditor.svelte +99 -17
- package/src/SvGridSelect.svelte +6 -2
- package/src/SvListBox.svelte +8 -0
- package/src/SvMultiSelect.svelte +6 -2
- package/src/SvNumberInput.svelte +4 -0
- package/src/SvRichCell.svelte +125 -0
- package/src/SvTextArea.svelte +5 -1
- package/src/SvTreeSelect.svelte +6 -2
- package/src/builtin-editors.test.ts +18 -1
- package/src/builtin-editors.ts +19 -3
- package/src/cell-values.ts +30 -0
- package/src/clipboard.test.ts +93 -20
- package/src/clipboard.ts +433 -33
- package/src/column-groups.ts +1 -1
- package/src/column-resize.test.ts +381 -0
- package/src/column-resize.ts +227 -0
- package/src/columns.test.ts +0 -103
- package/src/columns.ts +0 -58
- package/src/core.aggregate.test.ts +134 -0
- package/src/core.filter.test.ts +156 -0
- package/src/core.grouping.test.ts +146 -0
- package/src/core.row-shape.test.ts +119 -0
- package/src/core.rowmodel-cache.test.ts +121 -0
- package/src/core.sort.test.ts +293 -0
- package/src/core.ts +516 -119
- package/src/date-string-column.test.ts +87 -0
- package/src/editing.test.ts +25 -0
- package/src/editing.ts +12 -9
- package/src/editor-block-prop.test.ts +132 -0
- package/src/editors/cell-editors.ts +27 -1
- package/src/filtering/excel-filters.ts +30 -0
- package/src/filtering/normalize-fast-path.test.ts +104 -0
- package/src/grid-messages.ts +34 -0
- package/src/group-display.ts +1 -1
- package/src/index.ts +25 -1
- package/src/list-option.ts +6 -0
- package/src/menus.test.ts +43 -0
- package/src/menus.ts +38 -8
- package/src/move-cells.test.ts +850 -0
- package/src/number-editor-literal.test.ts +84 -0
- package/src/number-editor.grid.test.ts +160 -0
- package/src/resize-props.test.ts +361 -0
- package/src/row-resize.test.ts +31 -0
- package/src/row-resize.ts +21 -3
- package/src/sanitize-html.test.ts +182 -0
- package/src/sanitize-html.ts +235 -0
- package/src/selection-bar-view.svelte.ts +36 -0
- package/src/selection.test.ts +157 -0
- package/src/selection.ts +135 -8
- package/src/spreadsheet.ts +1 -1
- package/src/svgrid.filter-menu-listbox.svelte.test.ts +56 -10
- package/src/svgrid.in-suggest-snapshot.svelte.test.ts +91 -0
- package/src/svgrid.menu-scroll-close.test.ts +204 -0
- package/src/svgrid.selection-bar-seam.test.ts +185 -0
- package/src/svgrid.upsell-license.test.ts +117 -0
- package/dist/cdn/GridMenus-BfTAKn84.js +0 -488
- package/dist/cdn/GridMenus-C3bJd7w8.js +0 -489
- package/dist/cdn/SvDateTimePicker-CHnUkWcH.js +0 -2206
- package/dist/cdn/SvDateTimePicker-CRQH_U7E.js +0 -2201
- package/dist/cdn/SvGridCellEditor-BGUCzuPB.js +0 -523
- package/dist/cdn/SvGridCellEditor-G8IMWIws.js +0 -522
package/dist/editing.js
CHANGED
|
@@ -5,7 +5,7 @@ import { parseEditorValue, } from "./index.js";
|
|
|
5
5
|
import "./sv-grid-scrollbar.js";
|
|
6
6
|
import { getNextActiveCell } from "./keyboard.js";
|
|
7
7
|
import { getCellKey, toValueArray, } from "./SvGrid.helpers.js";
|
|
8
|
-
import { getColumnBaseValue, isGroupRow, } from "./cell-values.js";
|
|
8
|
+
import { createDataIndexLookup, getColumnBaseValue, isGroupRow, } from "./cell-values.js";
|
|
9
9
|
export function createEditing(ctx) {
|
|
10
10
|
/**
|
|
11
11
|
* Resolve `columnDef.editable` for one row × column pair.
|
|
@@ -117,6 +117,8 @@ export function createEditing(ctx) {
|
|
|
117
117
|
const column = ctx.allColumns.find((entry) => entry.id === ctx.editingCell?.columnId);
|
|
118
118
|
const parsedValue = parseEditorValue(ctx.editingCell.editorType, ctx.editingCell.value, {
|
|
119
119
|
multiple: column?.columnDef.editorMultiple === true,
|
|
120
|
+
// A dateString column holds 'YYYY-MM-DD', not a timestamp.
|
|
121
|
+
dateOnly: column?.columnDef.cellDataType === "dateString",
|
|
120
122
|
});
|
|
121
123
|
let oldValue = undefined;
|
|
122
124
|
let finalValue = parsedValue;
|
|
@@ -378,16 +380,16 @@ export function createEditing(ctx) {
|
|
|
378
380
|
? endCol - startCol + 1
|
|
379
381
|
: Math.max(...lines.map((l) => l.split("\t").length));
|
|
380
382
|
const next = ctx.internalData.slice();
|
|
383
|
+
const dataIndexOf = createDataIndexLookup(next);
|
|
381
384
|
for (let i = 0; i < rowSpan; i += 1) {
|
|
382
385
|
const targetRowIndex = startRow + i;
|
|
383
386
|
const row = ctx.allRows[targetRowIndex];
|
|
384
387
|
if (!row || isGroupRow(row))
|
|
385
388
|
continue;
|
|
386
|
-
// Map the visible row back to its
|
|
387
|
-
|
|
388
|
-
|
|
389
|
-
|
|
390
|
-
dataIndex >= next.length)
|
|
389
|
+
// Map the visible row back to its slot in the data array by identity -
|
|
390
|
+
// `row.id` is only the index under the default getRowId.
|
|
391
|
+
const dataIndex = dataIndexOf(row);
|
|
392
|
+
if (dataIndex < 0)
|
|
391
393
|
continue;
|
|
392
394
|
const originalRow = next[dataIndex];
|
|
393
395
|
if (!originalRow)
|
|
@@ -407,7 +409,9 @@ export function createEditing(ctx) {
|
|
|
407
409
|
const editorType = (column.columnDef.editorType ??
|
|
408
410
|
"text");
|
|
409
411
|
const raw = fillRange ? lines[0] : sourceCells?.[j] ?? "";
|
|
410
|
-
updated[column.columnDef.field] = parseEditorValue(editorType, raw
|
|
412
|
+
updated[column.columnDef.field] = parseEditorValue(editorType, raw, {
|
|
413
|
+
dateOnly: column.columnDef.cellDataType === "dateString",
|
|
414
|
+
});
|
|
411
415
|
}
|
|
412
416
|
next[dataIndex] = updated;
|
|
413
417
|
}
|
|
@@ -496,6 +500,7 @@ export function createEditing(ctx) {
|
|
|
496
500
|
const editorType = (column.columnDef.editorType ?? "text");
|
|
497
501
|
const parsed = parseEditorValue(editorType, fr.draft[column.id], {
|
|
498
502
|
multiple: column.columnDef.editorMultiple === true,
|
|
503
|
+
dateOnly: column.columnDef.cellDataType === "dateString",
|
|
499
504
|
});
|
|
500
505
|
const oldValue = row.original[field];
|
|
501
506
|
const parser = column.columnDef.valueParser;
|
|
@@ -12,6 +12,17 @@ export type CellEditorOption = {
|
|
|
12
12
|
export type ParseEditorValueOptions = {
|
|
13
13
|
/** When true, list/chips return an array; otherwise a scalar. */
|
|
14
14
|
multiple?: boolean;
|
|
15
|
+
/**
|
|
16
|
+
* Keep a date as the plain `YYYY-MM-DD` string the user picked, instead of a
|
|
17
|
+
* full ISO timestamp. Set for `cellDataType: 'dateString'` columns, which
|
|
18
|
+
* exist precisely to hold ISO date strings.
|
|
19
|
+
*
|
|
20
|
+
* It is not only about shape. `new Date('2026-12-25').toISOString()` sends
|
|
21
|
+
* the value through UTC, so a local midnight becomes the previous or next
|
|
22
|
+
* day either side of the meridian - the stored DATE changes depending on
|
|
23
|
+
* where the user is sitting. Slicing the picked date avoids that entirely.
|
|
24
|
+
*/
|
|
25
|
+
dateOnly?: boolean;
|
|
15
26
|
};
|
|
16
27
|
/** Normalize the loose `editorOptions` ColumnDef prop into a uniform shape.
|
|
17
28
|
* Dynamic (function) editorOptions are resolved before reaching here. */
|
|
@@ -36,7 +36,24 @@ export function parseEditorValue(rawType, value, opts) {
|
|
|
36
36
|
return s || '#000000';
|
|
37
37
|
}
|
|
38
38
|
if (type === 'date') {
|
|
39
|
-
const
|
|
39
|
+
const raw = String(value ?? '');
|
|
40
|
+
if (opts?.dateOnly) {
|
|
41
|
+
// Take the calendar date the editor produced as-is. It already arrives
|
|
42
|
+
// as `YYYY-MM-DD` (or that prefix on a datetime), so there is nothing to
|
|
43
|
+
// convert - and converting is exactly what shifts the day across a
|
|
44
|
+
// timezone boundary.
|
|
45
|
+
const match = /^(\d{4}-\d{2}-\d{2})/.exec(raw.trim());
|
|
46
|
+
if (match)
|
|
47
|
+
return match[1];
|
|
48
|
+
const parsed = new Date(raw);
|
|
49
|
+
if (Number.isNaN(parsed.getTime()))
|
|
50
|
+
return null;
|
|
51
|
+
// A non-ISO input (a locale string) still has to become a date string.
|
|
52
|
+
// Use the LOCAL parts, so the day is the one the user saw.
|
|
53
|
+
const pad = (n) => String(n).padStart(2, '0');
|
|
54
|
+
return `${parsed.getFullYear()}-${pad(parsed.getMonth() + 1)}-${pad(parsed.getDate())}`;
|
|
55
|
+
}
|
|
56
|
+
const date = new Date(raw);
|
|
40
57
|
return Number.isNaN(date.getTime()) ? null : date.toISOString();
|
|
41
58
|
}
|
|
42
59
|
if (type === 'datetime') {
|
|
@@ -8,11 +8,39 @@ const DIACRITIC_RE = /[̀-ͯ]/g;
|
|
|
8
8
|
export function normalizeForFilter(s, locale) {
|
|
9
9
|
if (!s)
|
|
10
10
|
return '';
|
|
11
|
+
// Fast path for pure-ASCII input, which is the overwhelming majority of what
|
|
12
|
+
// a grid filters. Both of the expensive steps are provably no-ops there:
|
|
13
|
+
// ASCII is already NFD-normalised, and the combining-marks block this strips
|
|
14
|
+
// (U+0300..U+036F) contains no ASCII. So lowercasing alone is the same
|
|
15
|
+
// answer, and `normalize-fast-path.test.ts` checks that exhaustively over
|
|
16
|
+
// every ASCII code point rather than taking the argument on trust.
|
|
17
|
+
//
|
|
18
|
+
// Worth the branch: this runs once per cell per filter - 100,000 times for a
|
|
19
|
+
// one-column filter over a 100k grid - and a CPU profile of a browser filter
|
|
20
|
+
// put more time in this function than in any other.
|
|
21
|
+
//
|
|
22
|
+
// Note the locale still routes through toLocaleLowerCase even on the fast
|
|
23
|
+
// path: 'I'.toLocaleLowerCase('tr') is 'ı', so ASCII does NOT imply the
|
|
24
|
+
// locale can be ignored.
|
|
25
|
+
if (isAsciiOnly(s)) {
|
|
26
|
+
return locale ? s.toLocaleLowerCase(locale) : s.toLowerCase();
|
|
27
|
+
}
|
|
11
28
|
const stripped = s.normalize('NFD').replace(DIACRITIC_RE, '');
|
|
12
29
|
return locale
|
|
13
30
|
? stripped.toLocaleLowerCase(locale)
|
|
14
31
|
: stripped.toLowerCase();
|
|
15
32
|
}
|
|
33
|
+
/**
|
|
34
|
+
* True when every code unit is ASCII. A plain char-code scan, which is far
|
|
35
|
+
* cheaper than the `normalize()` + regex pass it lets us skip.
|
|
36
|
+
*/
|
|
37
|
+
function isAsciiOnly(s) {
|
|
38
|
+
for (let i = 0; i < s.length; i++) {
|
|
39
|
+
if (s.charCodeAt(i) > 127)
|
|
40
|
+
return false;
|
|
41
|
+
}
|
|
42
|
+
return true;
|
|
43
|
+
}
|
|
16
44
|
/**
|
|
17
45
|
* Delimiter used to serialise the `in` / `notIn` value list into the single
|
|
18
46
|
* `value` string that the filter model carries.
|
package/dist/grid-messages.d.ts
CHANGED
|
@@ -54,9 +54,24 @@ export type GridMessages = {
|
|
|
54
54
|
menuRemoveRow: string;
|
|
55
55
|
menuRemoveColumn: string;
|
|
56
56
|
menuEditComment: string;
|
|
57
|
+
selectionBarLabel: string;
|
|
58
|
+
selectionBarCount: string;
|
|
59
|
+
selectionBarClear: string;
|
|
60
|
+
selectionBarMore: string;
|
|
61
|
+
selectionBarSelectAll: string;
|
|
62
|
+
selectionBarEditFields: string;
|
|
63
|
+
bulkEditTitle: string;
|
|
64
|
+
bulkEditLead: string;
|
|
65
|
+
bulkEditMixed: string;
|
|
66
|
+
bulkEditApply: string;
|
|
67
|
+
bulkEditCancel: string;
|
|
68
|
+
bulkEditNoFields: string;
|
|
57
69
|
chartRange: string;
|
|
58
70
|
pivotUpsellTitle: string;
|
|
59
71
|
pivotUpsellBody: string;
|
|
72
|
+
/** Shared licensing line under every Enterprise upsell note. */
|
|
73
|
+
upsellLicense: string;
|
|
74
|
+
upsellLicenseLink: string;
|
|
60
75
|
};
|
|
61
76
|
/** English defaults - the literal strings the grid shipped before localization. */
|
|
62
77
|
export declare const defaultGridMessages: GridMessages;
|
package/dist/grid-messages.js
CHANGED
|
@@ -49,6 +49,19 @@ export const defaultGridMessages = {
|
|
|
49
49
|
menuRemoveRow: 'Remove row',
|
|
50
50
|
menuRemoveColumn: 'Remove column',
|
|
51
51
|
menuEditComment: 'Edit comment',
|
|
52
|
+
selectionBarLabel: 'Selection actions',
|
|
53
|
+
/** Label beside the count CHIP, which carries the number itself. */
|
|
54
|
+
selectionBarCount: 'selected',
|
|
55
|
+
selectionBarClear: 'Clear selection',
|
|
56
|
+
selectionBarMore: 'More actions',
|
|
57
|
+
selectionBarSelectAll: 'Select all',
|
|
58
|
+
selectionBarEditFields: 'Edit fields',
|
|
59
|
+
bulkEditTitle: 'Edit fields',
|
|
60
|
+
bulkEditLead: 'Changes apply to all {count} selected items. Fields you leave alone keep their existing values.',
|
|
61
|
+
bulkEditMixed: 'Multiple values',
|
|
62
|
+
bulkEditApply: 'Apply to {count} items',
|
|
63
|
+
bulkEditCancel: 'Cancel',
|
|
64
|
+
bulkEditNoFields: 'No editable fields on this grid.',
|
|
52
65
|
opContains: 'Contains',
|
|
53
66
|
opNotContains: 'Not contains',
|
|
54
67
|
opEquals: 'Equals',
|
|
@@ -68,6 +81,8 @@ export const defaultGridMessages = {
|
|
|
68
81
|
chartRange: 'Chart selected range',
|
|
69
82
|
pivotUpsellTitle: 'Pivot mode',
|
|
70
83
|
pivotUpsellBody: 'Pivot mode is an Enterprise feature. Install @svgrid/enterprise and call enablePivot() to use it.',
|
|
84
|
+
upsellLicense: 'A license key is required for production use. Without one the feature still works, but the grid renders an unlicensed watermark.',
|
|
85
|
+
upsellLicenseLink: 'View licensing',
|
|
71
86
|
};
|
|
72
87
|
/**
|
|
73
88
|
* Merge a consumer's `localeText` over the English defaults. Undefined/empty
|
package/dist/group-display.d.ts
CHANGED
|
@@ -13,7 +13,7 @@
|
|
|
13
13
|
* Both are generic over the row / column shape (via small accessor callbacks) so
|
|
14
14
|
* they are trivially unit-testable and carry no dependency on the grid runtime.
|
|
15
15
|
*/
|
|
16
|
-
/**
|
|
16
|
+
/** Grouping display variants. */
|
|
17
17
|
export type GroupDisplayType = 'groupRows' | 'singleColumn' | 'multipleColumns';
|
|
18
18
|
export type GroupFooterOptions<R> = {
|
|
19
19
|
/** Depth of a row (group rows and their descendants). */
|
package/dist/index.d.ts
CHANGED
|
@@ -7,10 +7,12 @@ export { subscribeGrid, subscribeSvGrid } from './subscribe.js';
|
|
|
7
7
|
export { default as SvGrid } from './SvGrid.svelte';
|
|
8
8
|
export type { BoardConfig, BoardLane, BoardCardMoveEvent, BoardCardCommitEvent, BoardLayout, BoardSubtask, BoardComment, BoardMenuContext, BoardLaneMenuContext, BoardDrawerConfig } from './SvGrid.types.js';
|
|
9
9
|
export { registerBoardView, getBoardView, hasBoardView } from './board-view.svelte.js';
|
|
10
|
+
export type { SelectionBarAction, SelectionBarTarget, ContextMenuItem, ContextMenuTarget, } from './SvGrid.types.js';
|
|
10
11
|
export * from './ai.js';
|
|
11
12
|
export { registerExportProvider, getExportProvider, type GridExportProvider, type GridExportRunOptions, } from './export-provider.js';
|
|
12
13
|
export type { SchedulerConfig, SchedulerDrawerConfig, SchedulerEventMoveEvent, SchedulerEventResizeEvent, SchedulerEventCommitEvent, SchedulerRangeSelection, SchedulerView, SchedulerResource, SchedulerCollisionMode, SchedulerException, SchedulerEditScope, SchedulerOccurrenceChangeEvent, } from './SvGrid.types.js';
|
|
13
14
|
export { registerSchedulerView, getSchedulerView, hasSchedulerView } from './scheduler-view.svelte.js';
|
|
15
|
+
export { registerSelectionBarView, getSelectionBarView, hasSelectionBarView } from './selection-bar-view.svelte.js';
|
|
14
16
|
export type { ChartViewConfig } from './SvGrid.types.js';
|
|
15
17
|
export { registerChartView, getChartView, hasChartView } from './chart-view.svelte.js';
|
|
16
18
|
export { registerPivotEngine, getPivotEngine, hasPivotEngine, type PivotEngine, type GridPivotConfig, type GridPivotValue, type GridPivotRow, } from './pivot-view.svelte.js';
|
|
@@ -55,6 +57,7 @@ export { default as SvVisuallyHidden } from './SvVisuallyHidden.svelte';
|
|
|
55
57
|
export { default as SvAspectRatio } from './SvAspectRatio.svelte';
|
|
56
58
|
export { registerCellEditor, getCellEditor, hasCellEditor, unregisterCellEditor, registeredCellEditorTypes, defaultEditorProps, resolveEditorProps, type CellEditorContext, type CellEditorRegistration, } from './editor-registry.js';
|
|
57
59
|
export { registerBuiltinEditors } from './builtin-editors.js';
|
|
60
|
+
export { sanitizeHtml, renderMarkdown, htmlToText } from './sanitize-html.js';
|
|
58
61
|
export { default as SvField } from './SvField.svelte';
|
|
59
62
|
export { createListbox, toSelectedArray, toSelectedSet, type Listbox, type ListboxConfig, type ListboxValue, type ListboxRootProps, type OptionProps, } from './createListbox.svelte.js';
|
|
60
63
|
export { createCombobox, type Combobox, type ComboboxConfig, type ComboboxValue } from './createCombobox.svelte.js';
|
|
@@ -152,6 +155,7 @@ export { default as SvAvatarGroup } from './SvAvatarGroup.svelte';
|
|
|
152
155
|
export { default as SvCommand, type CommandItem } from './SvCommand.svelte';
|
|
153
156
|
export { fuzzyScore, fuzzyMatch } from './fuzzy.js';
|
|
154
157
|
export { default as SvRichText, type RichTextTool } from './SvRichText.svelte';
|
|
158
|
+
export { default as SvRichCell } from './SvRichCell.svelte';
|
|
155
159
|
export { default as SvCarousel } from './SvCarousel.svelte';
|
|
156
160
|
export { default as SvTour, type TourStep } from './SvTour.svelte';
|
|
157
161
|
export { default as SvPagination } from './SvPagination.svelte';
|
|
@@ -194,6 +198,7 @@ export { chartToSvgString, downloadChartSvg, chartToPngBlob, downloadChartPng, c
|
|
|
194
198
|
export { buildSparkline, toSparklineValues, type SparklineConfig, type SparklineType, type SparklineGeometry, } from './sparkline.js';
|
|
195
199
|
export { spreadsheetLayout, spansToMerges, type SpanColumn, type SpreadsheetActionOptions, type MergeSpec, type CellBorderSpec, type BorderSpec, } from './spreadsheet.js';
|
|
196
200
|
export { rowResize, type RowResizeOptions } from './row-resize.js';
|
|
201
|
+
export { columnResize, type ColumnResizeOptions } from './column-resize.js';
|
|
197
202
|
export { rowDropZone, type RowDragEndEvent, type RowDropZoneOptions } from './row-drag.js';
|
|
198
203
|
export { resolveColumnTypes, inferCellDataType, type CellDataType } from './column-types.js';
|
|
199
204
|
export { computeColumnGroupMeta, hiddenLeavesForCollapse, type ColumnGroupMeta, type ColumnGroupShow, } from './column-groups.js';
|
|
@@ -212,7 +217,7 @@ export { createVirtualizer } from './virtualization/virtualizer.js';
|
|
|
212
217
|
export { createSvelteVirtualizer } from './virtualization/svelte-virtualizer.svelte.js';
|
|
213
218
|
export { createColumnVirtualizer } from './virtualization/column-virtualizer.js';
|
|
214
219
|
export type { VirtualItem, VirtualizerOptions, VirtualizerState } from './virtualization/types.js';
|
|
215
|
-
export type { SvGridApi, SvGridFilterOperator, SvGridWrapperProps } from './svgrid-wrapper.types.js';
|
|
220
|
+
export type { SvGridApi, SvGridFilterOperator, SvGridViewState, SvGridWrapperProps, } from './svgrid-wrapper.types.js';
|
|
216
221
|
export { parseEditorValue, normalizeEditorOptions, type CellEditorType, type CellEditorOption, } from './editors/cell-editors.js';
|
|
217
222
|
export { applyExcelFilter, compileExcelFilter, normalizeForFilter, splitInTokens, joinInTokens, trailingInToken, type CompiledExcelFilter, type ExcelFilter, type ExcelFilterOperator, type ExcelFilterOptions, } from './filtering/excel-filters.js';
|
|
218
223
|
export { ALL_FILTER_OPERATORS, SET_OPERATOR_IDS, VALUELESS_OPERATOR_IDS, RANGE_OPERATOR_IDS, isSetOperator, isValuelessOperator, isRangeOperator, type FilterValueType, } from './filtering/filter-operator-catalogue.js';
|
package/dist/index.js
CHANGED
|
@@ -15,6 +15,8 @@ export { registerBoardView, getBoardView, hasBoardView } from './board-view.svel
|
|
|
15
15
|
export * from './ai.js';
|
|
16
16
|
export { registerExportProvider, getExportProvider, } from './export-provider.js';
|
|
17
17
|
export { registerSchedulerView, getSchedulerView, hasSchedulerView } from './scheduler-view.svelte.js';
|
|
18
|
+
// Bulk-action bar over the row selection. Prop + types free, renderer Pro.
|
|
19
|
+
export { registerSelectionBarView, getSelectionBarView, hasSelectionBarView } from './selection-bar-view.svelte.js';
|
|
18
20
|
export { registerChartView, getChartView, hasChartView } from './chart-view.svelte.js';
|
|
19
21
|
export { registerPivotEngine, getPivotEngine, hasPivotEngine, } from './pivot-view.svelte.js';
|
|
20
22
|
// Pure scheduler layout/model helpers (framework-free, like recurrence/date-core).
|
|
@@ -73,6 +75,7 @@ export { default as SvAspectRatio } from './SvAspectRatio.svelte';
|
|
|
73
75
|
// UI kit - custom cell-editor registry (register any component as a grid editor)
|
|
74
76
|
export { registerCellEditor, getCellEditor, hasCellEditor, unregisterCellEditor, registeredCellEditorTypes, defaultEditorProps, resolveEditorProps, } from './editor-registry.js';
|
|
75
77
|
export { registerBuiltinEditors } from './builtin-editors.js';
|
|
78
|
+
export { sanitizeHtml, renderMarkdown, htmlToText } from './sanitize-html.js';
|
|
76
79
|
// UI kit - shared field chrome (label + hint + error + direction wrapper)
|
|
77
80
|
export { default as SvField } from './SvField.svelte';
|
|
78
81
|
// UI kit - headless cores (state + prop-getters you render yourself, like createSvGrid)
|
|
@@ -187,6 +190,7 @@ export { default as SvAvatarGroup } from './SvAvatarGroup.svelte';
|
|
|
187
190
|
export { default as SvCommand } from './SvCommand.svelte';
|
|
188
191
|
export { fuzzyScore, fuzzyMatch } from './fuzzy.js';
|
|
189
192
|
export { default as SvRichText } from './SvRichText.svelte';
|
|
193
|
+
export { default as SvRichCell } from './SvRichCell.svelte';
|
|
190
194
|
export { default as SvCarousel } from './SvCarousel.svelte';
|
|
191
195
|
export { default as SvTour } from './SvTour.svelte';
|
|
192
196
|
export { default as SvPagination } from './SvPagination.svelte';
|
|
@@ -230,7 +234,13 @@ export { buildChart, formatChartValue, rowsToChartSpec, niceScale, niceLogScale,
|
|
|
230
234
|
export { chartToSvgString, downloadChartSvg, chartToPngBlob, downloadChartPng, chartSpecToCsv, downloadChartCsv, } from './chart-export.js';
|
|
231
235
|
export { buildSparkline, toSparklineValues, } from './sparkline.js';
|
|
232
236
|
export { spreadsheetLayout, spansToMerges, } from './spreadsheet.js';
|
|
237
|
+
// The two resize actions, exported as a matched pair. `<SvGrid>` drives both
|
|
238
|
+
// through the `rowResize` / `columnResize` props - both default OFF, both are
|
|
239
|
+
// turned on by setting them true, and the grid `import()`s the module itself so
|
|
240
|
+
// a grid that leaves them off carries neither. Import them directly only for a
|
|
241
|
+
// headless table, which renders its own rows and headers.
|
|
233
242
|
export { rowResize } from './row-resize.js';
|
|
243
|
+
export { columnResize } from './column-resize.js';
|
|
234
244
|
export { rowDropZone } from './row-drag.js';
|
|
235
245
|
export { resolveColumnTypes, inferCellDataType } from './column-types.js';
|
|
236
246
|
export { computeColumnGroupMeta, hiddenLeavesForCollapse, } from './column-groups.js';
|
package/dist/list-option.d.ts
CHANGED
|
@@ -7,6 +7,12 @@ export type ListOption = {
|
|
|
7
7
|
group?: string;
|
|
8
8
|
/** Optional color swatch (any CSS color) shown before the label. */
|
|
9
9
|
color?: string;
|
|
10
|
+
/**
|
|
11
|
+
* Optional muted text pinned to the trailing edge of the row - a count, a
|
|
12
|
+
* shortcut, a unit. Not part of the label, so it does not affect matching
|
|
13
|
+
* or the accessible name.
|
|
14
|
+
*/
|
|
15
|
+
hint?: string;
|
|
10
16
|
};
|
|
11
17
|
/**
|
|
12
18
|
* Coerce a raw options array into well-formed ListOptions. A primitive item
|
package/dist/menus.js
CHANGED
|
@@ -118,7 +118,7 @@ export function createMenus(ctx) {
|
|
|
118
118
|
function openChooseColumns(event) {
|
|
119
119
|
event.stopPropagation();
|
|
120
120
|
// Submenu behavior: keep the parent operations menu open and float the
|
|
121
|
-
// Choose Columns panel out to the right of it
|
|
121
|
+
// Choose Columns panel out to the right of it, submenu-style. Falls
|
|
122
122
|
// back to below the item if the popover would clip the viewport.
|
|
123
123
|
const trigger = event.currentTarget;
|
|
124
124
|
const menuEl = trigger.closest(".sv-grid-menu");
|
|
@@ -249,19 +249,52 @@ export function createMenus(ctx) {
|
|
|
249
249
|
}
|
|
250
250
|
ctx.valueFilters = { ...ctx.valueFilters, [columnId]: new Set(next) };
|
|
251
251
|
}
|
|
252
|
+
/**
|
|
253
|
+
* With a search query typed, "select all" means the RESULTS - the same thing
|
|
254
|
+
* it means in a spreadsheet. It used to mean the whole column regardless, so
|
|
255
|
+
* the standard flow (type a query, tick select-all, get just the matches)
|
|
256
|
+
* cleared the entire selection instead: `isAllFacetsChecked` saw every value
|
|
257
|
+
* ticked, read that as "on", and turned everything off.
|
|
258
|
+
*/
|
|
252
259
|
function isAllFacetsChecked(columnId) {
|
|
253
260
|
const selected = ctx.valueFilters[columnId];
|
|
254
|
-
|
|
261
|
+
const visible = ctx.columnMenuVisibleFacets;
|
|
262
|
+
const searching = visible.length !== ctx.columnMenuFacetValues.length;
|
|
263
|
+
if (!selected)
|
|
264
|
+
return true;
|
|
265
|
+
if (searching)
|
|
266
|
+
return visible.every((value) => selected.has(value));
|
|
267
|
+
return selected.size >= ctx.columnMenuFacetValues.length;
|
|
255
268
|
}
|
|
256
269
|
function toggleAllFacets(columnId) {
|
|
257
|
-
|
|
258
|
-
|
|
270
|
+
const visible = ctx.columnMenuVisibleFacets;
|
|
271
|
+
const all = ctx.columnMenuFacetValues;
|
|
272
|
+
const searching = visible.length !== all.length;
|
|
273
|
+
const on = isAllFacetsChecked(columnId);
|
|
274
|
+
if (!searching) {
|
|
275
|
+
if (on) {
|
|
276
|
+
ctx.valueFilters = { ...ctx.valueFilters, [columnId]: new Set() };
|
|
277
|
+
}
|
|
278
|
+
else {
|
|
279
|
+
const copy = { ...ctx.valueFilters };
|
|
280
|
+
delete copy[columnId];
|
|
281
|
+
ctx.valueFilters = copy;
|
|
282
|
+
}
|
|
283
|
+
return;
|
|
259
284
|
}
|
|
260
|
-
|
|
261
|
-
|
|
262
|
-
|
|
263
|
-
|
|
285
|
+
// Searching: add or remove just the matches, leaving the rest of the
|
|
286
|
+
// selection alone. An absent entry means "everything", so it has to be
|
|
287
|
+
// materialized before a subtraction can mean anything.
|
|
288
|
+
const current = ctx.valueFilters[columnId]
|
|
289
|
+
? new Set(ctx.valueFilters[columnId])
|
|
290
|
+
: new Set(all);
|
|
291
|
+
for (const value of visible) {
|
|
292
|
+
if (on)
|
|
293
|
+
current.delete(value);
|
|
294
|
+
else
|
|
295
|
+
current.add(value);
|
|
264
296
|
}
|
|
297
|
+
ctx.valueFilters = { ...ctx.valueFilters, [columnId]: current };
|
|
265
298
|
}
|
|
266
299
|
function clearColumnFilter(columnId) {
|
|
267
300
|
// `untrack`: read-modify-write on the filter maps. Keeps the method safe to
|
package/dist/row-resize.d.ts
CHANGED
|
@@ -36,6 +36,17 @@ export type RowResizeOptions = {
|
|
|
36
36
|
max?: number;
|
|
37
37
|
/** When true, the action removes its strips and ignores events. */
|
|
38
38
|
disabled?: boolean;
|
|
39
|
+
/**
|
|
40
|
+
* Where the drag strip is anchored.
|
|
41
|
+
* - `'gutter'` (default) - only rows that have a row-header gutter cell get
|
|
42
|
+
* a strip: the built-in row-number column (`showRowNumbers`) or a column
|
|
43
|
+
* tagged `cellClass: 'sv-row-gutter'`. Rows without one are skipped, so on
|
|
44
|
+
* a plain grid the action does nothing.
|
|
45
|
+
* - `'row'` - use the gutter when there is one, otherwise fall back to the
|
|
46
|
+
* row's first body cell. This is what `<SvGrid rowResize>` passes, so the
|
|
47
|
+
* prop works without also asking for a gutter column.
|
|
48
|
+
*/
|
|
49
|
+
anchor?: 'gutter' | 'row';
|
|
39
50
|
};
|
|
40
51
|
export declare function rowResize(node: HTMLElement, opts: RowResizeOptions): {
|
|
41
52
|
update(next: RowResizeOptions): void;
|
package/dist/row-resize.js
CHANGED
|
@@ -141,7 +141,13 @@ export function rowResize(node, opts) {
|
|
|
141
141
|
// A row-header gutter cell: either a user column tagged
|
|
142
142
|
// `sv-row-gutter`, or the grid's built-in row-number gutter
|
|
143
143
|
// (`showRowNumbers`), whose cell is `.sv-grid-row-number-cell`.
|
|
144
|
-
const gutter = tr.querySelector('.sv-grid-cell.sv-row-gutter, .sv-grid-cell.sv-grid-row-number-cell')
|
|
144
|
+
const gutter = tr.querySelector('.sv-grid-cell.sv-row-gutter, .sv-grid-cell.sv-grid-row-number-cell') ??
|
|
145
|
+
// `anchor: 'row'` - no gutter on this grid, so hang the strip off the
|
|
146
|
+
// first body cell instead. Without this a grid with no row-number
|
|
147
|
+
// column would silently not resize.
|
|
148
|
+
(current.anchor === 'row'
|
|
149
|
+
? tr.querySelector('.sv-grid-cell')
|
|
150
|
+
: null);
|
|
145
151
|
if (!gutter)
|
|
146
152
|
continue;
|
|
147
153
|
if (gutter.querySelector(`:scope > .${STRIP_CLASS}`))
|
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* sanitize-html - a dependency-free HTML sanitizer and a small Markdown
|
|
3
|
+
* renderer, sized for what a grid cell needs to display.
|
|
4
|
+
*
|
|
5
|
+
* A rich-text cell has to paint markup that came from a user, which is the one
|
|
6
|
+
* place a data grid can hand an attacker script execution. Everything rendered
|
|
7
|
+
* through `SvRichCell` goes through `sanitizeHtml` first, and the allowlist is
|
|
8
|
+
* deliberately narrower than a general-purpose sanitizer: it covers the tags
|
|
9
|
+
* `SvRichText` can produce, plus links and images.
|
|
10
|
+
*
|
|
11
|
+
* The parse uses the platform parser where there is one (`DOMParser`, which
|
|
12
|
+
* neither executes scripts nor runs loaders on a detached document) and a
|
|
13
|
+
* conservative regex stripper during SSR, where there is no DOM. The SSR path
|
|
14
|
+
* is stricter by design: when in doubt it drops markup rather than passing it
|
|
15
|
+
* through, and the hydrated client re-sanitizes with the real parser anyway.
|
|
16
|
+
*
|
|
17
|
+
* This is not a general-purpose sanitizer for arbitrary third-party HTML. It is
|
|
18
|
+
* a narrow allowlist for cell content. To render something outside the
|
|
19
|
+
* allowlist, extend it explicitly rather than widening the defaults.
|
|
20
|
+
*/
|
|
21
|
+
/**
|
|
22
|
+
* Return `html` with everything outside the allowlist removed. Idempotent, so
|
|
23
|
+
* it is safe to call on already-sanitized markup.
|
|
24
|
+
*/
|
|
25
|
+
export declare function sanitizeHtml(html: string | null | undefined): string;
|
|
26
|
+
/**
|
|
27
|
+
* Render a common Markdown subset to HTML: headings, bold, italic,
|
|
28
|
+
* strikethrough, inline code, links, images, and bullet / ordered lists.
|
|
29
|
+
*
|
|
30
|
+
* Deliberately not a full CommonMark implementation - a grid cell shows a line
|
|
31
|
+
* or two, and a complete parser is a dependency this package does not take. The
|
|
32
|
+
* output is sanitized, so a Markdown link cannot smuggle `javascript:`.
|
|
33
|
+
*/
|
|
34
|
+
export declare function renderMarkdown(markdown: string | null | undefined): string;
|
|
35
|
+
/** Strip markup down to readable text, for exports, aria labels and tooltips
|
|
36
|
+
* where a cell's HTML has to collapse to one plain string. */
|
|
37
|
+
export declare function htmlToText(html: string | null | undefined): string;
|