@svgrid/enterprise 2.6.4 → 2.7.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.
Files changed (59) hide show
  1. package/dist/SvGridBulkEditDrawer.svelte +158 -0
  2. package/dist/SvGridBulkEditDrawer.svelte.d.ts +9 -0
  3. package/dist/SvGridSelectionBar.svelte +452 -0
  4. package/dist/SvGridSelectionBar.svelte.d.ts +6 -0
  5. package/dist/SvPivotDesigner.svelte +3 -3
  6. package/dist/SvPivotDesigner.svelte.d.ts +3 -3
  7. package/dist/bulk-edit.d.ts +64 -0
  8. package/dist/bulk-edit.js +152 -0
  9. package/dist/cdn/svgrid-enterprise.svelte-external.js +6182 -5779
  10. package/dist/designer/assets/GridMenus-Cgilexpk.js +8 -0
  11. package/dist/designer/assets/SvDateRangeInput-BV5OXYQ2.css +1 -0
  12. package/dist/designer/assets/SvDateRangeInput-CVn-yqrQ.js +1 -0
  13. package/dist/designer/assets/SvDateTimePicker-BdioTrJQ.js +1 -0
  14. package/dist/designer/assets/SvDateTimePicker-CY8TK4BT.css +1 -0
  15. package/dist/designer/assets/SvField-BsqiA5me.js +1 -0
  16. package/dist/designer/assets/SvGridCellEditor-dLY7_kk9.js +2 -0
  17. package/dist/designer/assets/SvListBox-CVYQcLX9.js +1 -0
  18. package/dist/designer/assets/{SvListBox-BMSfFJJT.css → SvListBox-DgN8kvjt.css} +1 -1
  19. package/dist/designer/assets/column-resize-C_inr5zT.js +1 -0
  20. package/dist/designer/assets/date-format-4DJvNtG2.js +1 -0
  21. package/dist/designer/assets/{SvDateTimePicker-Cygij-dr.css → date-format-Dzy4mTGh.css} +1 -1
  22. package/dist/designer/assets/dismissable-BO547MH9.js +1 -0
  23. package/dist/designer/assets/editor-registry-BjP16H0v.js +1 -0
  24. package/dist/designer/assets/{index-DxBZuosR.js → index-BvaLmQSd.js} +129 -129
  25. package/dist/designer/assets/index-Cp7fDJ3b.css +1 -0
  26. package/dist/designer/assets/{js-scroller.svelte-03aI6ovu.js → js-scroller.svelte-Bhxqb3-c.js} +2 -2
  27. package/dist/designer/assets/preload-helper-CG0n22O7.js +1 -0
  28. package/dist/designer/assets/row-resize-B0FWHcNr.js +1 -0
  29. package/dist/designer/assets/src-7qOYsBug.js +2896 -0
  30. package/dist/designer/assets/src-B7DNcoQK.css +1 -0
  31. package/dist/designer/assets/validate-h-aslRV9.js +1 -0
  32. package/dist/designer/index.html +18 -13
  33. package/dist/export.d.ts +4 -0
  34. package/dist/import.d.ts +7 -0
  35. package/dist/index.d.ts +3 -0
  36. package/dist/index.js +8 -0
  37. package/dist/install.d.ts +3 -0
  38. package/dist/install.js +2 -0
  39. package/dist/node/studio.js +65 -3
  40. package/dist/pivot.d.ts +11 -0
  41. package/dist/pivot.js +6 -1
  42. package/dist/selection-bar.d.ts +7 -0
  43. package/dist/selection-bar.js +42 -0
  44. package/dist/studio/emit-project.js +6 -0
  45. package/dist/studio/ui-components.generated.js +64 -2
  46. package/dist/version.d.ts +1 -1
  47. package/dist/version.js +1 -1
  48. package/package.json +8 -3
  49. package/dist/designer/assets/GridMenus-BIU7Nfbr.js +0 -7
  50. package/dist/designer/assets/SvDateTimePicker-DOBYyLeN.js +0 -1
  51. package/dist/designer/assets/SvGrid.helpers-C6wxF55r.js +0 -1
  52. package/dist/designer/assets/SvGridCellEditor-CMtmQINJ.js +0 -2
  53. package/dist/designer/assets/SvListBox-D-_I_Aff.js +0 -1
  54. package/dist/designer/assets/dismissable-2EZKoens.js +0 -1
  55. package/dist/designer/assets/editor-registry-BB1Qb5mp.js +0 -1
  56. package/dist/designer/assets/index-BfzoL904.css +0 -1
  57. package/dist/designer/assets/src-D8qr49rE.css +0 -1
  58. package/dist/designer/assets/src-Dn1Axx6T.js +0 -2896
  59. /package/dist/designer/assets/{dismissable-BF-9TJSd.css → SvField-BF-9TJSd.css} +0 -0
@@ -0,0 +1,64 @@
1
+ /**
2
+ * Bulk edit - set one or more fields across every selected row, as a single
3
+ * undoable run. The engine half; `SvGridBulkEditDrawer.svelte` is the UI.
4
+ *
5
+ * Kept out of the component so it can be tested without mounting anything, and
6
+ * so the rules below live in one readable place rather than inside markup.
7
+ */
8
+ export type BulkEditField = {
9
+ /** Column id, which is what the write is addressed by. */
10
+ id: string;
11
+ /** Header text, or the column id when the header is not a plain string. */
12
+ label: string;
13
+ /** The column's editor type, mapped to a form control by the drawer. */
14
+ editorType: string;
15
+ /** Options for list / select style columns, when the column declares them. */
16
+ options?: Array<{
17
+ value: unknown;
18
+ label: string;
19
+ }>;
20
+ };
21
+ /**
22
+ * The columns a bulk edit can target.
23
+ *
24
+ * A column qualifies only if it is field-backed (there is somewhere to write
25
+ * the value) and editable. `isCellEditable` is asked WITHOUT a row, which is
26
+ * the column-level question - per-row rules are re-checked per cell at write
27
+ * time, so a column that is editable for some rows still shows up here and
28
+ * simply skips the rows that refuse it.
29
+ */
30
+ export declare function bulkEditableFields(ctx: any): BulkEditField[];
31
+ /** Coerce a form control's raw output to what the column should store. */
32
+ export declare function coerceBulkValue(editorType: string, raw: unknown): unknown;
33
+ /**
34
+ * What each field should show when the drawer opens.
35
+ *
36
+ * A field where every selected row already agrees shows that shared value, so
37
+ * the form reads as the current state rather than as empty. A field where they
38
+ * differ shows nothing and is reported as `mixed` - the drawer labels it, and
39
+ * leaving it alone leaves each row's own value intact. This is the answer to
40
+ * "what does an untouched field mean" that makes multi-field bulk edit safe:
41
+ * only fields the user actually changes are written.
42
+ */
43
+ export declare function bulkEditInitialValues(ctx: any, fields: BulkEditField[]): {
44
+ values: Record<string, unknown>;
45
+ mixed: Set<string>;
46
+ };
47
+ export type BulkEditResult = {
48
+ /** Cells actually changed. Skips rows already holding the value. */
49
+ changed: number;
50
+ /** Cells the grid refused to write, e.g. a per-row `editable` rule. */
51
+ skipped: number;
52
+ /** How many distinct fields were written. */
53
+ fields: number;
54
+ };
55
+ /**
56
+ * Apply `edits` (columnId -> value) to every selected row.
57
+ *
58
+ * Every write goes through `writeCellRaw`, so `onCellValueChange` fires per
59
+ * cell exactly as it does for a single edit. The undo steps for the WHOLE run -
60
+ * across every field and every row - are appended together, so one bulk edit
61
+ * walks back the way a paste does rather than leaving the user pressing Ctrl+Z
62
+ * once per cell.
63
+ */
64
+ export declare function applyBulkEdit(ctx: any, edits: Record<string, unknown>): BulkEditResult;
@@ -0,0 +1,152 @@
1
+ /**
2
+ * Bulk edit - set one or more fields across every selected row, as a single
3
+ * undoable run. The engine half; `SvGridBulkEditDrawer.svelte` is the UI.
4
+ *
5
+ * Kept out of the component so it can be tested without mounting anything, and
6
+ * so the rules below live in one readable place rather than inside markup.
7
+ */
8
+ /**
9
+ * The columns a bulk edit can target.
10
+ *
11
+ * A column qualifies only if it is field-backed (there is somewhere to write
12
+ * the value) and editable. `isCellEditable` is asked WITHOUT a row, which is
13
+ * the column-level question - per-row rules are re-checked per cell at write
14
+ * time, so a column that is editable for some rows still shows up here and
15
+ * simply skips the rows that refuse it.
16
+ */
17
+ export function bulkEditableFields(ctx) {
18
+ const out = [];
19
+ for (const column of ctx.allColumns ?? []) {
20
+ const def = column?.columnDef;
21
+ if (!def?.field)
22
+ continue;
23
+ if (def.editable === false)
24
+ continue;
25
+ if (!ctx.isCellEditable(column))
26
+ continue;
27
+ // A snippet header has no text to put in a form label; the id is at least
28
+ // stable and recognisable.
29
+ const label = typeof def.header === 'string' && def.header ? def.header : column.id;
30
+ const raw = def.editorOptions;
31
+ const options = Array.isArray(raw)
32
+ ? raw.map((o) => o && typeof o === 'object' && 'value' in o
33
+ ? { value: o.value, label: String(o.label ?? o.value) }
34
+ : { value: o, label: String(o) })
35
+ : undefined;
36
+ out.push({ id: column.id, label, editorType: String(def.editorType ?? 'text'), options });
37
+ }
38
+ return out;
39
+ }
40
+ /** Coerce a form control's raw output to what the column should store. */
41
+ export function coerceBulkValue(editorType, raw) {
42
+ if (editorType === 'checkbox')
43
+ return Boolean(raw);
44
+ if (editorType === 'number') {
45
+ if (raw === '' || raw == null)
46
+ return null;
47
+ const n = Number(raw);
48
+ return Number.isNaN(n) ? null : n;
49
+ }
50
+ return raw;
51
+ }
52
+ /**
53
+ * What each field should show when the drawer opens.
54
+ *
55
+ * A field where every selected row already agrees shows that shared value, so
56
+ * the form reads as the current state rather than as empty. A field where they
57
+ * differ shows nothing and is reported as `mixed` - the drawer labels it, and
58
+ * leaving it alone leaves each row's own value intact. This is the answer to
59
+ * "what does an untouched field mean" that makes multi-field bulk edit safe:
60
+ * only fields the user actually changes are written.
61
+ */
62
+ export function bulkEditInitialValues(ctx, fields) {
63
+ const values = {};
64
+ const mixed = new Set();
65
+ const ids = ctx.selectionBarTarget?.ids ?? [];
66
+ const selected = new Set(ids);
67
+ const rowIndexes = [];
68
+ ctx.allRows.forEach((row, i) => {
69
+ if (selected.has(row.id))
70
+ rowIndexes.push(i);
71
+ });
72
+ for (const field of fields) {
73
+ let first;
74
+ let seen = false;
75
+ let differs = false;
76
+ for (const rowIndex of rowIndexes) {
77
+ const v = ctx.readCellRaw(rowIndex, field.id);
78
+ if (!seen) {
79
+ first = v;
80
+ seen = true;
81
+ }
82
+ else if (v !== first) {
83
+ differs = true;
84
+ break;
85
+ }
86
+ }
87
+ if (differs) {
88
+ mixed.add(field.id);
89
+ values[field.id] = field.editorType === 'checkbox' ? false : '';
90
+ }
91
+ else {
92
+ values[field.id] = first ?? (field.editorType === 'checkbox' ? false : '');
93
+ }
94
+ }
95
+ return { values, mixed };
96
+ }
97
+ /**
98
+ * Apply `edits` (columnId -> value) to every selected row.
99
+ *
100
+ * Every write goes through `writeCellRaw`, so `onCellValueChange` fires per
101
+ * cell exactly as it does for a single edit. The undo steps for the WHOLE run -
102
+ * across every field and every row - are appended together, so one bulk edit
103
+ * walks back the way a paste does rather than leaving the user pressing Ctrl+Z
104
+ * once per cell.
105
+ */
106
+ export function applyBulkEdit(ctx, edits) {
107
+ const steps = [];
108
+ let skipped = 0;
109
+ let fieldsWritten = 0;
110
+ const ids = ctx.selectionBarTarget?.ids ?? [];
111
+ const selected = new Set(ids);
112
+ // Resolve indexes in ONE pass rather than searching per row. `writeCellRaw`
113
+ // swaps `internalData` on every call and `allRows` re-derives, so a per-row
114
+ // `findIndex` would walk a freshly rebuilt array for every cell - O(rows x
115
+ // selection) for a result that is already known. It would still be CORRECT,
116
+ // because row ids are stable across the swap; it is just needless work.
117
+ const targets = [];
118
+ ctx.allRows.forEach((row, rowIndex) => {
119
+ if (selected.has(row.id))
120
+ targets.push({ rowIndex, rowId: row.id });
121
+ });
122
+ for (const [columnId, value] of Object.entries(edits)) {
123
+ const column = ctx.allColumns.find((c) => c.id === columnId);
124
+ const field = column?.columnDef?.field;
125
+ if (!field)
126
+ continue;
127
+ fieldsWritten += 1;
128
+ const colIndex = ctx.allColumns.indexOf(column);
129
+ for (const { rowIndex, rowId } of targets) {
130
+ if (!ctx.isCellEditableAt(rowIndex, colIndex)) {
131
+ skipped += 1;
132
+ continue;
133
+ }
134
+ const before = ctx.readCellRaw(rowIndex, columnId);
135
+ if (before === value)
136
+ continue;
137
+ ctx.writeCellRaw(rowIndex, columnId, value);
138
+ steps.push({ rowId, columnId, field, before, after: value });
139
+ }
140
+ }
141
+ if (steps.length) {
142
+ let hist = ctx.history.slice(0, ctx.historyPtr + 1);
143
+ for (const step of steps)
144
+ hist.push(step);
145
+ if (hist.length > ctx.UNDO_LIMIT)
146
+ hist = hist.slice(hist.length - ctx.UNDO_LIMIT);
147
+ ctx.history = hist;
148
+ ctx.historyPtr = ctx.history.length - 1;
149
+ ctx.historyVersion += 1;
150
+ }
151
+ return { changed: steps.length, skipped, fields: fieldsWritten };
152
+ }