@toolbox-web/grid 1.25.1 → 1.25.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/all.js +2 -2
- package/all.js.map +1 -1
- package/index.js +1 -1
- package/index.js.map +1 -1
- package/lib/core/grid.d.ts +18 -2
- package/lib/core/internal/diagnostics.d.ts +164 -0
- package/lib/core/internal/sorting.d.ts +53 -4
- package/lib/core/internal/utils.d.ts +0 -8
- package/lib/core/plugin/base-plugin.d.ts +18 -2
- package/lib/core/plugin/plugin-manager.d.ts +6 -4
- package/lib/core/types.d.ts +3 -2
- package/lib/features/registry.js +1 -1
- package/lib/features/registry.js.map +1 -1
- package/lib/plugins/clipboard/index.js +1 -1
- package/lib/plugins/clipboard/index.js.map +1 -1
- package/lib/plugins/column-virtualization/index.js +1 -1
- package/lib/plugins/column-virtualization/index.js.map +1 -1
- package/lib/plugins/context-menu/index.js +1 -1
- package/lib/plugins/context-menu/index.js.map +1 -1
- package/lib/plugins/editing/index.js +1 -1
- package/lib/plugins/editing/index.js.map +1 -1
- package/lib/plugins/editing/types.d.ts +3 -1
- package/lib/plugins/export/ExportPlugin.d.ts +2 -2
- package/lib/plugins/export/index.js +1 -1
- package/lib/plugins/export/index.js.map +1 -1
- package/lib/plugins/filtering/FilteringPlugin.d.ts +2 -2
- package/lib/plugins/filtering/index.js +1 -1
- package/lib/plugins/filtering/index.js.map +1 -1
- package/lib/plugins/grouping-columns/index.js +1 -1
- package/lib/plugins/grouping-columns/index.js.map +1 -1
- package/lib/plugins/grouping-rows/GroupingRowsPlugin.d.ts +2 -2
- package/lib/plugins/grouping-rows/index.js +2 -2
- package/lib/plugins/grouping-rows/index.js.map +1 -1
- package/lib/plugins/master-detail/index.js +1 -1
- package/lib/plugins/master-detail/index.js.map +1 -1
- package/lib/plugins/multi-sort/MultiSortPlugin.d.ts +2 -2
- package/lib/plugins/multi-sort/index.js +1 -1
- package/lib/plugins/multi-sort/index.js.map +1 -1
- package/lib/plugins/pinned-columns/PinnedColumnsPlugin.d.ts +2 -2
- package/lib/plugins/pinned-columns/index.js +1 -1
- package/lib/plugins/pinned-columns/index.js.map +1 -1
- package/lib/plugins/pinned-rows/index.js +1 -1
- package/lib/plugins/pinned-rows/index.js.map +1 -1
- package/lib/plugins/pivot/index.js +1 -1
- package/lib/plugins/pivot/index.js.map +1 -1
- package/lib/plugins/print/PrintPlugin.d.ts +2 -1
- package/lib/plugins/print/index.js +1 -1
- package/lib/plugins/print/index.js.map +1 -1
- package/lib/plugins/print/print-isolated.d.ts +2 -1
- package/lib/plugins/reorder-columns/ReorderPlugin.d.ts +2 -2
- package/lib/plugins/reorder-columns/index.js +1 -1
- package/lib/plugins/reorder-columns/index.js.map +1 -1
- package/lib/plugins/reorder-rows/RowReorderPlugin.d.ts +2 -2
- package/lib/plugins/reorder-rows/index.js +1 -1
- package/lib/plugins/reorder-rows/index.js.map +1 -1
- package/lib/plugins/responsive/index.js +1 -1
- package/lib/plugins/responsive/index.js.map +1 -1
- package/lib/plugins/selection/index.js +1 -1
- package/lib/plugins/selection/index.js.map +1 -1
- package/lib/plugins/server-side/index.js +1 -1
- package/lib/plugins/server-side/index.js.map +1 -1
- package/lib/plugins/tree/TreePlugin.d.ts +2 -2
- package/lib/plugins/tree/index.js +1 -1
- package/lib/plugins/tree/index.js.map +1 -1
- package/lib/plugins/undo-redo/UndoRedoPlugin.d.ts +2 -2
- package/lib/plugins/undo-redo/index.js +1 -1
- package/lib/plugins/undo-redo/index.js.map +1 -1
- package/lib/plugins/visibility/VisibilityPlugin.d.ts +2 -2
- package/lib/plugins/visibility/index.js +1 -1
- package/lib/plugins/visibility/index.js.map +1 -1
- package/package.json +1 -1
- package/umd/grid.all.umd.js +1 -1
- package/umd/grid.all.umd.js.map +1 -1
- package/umd/grid.umd.js +1 -1
- package/umd/grid.umd.js.map +1 -1
- package/umd/plugins/clipboard.umd.js +1 -1
- package/umd/plugins/clipboard.umd.js.map +1 -1
- package/umd/plugins/context-menu.umd.js +1 -1
- package/umd/plugins/context-menu.umd.js.map +1 -1
- package/umd/plugins/editing.umd.js +1 -1
- package/umd/plugins/editing.umd.js.map +1 -1
- package/umd/plugins/export.umd.js.map +1 -1
- package/umd/plugins/filtering.umd.js.map +1 -1
- package/umd/plugins/grouping-columns.umd.js +1 -1
- package/umd/plugins/grouping-columns.umd.js.map +1 -1
- package/umd/plugins/grouping-rows.umd.js.map +1 -1
- package/umd/plugins/multi-sort.umd.js.map +1 -1
- package/umd/plugins/pinned-columns.umd.js.map +1 -1
- package/umd/plugins/print.umd.js +1 -1
- package/umd/plugins/print.umd.js.map +1 -1
- package/umd/plugins/reorder-columns.umd.js.map +1 -1
- package/umd/plugins/reorder-rows.umd.js.map +1 -1
- package/umd/plugins/responsive.umd.js +1 -1
- package/umd/plugins/responsive.umd.js.map +1 -1
- package/umd/plugins/tree.umd.js.map +1 -1
- package/umd/plugins/undo-redo.umd.js +1 -1
- package/umd/plugins/undo-redo.umd.js.map +1 -1
- package/umd/plugins/visibility.umd.js.map +1 -1
package/lib/core/grid.d.ts
CHANGED
|
@@ -228,6 +228,14 @@ export declare class DataGridElement<T = any> extends HTMLElement implements Int
|
|
|
228
228
|
*
|
|
229
229
|
* @param rowId - The row's unique identifier (from getRowId)
|
|
230
230
|
* @param loading - Whether the row is loading
|
|
231
|
+
*
|
|
232
|
+
* @example
|
|
233
|
+
* ```typescript
|
|
234
|
+
* // Show loading while saving row data
|
|
235
|
+
* grid.setRowLoading('row-123', true);
|
|
236
|
+
* await saveRow(rowData);
|
|
237
|
+
* grid.setRowLoading('row-123', false);
|
|
238
|
+
* ```
|
|
231
239
|
*/
|
|
232
240
|
setRowLoading(rowId: string, loading: boolean): void;
|
|
233
241
|
/**
|
|
@@ -237,6 +245,14 @@ export declare class DataGridElement<T = any> extends HTMLElement implements Int
|
|
|
237
245
|
* @param rowId - The row's unique identifier
|
|
238
246
|
* @param field - The column field
|
|
239
247
|
* @param loading - Whether the cell is loading
|
|
248
|
+
*
|
|
249
|
+
* @example
|
|
250
|
+
* ```typescript
|
|
251
|
+
* // Show loading while validating a single field
|
|
252
|
+
* grid.setCellLoading('row-123', 'email', true);
|
|
253
|
+
* const valid = await validateEmail(newValue);
|
|
254
|
+
* grid.setCellLoading('row-123', 'email', false);
|
|
255
|
+
* ```
|
|
240
256
|
*/
|
|
241
257
|
setCellLoading(rowId: string, field: string, loading: boolean): void;
|
|
242
258
|
/**
|
|
@@ -687,7 +703,7 @@ export declare class DataGridElement<T = any> extends HTMLElement implements Int
|
|
|
687
703
|
*
|
|
688
704
|
* @example
|
|
689
705
|
* ```typescript
|
|
690
|
-
* const grid =
|
|
706
|
+
* const grid = queryGrid('tbw-grid');
|
|
691
707
|
* await grid.ready();
|
|
692
708
|
* console.log('Grid is ready, rows:', grid.rows.length);
|
|
693
709
|
* ```
|
|
@@ -1179,7 +1195,7 @@ export declare class DataGridElement<T = any> extends HTMLElement implements Int
|
|
|
1179
1195
|
* @example
|
|
1180
1196
|
* ```typescript
|
|
1181
1197
|
* // Restore saved state on page load
|
|
1182
|
-
* const grid =
|
|
1198
|
+
* const grid = queryGrid('tbw-grid');
|
|
1183
1199
|
* const saved = localStorage.getItem('myGridState');
|
|
1184
1200
|
* if (saved) {
|
|
1185
1201
|
* grid.columnState = JSON.parse(saved);
|
|
@@ -0,0 +1,164 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Centralized diagnostic messages for @toolbox-web/grid.
|
|
3
|
+
*
|
|
4
|
+
* Every user-facing warning, error, or info message in the grid has a unique
|
|
5
|
+
* diagnostic code (e.g. `TBW001`). Each code maps to a section on the online
|
|
6
|
+
* troubleshooting page, giving developers a direct link to resolution steps.
|
|
7
|
+
*
|
|
8
|
+
* ## Usage
|
|
9
|
+
*
|
|
10
|
+
* ```ts
|
|
11
|
+
* import { MISSING_BREAKPOINT, warnDiagnostic, throwDiagnostic } from './diagnostics';
|
|
12
|
+
*
|
|
13
|
+
* // Warn with a code
|
|
14
|
+
* warnDiagnostic(MISSING_BREAKPOINT, 'Set a breakpoint...', gridId);
|
|
15
|
+
*
|
|
16
|
+
* // Throw with a code
|
|
17
|
+
* throwDiagnostic(MISSING_ROW_ID, 'Configure getRowId...', gridId);
|
|
18
|
+
* ```
|
|
19
|
+
*
|
|
20
|
+
* Plugins should prefer `this.warn(MISSING_BREAKPOINT, message)` via BaseGridPlugin
|
|
21
|
+
* instead of importing this module directly.
|
|
22
|
+
*
|
|
23
|
+
* @internal
|
|
24
|
+
*/
|
|
25
|
+
/**
|
|
26
|
+
* Build the `[tbw-grid]` or `[tbw-grid#my-id]` log prefix.
|
|
27
|
+
* Pass `pluginName` for a scoped prefix like `[tbw-grid:SelectionPlugin]`.
|
|
28
|
+
*/
|
|
29
|
+
export declare function gridPrefix(gridId?: string, pluginName?: string): string;
|
|
30
|
+
/**
|
|
31
|
+
* Diagnostic codes used across the grid library.
|
|
32
|
+
*
|
|
33
|
+
* Each code is an individual export so that unused codes are tree-shaken
|
|
34
|
+
* from bundles that don't reference them (esbuild can't tree-shake
|
|
35
|
+
* properties from a single object).
|
|
36
|
+
*
|
|
37
|
+
* Naming: TBW + 3-digit number.
|
|
38
|
+
* Ranges:
|
|
39
|
+
* 001–019 Configuration validation (missing plugins, bad config)
|
|
40
|
+
* 020–029 Plugin lifecycle (dependencies, incompatibilities, deprecation)
|
|
41
|
+
* 030–039 Feature registry
|
|
42
|
+
* 040–049 Row operations (row ID, row mutations)
|
|
43
|
+
* 050–059 Column operations (width, template)
|
|
44
|
+
* 060–069 Rendering (callbacks, formatters, external views)
|
|
45
|
+
* 070–079 Shell (tool panels, header/toolbar content)
|
|
46
|
+
* 080–089 Editing & editors
|
|
47
|
+
* 090–099 Print
|
|
48
|
+
* 100–109 Clipboard
|
|
49
|
+
* 110–119 Plugin-specific (responsive, undo-redo, grouping-columns)
|
|
50
|
+
* 120–129 Style injection
|
|
51
|
+
* 130–139 Attribute parsing
|
|
52
|
+
*/
|
|
53
|
+
/** Column uses a plugin-owned property but the plugin is not loaded. */
|
|
54
|
+
export declare const MISSING_PLUGIN: "TBW001";
|
|
55
|
+
/** Grid config uses a plugin-owned property but the plugin is not loaded. */
|
|
56
|
+
export declare const MISSING_PLUGIN_CONFIG: "TBW002";
|
|
57
|
+
/** Plugin config rule violation (error severity). */
|
|
58
|
+
export declare const CONFIG_RULE_ERROR: "TBW003";
|
|
59
|
+
/** Plugin config rule violation (warning severity). */
|
|
60
|
+
export declare const CONFIG_RULE_WARN: "TBW004";
|
|
61
|
+
/** Required plugin dependency is missing. */
|
|
62
|
+
export declare const MISSING_DEPENDENCY: "TBW020";
|
|
63
|
+
/** Optional plugin dependency is missing. */
|
|
64
|
+
export declare const OPTIONAL_DEPENDENCY: "TBW021";
|
|
65
|
+
/** Two loaded plugins are incompatible. */
|
|
66
|
+
export declare const INCOMPATIBLE_PLUGINS: "TBW022";
|
|
67
|
+
/** Plugin uses deprecated hooks. */
|
|
68
|
+
export declare const DEPRECATED_HOOK: "TBW023";
|
|
69
|
+
/** Error thrown inside a plugin event handler. */
|
|
70
|
+
export declare const PLUGIN_EVENT_ERROR: "TBW024";
|
|
71
|
+
/** Feature was re-registered (overwritten). */
|
|
72
|
+
export declare const FEATURE_REREGISTERED: "TBW030";
|
|
73
|
+
/** Feature configured but not imported. */
|
|
74
|
+
export declare const FEATURE_NOT_IMPORTED: "TBW031";
|
|
75
|
+
/** Feature depends on another feature that is not enabled. */
|
|
76
|
+
export declare const FEATURE_MISSING_DEP: "TBW032";
|
|
77
|
+
/** Cannot determine row ID (no getRowId and no id property). */
|
|
78
|
+
export declare const MISSING_ROW_ID: "TBW040";
|
|
79
|
+
/** Row with given ID not found. */
|
|
80
|
+
export declare const ROW_NOT_FOUND: "TBW041";
|
|
81
|
+
/** Column has an invalid CSS width value. */
|
|
82
|
+
export declare const INVALID_COLUMN_WIDTH: "TBW050";
|
|
83
|
+
/** rowClass callback threw an error. */
|
|
84
|
+
export declare const ROW_CLASS_ERROR: "TBW060";
|
|
85
|
+
/** cellClass callback threw an error. */
|
|
86
|
+
export declare const CELL_CLASS_ERROR: "TBW061";
|
|
87
|
+
/** Column format function threw an error. */
|
|
88
|
+
export declare const FORMAT_ERROR: "TBW062";
|
|
89
|
+
/** External view mount() threw an error. */
|
|
90
|
+
export declare const VIEW_MOUNT_ERROR: "TBW063";
|
|
91
|
+
/** External view event dispatch error. */
|
|
92
|
+
export declare const VIEW_DISPATCH_ERROR: "TBW064";
|
|
93
|
+
/** Tool panel missing required id or title. */
|
|
94
|
+
export declare const TOOL_PANEL_MISSING_ATTR: "TBW070";
|
|
95
|
+
/** No tool panels registered. */
|
|
96
|
+
export declare const NO_TOOL_PANELS: "TBW071";
|
|
97
|
+
/** Tool panel section not found. */
|
|
98
|
+
export declare const TOOL_PANEL_NOT_FOUND: "TBW072";
|
|
99
|
+
/** Tool panel already registered. */
|
|
100
|
+
export declare const TOOL_PANEL_DUPLICATE: "TBW073";
|
|
101
|
+
/** Header content already registered. */
|
|
102
|
+
export declare const HEADER_CONTENT_DUPLICATE: "TBW074";
|
|
103
|
+
/** Toolbar content already registered. */
|
|
104
|
+
export declare const TOOLBAR_CONTENT_DUPLICATE: "TBW075";
|
|
105
|
+
/** External editor mount() threw an error. */
|
|
106
|
+
export declare const EDITOR_MOUNT_ERROR: "TBW080";
|
|
107
|
+
/** Print already in progress. */
|
|
108
|
+
export declare const PRINT_IN_PROGRESS: "TBW090";
|
|
109
|
+
/** Grid not available for printing. */
|
|
110
|
+
export declare const PRINT_NO_GRID: "TBW091";
|
|
111
|
+
/** Print operation failed. */
|
|
112
|
+
export declare const PRINT_FAILED: "TBW092";
|
|
113
|
+
/** Multiple elements share the same grid ID (print isolation issue). */
|
|
114
|
+
export declare const PRINT_DUPLICATE_ID: "TBW093";
|
|
115
|
+
/** Clipboard API write failed. */
|
|
116
|
+
export declare const CLIPBOARD_FAILED: "TBW100";
|
|
117
|
+
/** ResponsivePlugin: no breakpoint configured. */
|
|
118
|
+
export declare const MISSING_BREAKPOINT: "TBW110";
|
|
119
|
+
/** UndoRedoPlugin: transaction already in progress. */
|
|
120
|
+
export declare const TRANSACTION_IN_PROGRESS: "TBW111";
|
|
121
|
+
/** UndoRedoPlugin: no transaction in progress. */
|
|
122
|
+
export declare const NO_TRANSACTION: "TBW112";
|
|
123
|
+
/** GroupingColumnsPlugin: missing id or header on column group definition. */
|
|
124
|
+
export declare const COLUMN_GROUP_NO_ID: "TBW113";
|
|
125
|
+
/** GroupingColumnsPlugin: conflicting columnGroups sources. */
|
|
126
|
+
export declare const COLUMN_GROUPS_CONFLICT: "TBW114";
|
|
127
|
+
/** Failed to extract grid.css from document stylesheets. */
|
|
128
|
+
export declare const STYLE_EXTRACT_FAILED: "TBW120";
|
|
129
|
+
/** Could not find grid.css in document.styleSheets. */
|
|
130
|
+
export declare const STYLE_NOT_FOUND: "TBW121";
|
|
131
|
+
/** Invalid JSON in an HTML attribute. */
|
|
132
|
+
export declare const INVALID_ATTRIBUTE_JSON: "TBW130";
|
|
133
|
+
export type DiagnosticCode = typeof MISSING_PLUGIN | typeof MISSING_PLUGIN_CONFIG | typeof CONFIG_RULE_ERROR | typeof CONFIG_RULE_WARN | typeof MISSING_DEPENDENCY | typeof OPTIONAL_DEPENDENCY | typeof INCOMPATIBLE_PLUGINS | typeof DEPRECATED_HOOK | typeof PLUGIN_EVENT_ERROR | typeof FEATURE_REREGISTERED | typeof FEATURE_NOT_IMPORTED | typeof FEATURE_MISSING_DEP | typeof MISSING_ROW_ID | typeof ROW_NOT_FOUND | typeof INVALID_COLUMN_WIDTH | typeof ROW_CLASS_ERROR | typeof CELL_CLASS_ERROR | typeof FORMAT_ERROR | typeof VIEW_MOUNT_ERROR | typeof VIEW_DISPATCH_ERROR | typeof TOOL_PANEL_MISSING_ATTR | typeof NO_TOOL_PANELS | typeof TOOL_PANEL_NOT_FOUND | typeof TOOL_PANEL_DUPLICATE | typeof HEADER_CONTENT_DUPLICATE | typeof TOOLBAR_CONTENT_DUPLICATE | typeof EDITOR_MOUNT_ERROR | typeof PRINT_IN_PROGRESS | typeof PRINT_NO_GRID | typeof PRINT_FAILED | typeof PRINT_DUPLICATE_ID | typeof CLIPBOARD_FAILED | typeof MISSING_BREAKPOINT | typeof TRANSACTION_IN_PROGRESS | typeof NO_TRANSACTION | typeof COLUMN_GROUP_NO_ID | typeof COLUMN_GROUPS_CONFLICT | typeof STYLE_EXTRACT_FAILED | typeof STYLE_NOT_FOUND | typeof INVALID_ATTRIBUTE_JSON;
|
|
134
|
+
/**
|
|
135
|
+
* Format a diagnostic message with prefix, code, and docs link.
|
|
136
|
+
*
|
|
137
|
+
* Output format:
|
|
138
|
+
* ```
|
|
139
|
+
* [tbw-grid#my-id] TBW001: Your message here.
|
|
140
|
+
*
|
|
141
|
+
* → More info: https://toolboxjs.com/grid/errors#tbw001
|
|
142
|
+
* ```
|
|
143
|
+
*/
|
|
144
|
+
export declare function formatDiagnostic(code: DiagnosticCode, message: string, gridId?: string, pluginName?: string): string;
|
|
145
|
+
/**
|
|
146
|
+
* Throw an error with a diagnostic code and docs link.
|
|
147
|
+
* Use for configuration errors and API misuse that should halt execution.
|
|
148
|
+
*/
|
|
149
|
+
export declare function throwDiagnostic(code: DiagnosticCode, message: string, gridId?: string, pluginName?: string): never;
|
|
150
|
+
/**
|
|
151
|
+
* Log a warning with a diagnostic code and docs link.
|
|
152
|
+
* Use for recoverable issues the developer should fix.
|
|
153
|
+
*/
|
|
154
|
+
export declare function warnDiagnostic(code: DiagnosticCode, message: string, gridId?: string, pluginName?: string): void;
|
|
155
|
+
/**
|
|
156
|
+
* Log an info message with a diagnostic code and docs link.
|
|
157
|
+
* Use for optional/soft dependency notifications.
|
|
158
|
+
*/
|
|
159
|
+
export declare function infoDiagnostic(code: DiagnosticCode, message: string, gridId?: string, pluginName?: string): void;
|
|
160
|
+
/**
|
|
161
|
+
* Log an error with a diagnostic code and docs link.
|
|
162
|
+
* Use for non-throwing errors (e.g., failed async operations).
|
|
163
|
+
*/
|
|
164
|
+
export declare function errorDiagnostic(code: DiagnosticCode, message: string, gridId?: string, pluginName?: string): void;
|
|
@@ -1,12 +1,61 @@
|
|
|
1
1
|
import { ColumnConfig, GridHost, InternalGrid, SortState } from '../types';
|
|
2
2
|
/**
|
|
3
|
-
* Default comparator
|
|
4
|
-
*
|
|
3
|
+
* Default comparator used when no column-level `sortComparator` is configured.
|
|
4
|
+
* Pushes `null`/`undefined` to the end and compares remaining values via `>` / `<`
|
|
5
|
+
* operators, which works correctly for numbers and falls back to lexicographic
|
|
6
|
+
* comparison for strings.
|
|
7
|
+
*
|
|
8
|
+
* Use this as a fallback inside a custom `sortComparator` when you only need
|
|
9
|
+
* special handling for certain values:
|
|
10
|
+
*
|
|
11
|
+
* @example
|
|
12
|
+
* ```typescript
|
|
13
|
+
* import { defaultComparator } from '@toolbox-web/grid';
|
|
14
|
+
*
|
|
15
|
+
* const column = {
|
|
16
|
+
* field: 'priority',
|
|
17
|
+
* sortComparator: (a, b, rowA, rowB) => {
|
|
18
|
+
* // Pin "urgent" to the top, then fall back to default ordering
|
|
19
|
+
* if (a === 'urgent') return -1;
|
|
20
|
+
* if (b === 'urgent') return 1;
|
|
21
|
+
* return defaultComparator(a, b);
|
|
22
|
+
* },
|
|
23
|
+
* };
|
|
24
|
+
* ```
|
|
25
|
+
*
|
|
26
|
+
* @see {@link BaseColumnConfig.sortComparator} for column-level comparators
|
|
27
|
+
* @see {@link builtInSort} for the full sort handler that uses this comparator
|
|
28
|
+
* @category Factory Functions
|
|
5
29
|
*/
|
|
6
30
|
export declare function defaultComparator(a: unknown, b: unknown): number;
|
|
7
31
|
/**
|
|
8
|
-
*
|
|
9
|
-
*
|
|
32
|
+
* The default `sortHandler` used when none is provided in {@link GridConfig.sortHandler}.
|
|
33
|
+
* Reads each column's `sortComparator` (falling back to {@link defaultComparator})
|
|
34
|
+
* and returns a sorted copy of the rows array.
|
|
35
|
+
*
|
|
36
|
+
* Use this as a fallback inside a custom `sortHandler` when you only need to
|
|
37
|
+
* intercept sorting for specific columns or add pre/post-processing:
|
|
38
|
+
*
|
|
39
|
+
* @example
|
|
40
|
+
* ```typescript
|
|
41
|
+
* import { builtInSort } from '@toolbox-web/grid';
|
|
42
|
+
* import type { SortHandler } from '@toolbox-web/grid';
|
|
43
|
+
*
|
|
44
|
+
* const customSort: SortHandler<Employee> = (rows, state, columns) => {
|
|
45
|
+
* // Server-side sort for the "salary" column, client-side for everything else
|
|
46
|
+
* if (state.field === 'salary') {
|
|
47
|
+
* return fetch(`/api/employees?sort=${state.field}&dir=${state.direction}`)
|
|
48
|
+
* .then(res => res.json());
|
|
49
|
+
* }
|
|
50
|
+
* return builtInSort(rows, state, columns);
|
|
51
|
+
* };
|
|
52
|
+
*
|
|
53
|
+
* grid.gridConfig = { sortHandler: customSort };
|
|
54
|
+
* ```
|
|
55
|
+
*
|
|
56
|
+
* @see {@link GridConfig.sortHandler} for configuring the handler
|
|
57
|
+
* @see {@link defaultComparator} for the comparator used per column
|
|
58
|
+
* @category Factory Functions
|
|
10
59
|
*/
|
|
11
60
|
export declare function builtInSort<T>(rows: T[], sortState: SortState, columns: ColumnConfig<T>[]): T[];
|
|
12
61
|
/**
|
|
@@ -4,14 +4,6 @@
|
|
|
4
4
|
* Used to show warnings only in development.
|
|
5
5
|
*/
|
|
6
6
|
export declare function isDevelopment(): boolean;
|
|
7
|
-
/**
|
|
8
|
-
* Build the `[tbw-grid]` or `[tbw-grid#my-id]` log prefix.
|
|
9
|
-
* Pass `pluginName` for a scoped prefix like `[tbw-grid:SelectionPlugin]`.
|
|
10
|
-
*
|
|
11
|
-
* @param gridId - The grid element's `id` attribute (optional)
|
|
12
|
-
* @param pluginName - Plugin display name to include (optional)
|
|
13
|
-
*/
|
|
14
|
-
export declare function gridPrefix(gridId?: string, pluginName?: string): string;
|
|
15
7
|
/**
|
|
16
8
|
* Generate accessible HTML for a boolean cell.
|
|
17
9
|
* Uses role="checkbox" with proper aria attributes.
|
|
@@ -1,7 +1,8 @@
|
|
|
1
|
+
import { DiagnosticCode } from '../internal/diagnostics';
|
|
1
2
|
import { ColumnConfig, ColumnState, GridPlugin, HeaderContentDefinition, IconValue, PluginNameMap, ToolPanelDefinition, DEFAULT_GRID_ICONS } from '../types';
|
|
2
3
|
import { AfterCellRenderContext, AfterRowRenderContext, CellClickEvent, CellEditor, CellMouseEvent, CellRenderer, GridElementRef, HeaderClickEvent, HeaderRenderer, PluginQuery, RowClickEvent, ScrollEvent } from './types';
|
|
3
4
|
export { PLUGIN_QUERIES } from './types';
|
|
4
|
-
export type { AfterCellRenderContext, AfterRowRenderContext, CellClickEvent, CellCoords, CellEditor, CellMouseEvent, CellRenderer, ContextMenuItem, ContextMenuParams, GridElementRef, HeaderClickEvent, HeaderRenderer, KeyboardModifiers, PluginCellRenderContext, PluginQuery, RowClickEvent, ScrollEvent } from './types';
|
|
5
|
+
export type { AfterCellRenderContext, AfterRowRenderContext, CellClickEvent, CellCoords, CellEditor, CellMouseEvent, CellRenderer, ContextMenuItem, ContextMenuParams, GridElementRef, HeaderClickEvent, HeaderRenderer, KeyboardModifiers, PluginCellRenderContext, PluginQuery, RowClickEvent, ScrollEvent, } from './types';
|
|
5
6
|
/**
|
|
6
7
|
* Grid element interface for plugins.
|
|
7
8
|
* Extends GridElementRef with plugin-specific methods.
|
|
@@ -622,9 +623,24 @@ export declare abstract class BaseGridPlugin<TConfig = unknown> implements GridP
|
|
|
622
623
|
*/
|
|
623
624
|
protected setIcon(element: HTMLElement, icon: IconValue): void;
|
|
624
625
|
/**
|
|
625
|
-
* Log a warning
|
|
626
|
+
* Log a warning with an optional diagnostic code.
|
|
627
|
+
*
|
|
628
|
+
* When a diagnostic code is provided, the message is formatted with the code
|
|
629
|
+
* and a link to the troubleshooting docs.
|
|
630
|
+
*
|
|
631
|
+
* @example
|
|
632
|
+
* ```ts
|
|
633
|
+
* this.warn('Something went wrong'); // plain
|
|
634
|
+
* this.warn(MISSING_BREAKPOINT, 'Set a breakpoint'); // with code + docs link
|
|
635
|
+
* ```
|
|
626
636
|
*/
|
|
627
637
|
protected warn(message: string): void;
|
|
638
|
+
protected warn(code: DiagnosticCode, message: string): void;
|
|
639
|
+
/**
|
|
640
|
+
* Throw an error with a diagnostic code and docs link.
|
|
641
|
+
* Use for configuration errors and API misuse that should halt execution.
|
|
642
|
+
*/
|
|
643
|
+
protected throwDiagnostic(code: DiagnosticCode, message: string): never;
|
|
628
644
|
/**
|
|
629
645
|
* Transform rows before rendering.
|
|
630
646
|
* Called during each render cycle before rows are rendered to the DOM.
|
|
@@ -7,6 +7,7 @@ import { AfterCellRenderContext, AfterRowRenderContext, BaseGridPlugin, CellClic
|
|
|
7
7
|
* Place plugins in the order you want their hooks to execute.
|
|
8
8
|
*/
|
|
9
9
|
export declare class PluginManager {
|
|
10
|
+
#private;
|
|
10
11
|
private grid;
|
|
11
12
|
/** Plugin instances in order of attachment */
|
|
12
13
|
private plugins;
|
|
@@ -20,6 +21,9 @@ export declare class PluginManager {
|
|
|
20
21
|
private headerRenderers;
|
|
21
22
|
/** Cell editors registered by plugins */
|
|
22
23
|
private cellEditors;
|
|
24
|
+
/** Cached hook presence flags — invalidated on plugin attach/detach */
|
|
25
|
+
private _hasAfterCellRender;
|
|
26
|
+
private _hasAfterRowRender;
|
|
23
27
|
/**
|
|
24
28
|
* Event listeners indexed by event type.
|
|
25
29
|
* Maps event type → Map<plugin instance → callback>.
|
|
@@ -35,8 +39,6 @@ export declare class PluginManager {
|
|
|
35
39
|
/** Set of plugin constructors that have been warned about deprecated hooks */
|
|
36
40
|
private static deprecationWarned;
|
|
37
41
|
constructor(grid: GridElement);
|
|
38
|
-
/** Build log prefix: `[tbw-grid]` or `[tbw-grid#my-id]` */
|
|
39
|
-
private get logPrefix();
|
|
40
42
|
/**
|
|
41
43
|
* Attach all plugins from the config.
|
|
42
44
|
*/
|
|
@@ -129,7 +131,7 @@ export declare class PluginManager {
|
|
|
129
131
|
afterCellRender(context: AfterCellRenderContext): void;
|
|
130
132
|
/**
|
|
131
133
|
* Check if any plugin has the afterCellRender hook implemented.
|
|
132
|
-
*
|
|
134
|
+
* Cached — invalidated on plugin attach/detach.
|
|
133
135
|
*/
|
|
134
136
|
hasAfterCellRenderHook(): boolean;
|
|
135
137
|
/**
|
|
@@ -141,7 +143,7 @@ export declare class PluginManager {
|
|
|
141
143
|
afterRowRender(context: AfterRowRenderContext): void;
|
|
142
144
|
/**
|
|
143
145
|
* Check if any plugin has the afterRowRender hook implemented.
|
|
144
|
-
*
|
|
146
|
+
* Cached — invalidated on plugin attach/detach.
|
|
145
147
|
*/
|
|
146
148
|
hasAfterRowRenderHook(): boolean;
|
|
147
149
|
/**
|
package/lib/core/types.d.ts
CHANGED
|
@@ -20,8 +20,9 @@ export type RowPositionEntry = RowPosition;
|
|
|
20
20
|
*
|
|
21
21
|
* @example
|
|
22
22
|
* ```typescript
|
|
23
|
-
* // Query existing grid
|
|
24
|
-
*
|
|
23
|
+
* // Query existing grid with type safety
|
|
24
|
+
* import { queryGrid } from '@toolbox-web/grid';
|
|
25
|
+
* const grid = queryGrid<Employee>('tbw-grid');
|
|
25
26
|
* grid.rows = employees;
|
|
26
27
|
* grid.on('cell-click', (detail) => console.log(detail));
|
|
27
28
|
*
|
package/lib/features/registry.js
CHANGED
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
import{setFeatureResolver as o}from"@toolbox-web/grid";const
|
|
1
|
+
import{setFeatureResolver as o}from"@toolbox-web/grid";function e(o,e,t,n){console.warn(function(o,e){return`[tbw-grid] ${o}: ${e}\n\n → More info: ${function(o){return`https://toolboxjs.com/grid/errors#${o.toLowerCase()}`}(o)}`}(o,e))}const t=/* @__PURE__ */new Map,n=/* @__PURE__ */new Set,r=()=>"undefined"!=typeof window&&("localhost"===window.location?.hostname||"127.0.0.1"===window.location?.hostname);function i(o,n){r()&&t.has(o)&&e("TBW030",`Feature "${o}" was re-registered. Previous registration overwritten.`),t.set(o,{factory:n,name:o})}function s(o){return t.has(o)}function c(o){return t.get(o)?.factory}function f(){return Array.from(t.keys())}const u={undoRedo:["editing"],clipboard:["selection"]},d={sorting:"multiSort",reorder:"reorderColumns",rowReorder:"reorderRows"};function a(o,i){const s=t.get(o);if(s)return s.factory(i);if(r()&&!n.has(o)){n.add(o);const t=o.replace(/([a-z])([A-Z])/g,"$1-$2").toLowerCase();e("TBW031",`Feature "${o}" is configured but not registered.\nAdd this import to enable it:\n\n import '@toolbox-web/grid/features/${t}';\n`)}}function l(o){const t=[],n=[],i={...o};for(const[e,r]of Object.entries(d))void 0!==i[e]&&void 0===i[r]&&(i[r]=i[e]),delete i[e];for(const[e,r]of Object.entries(i))void 0!==r&&!1!==r&&n.push(e);!function(o){const t=new Set(o);for(const n of o){const o=u[n];if(o)for(const i of o)t.has(i)||r()&&e("TBW032",`Feature "${n}" requires "${i}" to be enabled. Add "${i}" to your features configuration.`)}}(n);const s=["selection","editing",...n.filter(o=>"selection"!==o&&"editing"!==o)],c=[...new Set(s)].filter(o=>n.includes(o));for(const e of c){const o=i[e];if(void 0===o||!1===o)continue;const n=a(e,o);n&&t.push(n)}return t}function w(){t.clear(),n.clear()}o(l);export{w as clearFeatureRegistry,a as createPluginFromFeature,l as createPluginsFromFeatures,c as getFeatureFactory,f as getRegisteredFeatures,s as isFeatureRegistered,i as registerFeature};
|
|
2
2
|
//# sourceMappingURL=registry.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"registry.js","sources":["../../../../../libs/grid/src/lib/features/registry.ts"],"sourcesContent":["/**\n * Core Feature Registry for @toolbox-web/grid\n *\n * This module provides a framework-agnostic registry for plugin factories.\n * Features are registered via side-effect imports, enabling tree-shaking\n * while maintaining a clean declarative API.\n *\n * @example\n * ```typescript\n * // Import features you need (side-effect imports)\n * import '@toolbox-web/grid/features/selection';\n * import '@toolbox-web/grid/features/filtering';\n *\n * // Configure grid declaratively\n * grid.gridConfig = {\n * features: {\n * selection: 'range',\n * filtering: { debounceMs: 200 },\n * },\n * };\n * ```\n *\n * @packageDocumentation\n * @module Features\n */\n\nimport type { FeatureConfig, GridPlugin } from '../core/types';\nimport { setFeatureResolver } from '../core/internal/feature-hook';\n\n// #region Types\n\n/** Feature name — keys of the augmented FeatureConfig interface. */\nexport type FeatureName = keyof FeatureConfig;\n\n/** Factory function that creates a plugin from a feature config value. */\nexport type PluginFactory<TConfig = unknown> = (config: TConfig) => GridPlugin;\n\ninterface RegistryEntry {\n factory: PluginFactory;\n name: string;\n}\n\n// #endregion\n\n// #region Registry State\n\nconst featureRegistry = new Map<string, RegistryEntry>();\nconst warnedFeatures = new Set<string>();\n\n// #endregion\n\n// #region Registration API\n\n/** Runtime dev-mode check (localhost or 127.0.0.1). */\nconst isDev = (): boolean =>\n typeof window !== 'undefined' &&\n (window.location?.hostname === 'localhost' || window.location?.hostname === '127.0.0.1');\n\n/**\n * Register a feature's plugin factory.\n * Called by side-effect feature imports (e.g., `import '@toolbox-web/grid/features/selection'`).\n *\n * @param name - The feature name (matches a key on FeatureConfig)\n * @param factory - Function that creates a plugin instance from config\n */\nexport function registerFeature<K extends FeatureName>(name: K, factory: PluginFactory<FeatureConfig[K]>): void;\nexport function registerFeature(name: string, factory: PluginFactory): void;\nexport function registerFeature(name: string, factory: PluginFactory): void {\n if (isDev() && featureRegistry.has(name)) {\n console.warn(`[tbw-grid] Feature \"${name}\" was re-registered. Previous registration overwritten.`);\n }\n featureRegistry.set(name, { factory, name });\n}\n\n/**\n * Check if a feature has been registered.\n */\nexport function isFeatureRegistered(name: string): boolean {\n return featureRegistry.has(name);\n}\n\n/**\n * Get a registered feature's factory. Returns undefined if not registered.\n */\nexport function getFeatureFactory(name: string): PluginFactory | undefined {\n return featureRegistry.get(name)?.factory;\n}\n\n/**\n * Get all registered feature names.\n */\nexport function getRegisteredFeatures(): string[] {\n return Array.from(featureRegistry.keys());\n}\n\n// #endregion\n\n// #region Plugin Creation\n\n/**\n * Plugin dependency declarations.\n * Some plugins require others to be loaded first.\n */\nconst PLUGIN_DEPENDENCIES: Record<string, string[]> = {\n undoRedo: ['editing'],\n clipboard: ['selection'],\n};\n\n/**\n * Deprecated alias mappings.\n * When both alias and primary are set, primary takes precedence.\n */\nconst FEATURE_ALIASES: Record<string, string> = {\n sorting: 'multiSort',\n reorder: 'reorderColumns',\n rowReorder: 'reorderRows',\n};\n\n/**\n * Create a plugin instance for a single feature.\n * Shows a warning if the feature is not registered.\n */\nexport function createPluginFromFeature(name: string, config: unknown): GridPlugin | undefined {\n const entry = featureRegistry.get(name);\n\n if (!entry) {\n if (isDev() && !warnedFeatures.has(name)) {\n warnedFeatures.add(name);\n const kebab = name.replace(/([a-z])([A-Z])/g, '$1-$2').toLowerCase();\n console.warn(\n `[tbw-grid] Feature \"${name}\" is configured but not registered.\\n` +\n `Add this import to enable it:\\n\\n` +\n ` import '@toolbox-web/grid/features/${kebab}';\\n`,\n );\n }\n return undefined;\n }\n\n return entry.factory(config);\n}\n\n/**\n * Validate feature dependencies and log warnings for missing ones.\n */\nfunction validateDependencies(featureNames: string[]): void {\n const featureSet = new Set(featureNames);\n\n for (const feature of featureNames) {\n const deps = PLUGIN_DEPENDENCIES[feature];\n if (!deps) continue;\n\n for (const dep of deps) {\n if (!featureSet.has(dep)) {\n if (isDev()) {\n console.warn(\n `[tbw-grid] Feature \"${feature}\" requires \"${dep}\" to be enabled. ` +\n `Add \"${dep}\" to your features configuration.`,\n );\n }\n }\n }\n }\n}\n\n/**\n * Create plugin instances from a features configuration object.\n *\n * Handles:\n * - Deprecated alias resolution (sorting → multiSort, etc.)\n * - Dependency validation (clipboard needs selection)\n * - Dependency ordering (selection before clipboard)\n * - Skipping false/undefined values\n *\n * @param features - Partial FeatureConfig object\n * @returns Array of plugin instances ready for gridConfig.plugins\n */\nexport function createPluginsFromFeatures(features: Record<string, unknown>): GridPlugin[] {\n const plugins: GridPlugin[] = [];\n const enabledFeatures: string[] = [];\n\n // Resolve deprecated aliases: use primary name, skip alias if primary is set\n const effective: Record<string, unknown> = { ...features };\n for (const [alias, primary] of Object.entries(FEATURE_ALIASES)) {\n if (effective[alias] !== undefined && effective[primary] === undefined) {\n effective[primary] = effective[alias];\n }\n delete effective[alias];\n }\n\n // Collect enabled feature names\n for (const [key, value] of Object.entries(effective)) {\n if (value === undefined || value === false) continue;\n enabledFeatures.push(key);\n }\n\n // Validate dependencies\n validateDependencies(enabledFeatures);\n\n // Create plugins in dependency order: dep-targets first, then the rest\n const dependencyOrder: string[] = [\n 'selection',\n 'editing',\n ...enabledFeatures.filter((f) => f !== 'selection' && f !== 'editing'),\n ];\n const orderedFeatures = [...new Set(dependencyOrder)].filter((f) => enabledFeatures.includes(f));\n\n for (const featureName of orderedFeatures) {\n const config = effective[featureName];\n if (config === undefined || config === false) continue;\n\n const plugin = createPluginFromFeature(featureName, config);\n if (plugin) {\n plugins.push(plugin);\n }\n }\n\n return plugins;\n}\n\n// #endregion\n\n// #region Auto-Registration\n\n// Wire feature resolver into grid core so `gridConfig.features` is handled automatically.\n// This runs when any feature module is imported (they all import this registry).\nsetFeatureResolver(createPluginsFromFeatures as (features: Record<string, unknown>) => GridPlugin[]);\n\n// #endregion\n\n// #region Testing Utilities\n\n/**\n * Clear the registry. For testing only.\n * @internal\n */\nexport function clearFeatureRegistry(): void {\n featureRegistry.clear();\n warnedFeatures.clear();\n}\n\n// #endregion\n"],"names":["featureRegistry","Map","warnedFeatures","Set","isDev","window","location","hostname","registerFeature","name","factory","has","console","warn","set","isFeatureRegistered","getFeatureFactory","get","getRegisteredFeatures","Array","from","keys","PLUGIN_DEPENDENCIES","undoRedo","clipboard","FEATURE_ALIASES","sorting","reorder","rowReorder","createPluginFromFeature","config","entry","add","kebab","replace","toLowerCase","createPluginsFromFeatures","features","plugins","enabledFeatures","effective","alias","primary","Object","entries","key","value","push","featureNames","featureSet","feature","deps","dep","validateDependencies","dependencyOrder","filter","f","orderedFeatures","includes","featureName","plugin","clearFeatureRegistry","clear","setFeatureResolver"],"mappings":"uDA8CA,MAAMA,qBAAsBC,IACtBC,qBAAqBC,IAOrBC,EAAQ,IACM,oBAAXC,SACwB,cAA9BA,OAAOC,UAAUC,UAA0D,cAA9BF,OAAOC,UAAUC,UAW1D,SAASC,EAAgBC,EAAcC,GACxCN,KAAWJ,EAAgBW,IAAIF,IACjCG,QAAQC,KAAK,uBAAuBJ,4DAEtCT,EAAgBc,IAAIL,EAAM,CAAEC,UAASD,QACvC,CAKO,SAASM,EAAoBN,GAClC,OAAOT,EAAgBW,IAAIF,EAC7B,CAKO,SAASO,EAAkBP,GAChC,OAAOT,EAAgBiB,IAAIR,IAAOC,OACpC,CAKO,SAASQ,IACd,OAAOC,MAAMC,KAAKpB,EAAgBqB,OACpC,CAUA,MAAMC,EAAgD,CACpDC,SAAU,CAAC,WACXC,UAAW,CAAC,cAORC,EAA0C,CAC9CC,QAAS,YACTC,QAAS,iBACTC,WAAY,eAOP,SAASC,EAAwBpB,EAAcqB,GACpD,MAAMC,EAAQ/B,EAAgBiB,IAAIR,GAElC,GAAKsB,EAaL,OAAOA,EAAMrB,QAAQoB,GAZnB,GAAI1B,MAAYF,EAAeS,IAAIF,GAAO,CACxCP,EAAe8B,IAAIvB,GACnB,MAAMwB,EAAQxB,EAAKyB,QAAQ,kBAAmB,SAASC,cACvDvB,QAAQC,KACN,uBAAuBJ,+GAEmBwB,QAE9C,CAKJ,CAqCO,SAASG,EAA0BC,GACxC,MAAMC,EAAwB,GACxBC,EAA4B,GAG5BC,EAAqC,IAAKH,GAChD,IAAA,MAAYI,EAAOC,KAAYC,OAAOC,QAAQnB,QACnB,IAArBe,EAAUC,SAA+C,IAAvBD,EAAUE,KAC9CF,EAAUE,GAAWF,EAAUC,WAE1BD,EAAUC,GAInB,IAAA,MAAYI,EAAKC,KAAUH,OAAOC,QAAQJ,QAC1B,IAAVM,IAAiC,IAAVA,GAC3BP,EAAgBQ,KAAKF,IAhDzB,SAA8BG,GAC5B,MAAMC,EAAa,IAAI9C,IAAI6C,GAE3B,IAAA,MAAWE,KAAWF,EAAc,CAClC,MAAMG,EAAO7B,EAAoB4B,GACjC,GAAKC,EAEL,IAAA,MAAWC,KAAOD,EACXF,EAAWtC,IAAIyC,IACdhD,KACFQ,QAAQC,KACN,uBAAuBqC,gBAAsBE,0BACnCA,qCAKpB,CACF,CAkCEC,CAAqBd,GAGrB,MAAMe,EAA4B,CAChC,YACA,aACGf,EAAgBgB,OAAQC,GAAY,cAANA,GAA2B,YAANA,IAElDC,EAAkB,IAAI,IAAItD,IAAImD,IAAkBC,OAAQC,GAAMjB,EAAgBmB,SAASF,IAE7F,IAAA,MAAWG,KAAeF,EAAiB,CACzC,MAAM3B,EAASU,EAAUmB,GACzB,QAAe,IAAX7B,IAAmC,IAAXA,EAAkB,SAE9C,MAAM8B,EAAS/B,EAAwB8B,EAAa7B,GAChD8B,GACFtB,EAAQS,KAAKa,EAEjB,CAEA,OAAOtB,CACT,CAkBO,SAASuB,IACd7D,EAAgB8D,QAChB5D,EAAe4D,OACjB,CAbAC,EAAmB3B"}
|
|
1
|
+
{"version":3,"file":"registry.js","sources":["../../../../../libs/grid/src/lib/core/internal/diagnostics.ts","../../../../../libs/grid/src/lib/features/registry.ts"],"sourcesContent":["/**\n * Centralized diagnostic messages for @toolbox-web/grid.\n *\n * Every user-facing warning, error, or info message in the grid has a unique\n * diagnostic code (e.g. `TBW001`). Each code maps to a section on the online\n * troubleshooting page, giving developers a direct link to resolution steps.\n *\n * ## Usage\n *\n * ```ts\n * import { MISSING_BREAKPOINT, warnDiagnostic, throwDiagnostic } from './diagnostics';\n *\n * // Warn with a code\n * warnDiagnostic(MISSING_BREAKPOINT, 'Set a breakpoint...', gridId);\n *\n * // Throw with a code\n * throwDiagnostic(MISSING_ROW_ID, 'Configure getRowId...', gridId);\n * ```\n *\n * Plugins should prefer `this.warn(MISSING_BREAKPOINT, message)` via BaseGridPlugin\n * instead of importing this module directly.\n *\n * @internal\n */\n\n// #region Grid Prefix\n\n/**\n * Build the `[tbw-grid]` or `[tbw-grid#my-id]` log prefix.\n * Pass `pluginName` for a scoped prefix like `[tbw-grid:SelectionPlugin]`.\n */\nexport function gridPrefix(gridId?: string, pluginName?: string): string {\n const id = gridId ? `#${gridId}` : '';\n const plugin = pluginName ? `:${pluginName}` : '';\n return `[tbw-grid${id}${plugin}]`;\n}\n\n// #endregion\n\n// #region Diagnostic Codes\n\n/**\n * Diagnostic codes used across the grid library.\n *\n * Each code is an individual export so that unused codes are tree-shaken\n * from bundles that don't reference them (esbuild can't tree-shake\n * properties from a single object).\n *\n * Naming: TBW + 3-digit number.\n * Ranges:\n * 001–019 Configuration validation (missing plugins, bad config)\n * 020–029 Plugin lifecycle (dependencies, incompatibilities, deprecation)\n * 030–039 Feature registry\n * 040–049 Row operations (row ID, row mutations)\n * 050–059 Column operations (width, template)\n * 060–069 Rendering (callbacks, formatters, external views)\n * 070–079 Shell (tool panels, header/toolbar content)\n * 080–089 Editing & editors\n * 090–099 Print\n * 100–109 Clipboard\n * 110–119 Plugin-specific (responsive, undo-redo, grouping-columns)\n * 120–129 Style injection\n * 130–139 Attribute parsing\n */\n\n// --- Config validation (001–019) ---\n/** Column uses a plugin-owned property but the plugin is not loaded. */\nexport const MISSING_PLUGIN = 'TBW001' as const;\n/** Grid config uses a plugin-owned property but the plugin is not loaded. */\nexport const MISSING_PLUGIN_CONFIG = 'TBW002' as const;\n/** Plugin config rule violation (error severity). */\nexport const CONFIG_RULE_ERROR = 'TBW003' as const;\n/** Plugin config rule violation (warning severity). */\nexport const CONFIG_RULE_WARN = 'TBW004' as const;\n\n// --- Plugin lifecycle (020–029) ---\n/** Required plugin dependency is missing. */\nexport const MISSING_DEPENDENCY = 'TBW020' as const;\n/** Optional plugin dependency is missing. */\nexport const OPTIONAL_DEPENDENCY = 'TBW021' as const;\n/** Two loaded plugins are incompatible. */\nexport const INCOMPATIBLE_PLUGINS = 'TBW022' as const;\n/** Plugin uses deprecated hooks. */\nexport const DEPRECATED_HOOK = 'TBW023' as const;\n/** Error thrown inside a plugin event handler. */\nexport const PLUGIN_EVENT_ERROR = 'TBW024' as const;\n\n// --- Feature registry (030–039) ---\n/** Feature was re-registered (overwritten). */\nexport const FEATURE_REREGISTERED = 'TBW030' as const;\n/** Feature configured but not imported. */\nexport const FEATURE_NOT_IMPORTED = 'TBW031' as const;\n/** Feature depends on another feature that is not enabled. */\nexport const FEATURE_MISSING_DEP = 'TBW032' as const;\n\n// --- Row operations (040–049) ---\n/** Cannot determine row ID (no getRowId and no id property). */\nexport const MISSING_ROW_ID = 'TBW040' as const;\n/** Row with given ID not found. */\nexport const ROW_NOT_FOUND = 'TBW041' as const;\n\n// --- Column operations (050–059) ---\n/** Column has an invalid CSS width value. */\nexport const INVALID_COLUMN_WIDTH = 'TBW050' as const;\n\n// --- Rendering callbacks (060–069) ---\n/** rowClass callback threw an error. */\nexport const ROW_CLASS_ERROR = 'TBW060' as const;\n/** cellClass callback threw an error. */\nexport const CELL_CLASS_ERROR = 'TBW061' as const;\n/** Column format function threw an error. */\nexport const FORMAT_ERROR = 'TBW062' as const;\n/** External view mount() threw an error. */\nexport const VIEW_MOUNT_ERROR = 'TBW063' as const;\n/** External view event dispatch error. */\nexport const VIEW_DISPATCH_ERROR = 'TBW064' as const;\n\n// --- Shell (070–079) ---\n/** Tool panel missing required id or title. */\nexport const TOOL_PANEL_MISSING_ATTR = 'TBW070' as const;\n/** No tool panels registered. */\nexport const NO_TOOL_PANELS = 'TBW071' as const;\n/** Tool panel section not found. */\nexport const TOOL_PANEL_NOT_FOUND = 'TBW072' as const;\n/** Tool panel already registered. */\nexport const TOOL_PANEL_DUPLICATE = 'TBW073' as const;\n/** Header content already registered. */\nexport const HEADER_CONTENT_DUPLICATE = 'TBW074' as const;\n/** Toolbar content already registered. */\nexport const TOOLBAR_CONTENT_DUPLICATE = 'TBW075' as const;\n\n// --- Editing & editors (080–089) ---\n/** External editor mount() threw an error. */\nexport const EDITOR_MOUNT_ERROR = 'TBW080' as const;\n\n// --- Print (090–099) ---\n/** Print already in progress. */\nexport const PRINT_IN_PROGRESS = 'TBW090' as const;\n/** Grid not available for printing. */\nexport const PRINT_NO_GRID = 'TBW091' as const;\n/** Print operation failed. */\nexport const PRINT_FAILED = 'TBW092' as const;\n/** Multiple elements share the same grid ID (print isolation issue). */\nexport const PRINT_DUPLICATE_ID = 'TBW093' as const;\n\n// --- Clipboard (100–109) ---\n/** Clipboard API write failed. */\nexport const CLIPBOARD_FAILED = 'TBW100' as const;\n\n// --- Plugin-specific (110–119) ---\n/** ResponsivePlugin: no breakpoint configured. */\nexport const MISSING_BREAKPOINT = 'TBW110' as const;\n/** UndoRedoPlugin: transaction already in progress. */\nexport const TRANSACTION_IN_PROGRESS = 'TBW111' as const;\n/** UndoRedoPlugin: no transaction in progress. */\nexport const NO_TRANSACTION = 'TBW112' as const;\n/** GroupingColumnsPlugin: missing id or header on column group definition. */\nexport const COLUMN_GROUP_NO_ID = 'TBW113' as const;\n/** GroupingColumnsPlugin: conflicting columnGroups sources. */\nexport const COLUMN_GROUPS_CONFLICT = 'TBW114' as const;\n\n// --- Style injection (120–129) ---\n/** Failed to extract grid.css from document stylesheets. */\nexport const STYLE_EXTRACT_FAILED = 'TBW120' as const;\n/** Could not find grid.css in document.styleSheets. */\nexport const STYLE_NOT_FOUND = 'TBW121' as const;\n\n// --- Attribute parsing (130–139) ---\n/** Invalid JSON in an HTML attribute. */\nexport const INVALID_ATTRIBUTE_JSON = 'TBW130' as const;\n\nexport type DiagnosticCode =\n | typeof MISSING_PLUGIN\n | typeof MISSING_PLUGIN_CONFIG\n | typeof CONFIG_RULE_ERROR\n | typeof CONFIG_RULE_WARN\n | typeof MISSING_DEPENDENCY\n | typeof OPTIONAL_DEPENDENCY\n | typeof INCOMPATIBLE_PLUGINS\n | typeof DEPRECATED_HOOK\n | typeof PLUGIN_EVENT_ERROR\n | typeof FEATURE_REREGISTERED\n | typeof FEATURE_NOT_IMPORTED\n | typeof FEATURE_MISSING_DEP\n | typeof MISSING_ROW_ID\n | typeof ROW_NOT_FOUND\n | typeof INVALID_COLUMN_WIDTH\n | typeof ROW_CLASS_ERROR\n | typeof CELL_CLASS_ERROR\n | typeof FORMAT_ERROR\n | typeof VIEW_MOUNT_ERROR\n | typeof VIEW_DISPATCH_ERROR\n | typeof TOOL_PANEL_MISSING_ATTR\n | typeof NO_TOOL_PANELS\n | typeof TOOL_PANEL_NOT_FOUND\n | typeof TOOL_PANEL_DUPLICATE\n | typeof HEADER_CONTENT_DUPLICATE\n | typeof TOOLBAR_CONTENT_DUPLICATE\n | typeof EDITOR_MOUNT_ERROR\n | typeof PRINT_IN_PROGRESS\n | typeof PRINT_NO_GRID\n | typeof PRINT_FAILED\n | typeof PRINT_DUPLICATE_ID\n | typeof CLIPBOARD_FAILED\n | typeof MISSING_BREAKPOINT\n | typeof TRANSACTION_IN_PROGRESS\n | typeof NO_TRANSACTION\n | typeof COLUMN_GROUP_NO_ID\n | typeof COLUMN_GROUPS_CONFLICT\n | typeof STYLE_EXTRACT_FAILED\n | typeof STYLE_NOT_FOUND\n | typeof INVALID_ATTRIBUTE_JSON;\n\n// #endregion\n\n// #region Docs URL\n\nconst DOCS_BASE = 'https://toolboxjs.com/grid/errors';\n\n/** Build a direct link to the troubleshooting section for a code. */\nfunction docsUrl(code: DiagnosticCode): string {\n return `${DOCS_BASE}#${code.toLowerCase()}`;\n}\n\n// #endregion\n\n// #region Formatting\n\n/**\n * Format a diagnostic message with prefix, code, and docs link.\n *\n * Output format:\n * ```\n * [tbw-grid#my-id] TBW001: Your message here.\n *\n * → More info: https://toolboxjs.com/grid/errors#tbw001\n * ```\n */\nexport function formatDiagnostic(code: DiagnosticCode, message: string, gridId?: string, pluginName?: string): string {\n const prefix = gridPrefix(gridId, pluginName);\n return `${prefix} ${code}: ${message}\\n\\n → More info: ${docsUrl(code)}`;\n}\n\n// #endregion\n\n// #region Public API\n\n/**\n * Throw an error with a diagnostic code and docs link.\n * Use for configuration errors and API misuse that should halt execution.\n */\nexport function throwDiagnostic(code: DiagnosticCode, message: string, gridId?: string, pluginName?: string): never {\n throw new Error(formatDiagnostic(code, message, gridId, pluginName));\n}\n\n/**\n * Log a warning with a diagnostic code and docs link.\n * Use for recoverable issues the developer should fix.\n */\nexport function warnDiagnostic(code: DiagnosticCode, message: string, gridId?: string, pluginName?: string): void {\n console.warn(formatDiagnostic(code, message, gridId, pluginName));\n}\n\n/**\n * Log an info message with a diagnostic code and docs link.\n * Use for optional/soft dependency notifications.\n */\nexport function infoDiagnostic(code: DiagnosticCode, message: string, gridId?: string, pluginName?: string): void {\n console.info(formatDiagnostic(code, message, gridId, pluginName));\n}\n\n/**\n * Log an error with a diagnostic code and docs link.\n * Use for non-throwing errors (e.g., failed async operations).\n */\nexport function errorDiagnostic(code: DiagnosticCode, message: string, gridId?: string, pluginName?: string): void {\n console.error(formatDiagnostic(code, message, gridId, pluginName));\n}\n\n// #endregion\n","/**\n * Core Feature Registry for @toolbox-web/grid\n *\n * This module provides a framework-agnostic registry for plugin factories.\n * Features are registered via side-effect imports, enabling tree-shaking\n * while maintaining a clean declarative API.\n *\n * @example\n * ```typescript\n * // Import features you need (side-effect imports)\n * import '@toolbox-web/grid/features/selection';\n * import '@toolbox-web/grid/features/filtering';\n *\n * // Configure grid declaratively\n * grid.gridConfig = {\n * features: {\n * selection: 'range',\n * filtering: { debounceMs: 200 },\n * },\n * };\n * ```\n *\n * @packageDocumentation\n * @module Features\n */\n\nimport {\n FEATURE_MISSING_DEP,\n FEATURE_NOT_IMPORTED,\n FEATURE_REREGISTERED,\n warnDiagnostic,\n} from '../core/internal/diagnostics';\nimport { setFeatureResolver } from '../core/internal/feature-hook';\nimport type { FeatureConfig, GridPlugin } from '../core/types';\n\n// #region Types\n\n/** Feature name — keys of the augmented FeatureConfig interface. */\nexport type FeatureName = keyof FeatureConfig;\n\n/** Factory function that creates a plugin from a feature config value. */\nexport type PluginFactory<TConfig = unknown> = (config: TConfig) => GridPlugin;\n\ninterface RegistryEntry {\n factory: PluginFactory;\n name: string;\n}\n\n// #endregion\n\n// #region Registry State\n\nconst featureRegistry = new Map<string, RegistryEntry>();\nconst warnedFeatures = new Set<string>();\n\n// #endregion\n\n// #region Registration API\n\n/** Runtime dev-mode check (localhost or 127.0.0.1). */\nconst isDev = (): boolean =>\n typeof window !== 'undefined' &&\n (window.location?.hostname === 'localhost' || window.location?.hostname === '127.0.0.1');\n\n/**\n * Register a feature's plugin factory.\n * Called by side-effect feature imports (e.g., `import '@toolbox-web/grid/features/selection'`).\n *\n * @param name - The feature name (matches a key on FeatureConfig)\n * @param factory - Function that creates a plugin instance from config\n */\nexport function registerFeature<K extends FeatureName>(name: K, factory: PluginFactory<FeatureConfig[K]>): void;\nexport function registerFeature(name: string, factory: PluginFactory): void;\nexport function registerFeature(name: string, factory: PluginFactory): void {\n if (isDev() && featureRegistry.has(name)) {\n warnDiagnostic(FEATURE_REREGISTERED, `Feature \"${name}\" was re-registered. Previous registration overwritten.`);\n }\n featureRegistry.set(name, { factory, name });\n}\n\n/**\n * Check if a feature has been registered.\n */\nexport function isFeatureRegistered(name: string): boolean {\n return featureRegistry.has(name);\n}\n\n/**\n * Get a registered feature's factory. Returns undefined if not registered.\n */\nexport function getFeatureFactory(name: string): PluginFactory | undefined {\n return featureRegistry.get(name)?.factory;\n}\n\n/**\n * Get all registered feature names.\n */\nexport function getRegisteredFeatures(): string[] {\n return Array.from(featureRegistry.keys());\n}\n\n// #endregion\n\n// #region Plugin Creation\n\n/**\n * Plugin dependency declarations.\n * Some plugins require others to be loaded first.\n */\nconst PLUGIN_DEPENDENCIES: Record<string, string[]> = {\n undoRedo: ['editing'],\n clipboard: ['selection'],\n};\n\n/**\n * Deprecated alias mappings.\n * When both alias and primary are set, primary takes precedence.\n */\nconst FEATURE_ALIASES: Record<string, string> = {\n sorting: 'multiSort',\n reorder: 'reorderColumns',\n rowReorder: 'reorderRows',\n};\n\n/**\n * Create a plugin instance for a single feature.\n * Shows a warning if the feature is not registered.\n */\nexport function createPluginFromFeature(name: string, config: unknown): GridPlugin | undefined {\n const entry = featureRegistry.get(name);\n\n if (!entry) {\n if (isDev() && !warnedFeatures.has(name)) {\n warnedFeatures.add(name);\n const kebab = name.replace(/([a-z])([A-Z])/g, '$1-$2').toLowerCase();\n warnDiagnostic(\n FEATURE_NOT_IMPORTED,\n `Feature \"${name}\" is configured but not registered.\\n` +\n `Add this import to enable it:\\n\\n` +\n ` import '@toolbox-web/grid/features/${kebab}';\\n`,\n );\n }\n return undefined;\n }\n\n return entry.factory(config);\n}\n\n/**\n * Validate feature dependencies and log warnings for missing ones.\n */\nfunction validateDependencies(featureNames: string[]): void {\n const featureSet = new Set(featureNames);\n\n for (const feature of featureNames) {\n const deps = PLUGIN_DEPENDENCIES[feature];\n if (!deps) continue;\n\n for (const dep of deps) {\n if (!featureSet.has(dep)) {\n if (isDev()) {\n warnDiagnostic(\n FEATURE_MISSING_DEP,\n `Feature \"${feature}\" requires \"${dep}\" to be enabled. ` + `Add \"${dep}\" to your features configuration.`,\n );\n }\n }\n }\n }\n}\n\n/**\n * Create plugin instances from a features configuration object.\n *\n * Handles:\n * - Deprecated alias resolution (sorting → multiSort, etc.)\n * - Dependency validation (clipboard needs selection)\n * - Dependency ordering (selection before clipboard)\n * - Skipping false/undefined values\n *\n * @param features - Partial FeatureConfig object\n * @returns Array of plugin instances ready for gridConfig.plugins\n */\nexport function createPluginsFromFeatures(features: Record<string, unknown>): GridPlugin[] {\n const plugins: GridPlugin[] = [];\n const enabledFeatures: string[] = [];\n\n // Resolve deprecated aliases: use primary name, skip alias if primary is set\n const effective: Record<string, unknown> = { ...features };\n for (const [alias, primary] of Object.entries(FEATURE_ALIASES)) {\n if (effective[alias] !== undefined && effective[primary] === undefined) {\n effective[primary] = effective[alias];\n }\n delete effective[alias];\n }\n\n // Collect enabled feature names\n for (const [key, value] of Object.entries(effective)) {\n if (value === undefined || value === false) continue;\n enabledFeatures.push(key);\n }\n\n // Validate dependencies\n validateDependencies(enabledFeatures);\n\n // Create plugins in dependency order: dep-targets first, then the rest\n const dependencyOrder: string[] = [\n 'selection',\n 'editing',\n ...enabledFeatures.filter((f) => f !== 'selection' && f !== 'editing'),\n ];\n const orderedFeatures = [...new Set(dependencyOrder)].filter((f) => enabledFeatures.includes(f));\n\n for (const featureName of orderedFeatures) {\n const config = effective[featureName];\n if (config === undefined || config === false) continue;\n\n const plugin = createPluginFromFeature(featureName, config);\n if (plugin) {\n plugins.push(plugin);\n }\n }\n\n return plugins;\n}\n\n// #endregion\n\n// #region Auto-Registration\n\n// Wire feature resolver into grid core so `gridConfig.features` is handled automatically.\n// This runs when any feature module is imported (they all import this registry).\nsetFeatureResolver(createPluginsFromFeatures as (features: Record<string, unknown>) => GridPlugin[]);\n\n// #endregion\n\n// #region Testing Utilities\n\n/**\n * Clear the registry. For testing only.\n * @internal\n */\nexport function clearFeatureRegistry(): void {\n featureRegistry.clear();\n warnedFeatures.clear();\n}\n\n// #endregion\n"],"names":["warnDiagnostic","code","message","gridId","pluginName","console","warn","toLowerCase","docsUrl","formatDiagnostic","featureRegistry","Map","warnedFeatures","Set","isDev","window","location","hostname","registerFeature","name","factory","has","set","isFeatureRegistered","getFeatureFactory","get","getRegisteredFeatures","Array","from","keys","PLUGIN_DEPENDENCIES","undoRedo","clipboard","FEATURE_ALIASES","sorting","reorder","rowReorder","createPluginFromFeature","config","entry","add","kebab","replace","createPluginsFromFeatures","features","plugins","enabledFeatures","effective","alias","primary","Object","entries","key","value","push","featureNames","featureSet","feature","deps","dep","validateDependencies","dependencyOrder","filter","f","orderedFeatures","includes","featureName","plugin","clearFeatureRegistry","clear","setFeatureResolver"],"mappings":"uDAmQO,SAASA,EAAeC,EAAsBC,EAAiBC,EAAiBC,GACrFC,QAAQC,KAtBH,SAA0BL,EAAsBC,GAErD,MAAO,cAAaD,MAASC,uBApB/B,SAAiBD,GACf,MAAO,qCAAgBA,EAAKM,eAC9B,CAkB4DC,CAAQP,IACpE,CAmBeQ,CAAiBR,EAAMC,GACtC,CCjNA,MAAMQ,qBAAsBC,IACtBC,qBAAqBC,IAOrBC,EAAQ,IACM,oBAAXC,SACwB,cAA9BA,OAAOC,UAAUC,UAA0D,cAA9BF,OAAOC,UAAUC,UAW1D,SAASC,EAAgBC,EAAcC,GACxCN,KAAWJ,EAAgBW,IAAIF,IACjCnB,EDcgC,SCdK,YAAYmB,4DAEnDT,EAAgBY,IAAIH,EAAM,CAAEC,UAASD,QACvC,CAKO,SAASI,EAAoBJ,GAClC,OAAOT,EAAgBW,IAAIF,EAC7B,CAKO,SAASK,EAAkBL,GAChC,OAAOT,EAAgBe,IAAIN,IAAOC,OACpC,CAKO,SAASM,IACd,OAAOC,MAAMC,KAAKlB,EAAgBmB,OACpC,CAUA,MAAMC,EAAgD,CACpDC,SAAU,CAAC,WACXC,UAAW,CAAC,cAORC,EAA0C,CAC9CC,QAAS,YACTC,QAAS,iBACTC,WAAY,eAOP,SAASC,EAAwBlB,EAAcmB,GACpD,MAAMC,EAAQ7B,EAAgBe,IAAIN,GAElC,GAAKoB,EAcL,OAAOA,EAAMnB,QAAQkB,GAbnB,GAAIxB,MAAYF,EAAeS,IAAIF,GAAO,CACxCP,EAAe4B,IAAIrB,GACnB,MAAMsB,EAAQtB,EAAKuB,QAAQ,kBAAmB,SAASnC,cACvDP,ED5C8B,SC8C5B,YAAYmB,+GAE8BsB,QAE9C,CAKJ,CAqCO,SAASE,EAA0BC,GACxC,MAAMC,EAAwB,GACxBC,EAA4B,GAG5BC,EAAqC,IAAKH,GAChD,IAAA,MAAYI,EAAOC,KAAYC,OAAOC,QAAQlB,QACnB,IAArBc,EAAUC,SAA+C,IAAvBD,EAAUE,KAC9CF,EAAUE,GAAWF,EAAUC,WAE1BD,EAAUC,GAInB,IAAA,MAAYI,EAAKC,KAAUH,OAAOC,QAAQJ,QAC1B,IAAVM,IAAiC,IAAVA,GAC3BP,EAAgBQ,KAAKF,IAhDzB,SAA8BG,GAC5B,MAAMC,EAAa,IAAI3C,IAAI0C,GAE3B,IAAA,MAAWE,KAAWF,EAAc,CAClC,MAAMG,EAAO5B,EAAoB2B,GACjC,GAAKC,EAEL,IAAA,MAAWC,KAAOD,EACXF,EAAWnC,IAAIsC,IACd7C,KACFd,EDpEyB,SCsEvB,YAAYyD,gBAAsBE,0BAAiCA,qCAK7E,CACF,CAkCEC,CAAqBd,GAGrB,MAAMe,EAA4B,CAChC,YACA,aACGf,EAAgBgB,OAAQC,GAAY,cAANA,GAA2B,YAANA,IAElDC,EAAkB,IAAI,IAAInD,IAAIgD,IAAkBC,OAAQC,GAAMjB,EAAgBmB,SAASF,IAE7F,IAAA,MAAWG,KAAeF,EAAiB,CACzC,MAAM1B,EAASS,EAAUmB,GACzB,QAAe,IAAX5B,IAAmC,IAAXA,EAAkB,SAE9C,MAAM6B,EAAS9B,EAAwB6B,EAAa5B,GAChD6B,GACFtB,EAAQS,KAAKa,EAEjB,CAEA,OAAOtB,CACT,CAkBO,SAASuB,IACd1D,EAAgB2D,QAChBzD,EAAeyD,OACjB,CAbAC,EAAmB3B"}
|
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
const
|
|
1
|
+
function e(e,t){return`[tbw-grid${e?`#${e}`:""}${t?`:${t}`:""}]`}function t(t,n,r,i){return`${e(r,i)} ${t}: ${n}\n\n → More info: ${function(e){return`https://toolboxjs.com/grid/errors#${e.toLowerCase()}`}(t)}`}const n='<svg viewBox="0 0 16 16" width="12" height="12"><path fill="currentColor" d="M6 10.5a.5.5 0 0 1 .5-.5h3a.5.5 0 0 1 0 1h-3a.5.5 0 0 1-.5-.5zm-2-3a.5.5 0 0 1 .5-.5h7a.5.5 0 0 1 0 1h-7a.5.5 0 0 1-.5-.5zm-2-3a.5.5 0 0 1 .5-.5h11a.5.5 0 0 1 0 1h-11a.5.5 0 0 1-.5-.5z"/></svg>',r={expand:"▶",collapse:"▼",sortAsc:"▲",sortDesc:"▼",sortNone:"⇅",submenuArrow:"▶",dragHandle:"⋮⋮",toolPanel:"☰",filter:n,filterActive:n,print:"🖨️"};class i{static dependencies;static manifest;aliases;version="undefined"!=typeof __GRID_VERSION__?__GRID_VERSION__:"dev";styles;cellRenderers;headerRenderers;cellEditors;grid;config;userConfig;#e;get defaultConfig(){return{}}constructor(e={}){this.userConfig=e}attach(e){this.#e?.abort(),this.#e=new AbortController,this.grid=e,this.config={...this.defaultConfig,...this.userConfig}}detach(){this.#e?.abort(),this.#e=void 0}getPlugin(e){return this.grid?.getPlugin(e)}emit(e,t){this.grid?.dispatchEvent?.(new CustomEvent(e,{detail:t,bubbles:!0}))}emitCancelable(e,t){const n=new CustomEvent(e,{detail:t,bubbles:!0,cancelable:!0});return this.grid?.dispatchEvent?.(n),n.defaultPrevented}on(e,t){this.grid?._pluginManager?.subscribe(this,e,t)}off(e){this.grid?._pluginManager?.unsubscribe(this,e)}emitPluginEvent(e,t){this.grid?._pluginManager?.emitPluginEvent(e,t)}requestRender(){this.grid?.requestRender?.()}requestColumnsRender(){this.grid?.requestColumnsRender?.()}requestRenderWithFocus(){this.grid?.requestRenderWithFocus?.()}requestAfterRender(){this.grid?.requestAfterRender?.()}requestVirtualRefresh(){this.grid?.requestVirtualRefresh?.()}get rows(){return this.grid?.rows??[]}get sourceRows(){return this.grid?.sourceRows??[]}get columns(){return this.grid?.columns??[]}get visibleColumns(){return this.grid?._visibleColumns??[]}get gridElement(){return this.grid?._hostElement}get disconnectSignal(){return this.#e?.signal??this.grid?.disconnectSignal}get gridIcons(){const e=this.grid?.gridConfig?.icons??{};return{...r,...e}}get isAnimationEnabled(){const e=this.grid?.effectiveConfig?.animation?.mode??"reduced-motion";if(!1===e||"off"===e)return!1;if(!0===e||"on"===e)return!0;const t=this.gridElement;if(t){return"0"!==getComputedStyle(t).getPropertyValue("--tbw-animation-enabled").trim()}return!0}get animationDuration(){const e=this.gridElement;if(e){const t=getComputedStyle(e).getPropertyValue("--tbw-animation-duration").trim(),n=parseInt(t,10);if(!isNaN(n))return n}return 200}resolveIcon(e,t){return void 0!==t?t:this.gridIcons[e]}setIcon(e,t){"string"==typeof t?e.innerHTML=t:t instanceof HTMLElement&&(e.innerHTML="",e.appendChild(t.cloneNode(!0)))}warn(n,r){void 0!==r?console.warn(t(n,r,this.gridElement.id,this.name)):console.warn(`${e(this.gridElement.id,this.name)} ${n}`)}throwDiagnostic(e,n){throw new Error(t(e,n,this.gridElement.id,this.name))}}function o(e,t,n=!0){let r=e;if(n&&(r=r.filter(e=>!e.hidden&&!e.field.startsWith("__")&&!0!==e.meta?.utility)),t?.length){const e=new Set(t);r=r.filter(t=>e.has(t.field))}return r}function s(e){return null==e?"":e instanceof Date?e.toISOString():"object"==typeof e?JSON.stringify(e):String(e)}async function l(e){try{return await navigator.clipboard.writeText(e),!0}catch(s){n="TBW100",r=`Clipboard API failed: ${s}`,console.warn(t(n,r,i,o));const l=document.createElement("textarea");l.value=e,l.style.position="fixed",l.style.opacity="0",l.style.pointerEvents="none",document.body.appendChild(l),l.select();const a=document.execCommand("copy");return document.body.removeChild(l),a}var n,r,i,o}function a(e,t){const n=t.delimiter??"\t",r=t.newline??"\n",i=e.replace(/\r\n/g,"\n").replace(/\r/g,"\n"),o=[];let s=[],l="",a=!1;for(let c=0;c<i.length;c++){const e=i[c];'"'!==e||a?'"'===e&&a?'"'===i[c+1]?(l+='"',c++):a=!1:e!==n||a?e!==r||a?l+=e:(s.push(l),l="",(s.length>1||s.some(e=>""!==e.trim()))&&o.push(s),s=[]):(s.push(l),l=""):a=!0}return s.push(l),(s.length>1||s.some(e=>""!==e.trim()))&&o.push(s),o}function c(e,t){const{rows:n,target:r,fields:i}=e;if(!r)return;const o=t.rows,s=t.effectiveConfig.columns??[],l=s.map(e=>e.field),a=/* @__PURE__ */new Map;s.forEach(e=>{a.set(e.field,!0===e.editable)});const c=[...o],d=r.bounds?r.bounds.endRow:1/0;n.forEach((e,t)=>{const n=r.row+t;if(!(n>d)){if(r.bounds){if(n>=c.length)return}else for(;n>=c.length;){const e={};l.forEach(t=>e[t]=""),c.push(e)}c[n]={...c[n]},e.forEach((e,t)=>{const r=i[t];r&&a.get(r)&&(c[n][r]=e)})}}),t.rows=c}class d extends i{static dependencies=[{name:"selection",required:!1,reason:"Enables copy/paste of selected cells instead of entire grid"}];name="clipboard";get defaultConfig(){return{includeHeaders:!1,delimiter:"\t",newline:"\n",quoteStrings:!1}}lastCopied=null;attach(e){super.attach(e),e.addEventListener("paste",e=>this.#t(e),{signal:this.disconnectSignal})}detach(){this.lastCopied=null}onKeyDown(e){return!(!e.ctrlKey&&!e.metaKey||"c"!==e.key)&&(e.preventDefault(),this.#n(e.target),!0)}#n(e){const t=this.#r();if(t&&0===t.ranges.length){const t=this.#i(e);if(!t)return;const n=this.columns[t.col];if(!n)return;return void this.copy({rowIndices:[t.row],columns:[n.field]})}this.copy()}#t(e){const t=e.clipboardData?.getData("text/plain");if(!t)return;e.preventDefault();const n=a(t,this.config),r=this.#r(),i=r?.ranges?.[0],o=i?.from.row??0,s=i?.from.col??0,l=i&&("range"===r?.mode||"row"===r?.mode)&&(i.from.row!==i.to.row||i.from.col!==i.to.col)?{endRow:i.to.row,endCol:i.to.col}:null,c=l?.endCol??this.visibleColumns.length-1,d=this.visibleColumns[s],u=d?{row:o,col:s,field:d.field,bounds:l}:null,h=[],g=n[0]?.length??0;for(let a=0;a<g&&s+a<=c;a++){const e=this.visibleColumns[s+a];e&&h.push(e.field)}const f={rows:n,text:t,target:u,fields:h};this.emit("paste",f),this.#o(f)}#o(e){if(!this.grid)return;const{pasteHandler:t}=this.config;if(null===t)return;(t??c)(e,this.grid)}#r(){const e=this.grid?.query("getSelection");return e?.[0]}#s(e){const t=this.#r();let n,r;if(e?.columns)n=o(this.columns,e.columns);else if(t?.ranges.length&&"row"!==t.mode){const e=t.ranges[t.ranges.length-1],r=Math.min(e.from.col,e.to.col),i=Math.max(e.from.col,e.to.col);n=o(this.visibleColumns.slice(r,i+1))}else n=o(this.columns);if(e?.rowIndices)r=function(e,t){return t?.length?[...t].sort((e,t)=>e-t).map(t=>e[t]).filter(e=>null!=e):e}(this.rows,e.rowIndices);else if(t?.ranges.length){const e=t.ranges[t.ranges.length-1],n=Math.min(e.from.row,e.to.row),i=Math.max(e.from.row,e.to.row);r=[];for(let t=n;t<=i;t++){const e=this.rows[t];e&&r.push(e)}}else r=this.rows;return{columns:n,rows:r}}#l(e,t,n){const r=n?.delimiter??this.config.delimiter??"\t",i=n?.newline??this.config.newline??"\n",o=n?.includeHeaders??this.config.includeHeaders??!1,l=n?.processCell??this.config.processCell,a=[];o&&a.push(e.map(e=>e.header||e.field).join(r));for(const c of t){const t=e.map(e=>{const t=c[e.field];return l?l(t,e.field,c):s(t)});a.push(t.join(r))}return a.join(i)}#i(e){const t=e.closest("[data-field-cache]");if(!t)return null;const n=t.dataset.fieldCache,r=t.dataset.row;if(!n||!r)return null;const i=parseInt(r,10);if(isNaN(i))return null;const o=this.columns.findIndex(e=>e.field===n);return-1===o?null:{row:i,col:o}}getSelectionAsText(e){const{columns:t,rows:n}=this.#s(e);return 0===t.length||0===n.length?"":this.#l(t,n,e)}async copy(e){const{columns:t,rows:n}=this.#s(e);if(0===t.length||0===n.length)return"";const r=this.#l(t,n,e);return await l(r),this.lastCopied={text:r,timestamp:Date.now()},this.emit("copy",{text:r,rowCount:n.length,columnCount:t.length}),r}async copyRows(e,t){return 0===e.length?"":this.copy({...t,rowIndices:e})}async paste(){const e=await async function(){try{return await navigator.clipboard.readText()}catch{return""}}();return e?a(e,this.config):null}getLastCopied(){return this.lastCopied}}export{d as ClipboardPlugin,c as defaultPasteHandler};
|
|
2
2
|
//# sourceMappingURL=index.js.map
|