@toolbox-web/grid-angular 0.18.2 → 0.18.4
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/fesm2022/toolbox-web-grid-angular-features-export.mjs +1 -1
- package/fesm2022/toolbox-web-grid-angular-features-export.mjs.map +1 -1
- package/fesm2022/toolbox-web-grid-angular-features-filtering.mjs +13 -1
- package/fesm2022/toolbox-web-grid-angular-features-filtering.mjs.map +1 -1
- package/fesm2022/toolbox-web-grid-angular-features-print.mjs +1 -1
- package/fesm2022/toolbox-web-grid-angular-features-print.mjs.map +1 -1
- package/fesm2022/toolbox-web-grid-angular-features-selection.mjs +4 -4
- package/fesm2022/toolbox-web-grid-angular-features-selection.mjs.map +1 -1
- package/fesm2022/toolbox-web-grid-angular-features-undo-redo.mjs +3 -3
- package/fesm2022/toolbox-web-grid-angular-features-undo-redo.mjs.map +1 -1
- package/fesm2022/toolbox-web-grid-angular.mjs +167 -176
- package/fesm2022/toolbox-web-grid-angular.mjs.map +1 -1
- package/package.json +1 -1
- package/types/toolbox-web-grid-angular-features-clipboard.d.ts.map +1 -1
- package/types/toolbox-web-grid-angular-features-column-virtualization.d.ts.map +1 -1
- package/types/toolbox-web-grid-angular-features-context-menu.d.ts.map +1 -1
- package/types/toolbox-web-grid-angular-features-editing.d.ts.map +1 -1
- package/types/toolbox-web-grid-angular-features-export.d.ts.map +1 -1
- package/types/toolbox-web-grid-angular-features-filtering.d.ts +13 -1
- package/types/toolbox-web-grid-angular-features-filtering.d.ts.map +1 -1
- package/types/toolbox-web-grid-angular-features-grouping-columns.d.ts.map +1 -1
- package/types/toolbox-web-grid-angular-features-grouping-rows.d.ts.map +1 -1
- package/types/toolbox-web-grid-angular-features-master-detail.d.ts.map +1 -1
- package/types/toolbox-web-grid-angular-features-multi-sort.d.ts.map +1 -1
- package/types/toolbox-web-grid-angular-features-pinned-columns.d.ts.map +1 -1
- package/types/toolbox-web-grid-angular-features-pinned-rows.d.ts.map +1 -1
- package/types/toolbox-web-grid-angular-features-pivot.d.ts.map +1 -1
- package/types/toolbox-web-grid-angular-features-print.d.ts.map +1 -1
- package/types/toolbox-web-grid-angular-features-reorder-columns.d.ts.map +1 -1
- package/types/toolbox-web-grid-angular-features-reorder-rows.d.ts.map +1 -1
- package/types/toolbox-web-grid-angular-features-reorder.d.ts.map +1 -1
- package/types/toolbox-web-grid-angular-features-responsive.d.ts.map +1 -1
- package/types/toolbox-web-grid-angular-features-row-reorder.d.ts.map +1 -1
- package/types/toolbox-web-grid-angular-features-selection.d.ts.map +1 -1
- package/types/toolbox-web-grid-angular-features-server-side.d.ts.map +1 -1
- package/types/toolbox-web-grid-angular-features-sorting.d.ts.map +1 -1
- package/types/toolbox-web-grid-angular-features-tree.d.ts.map +1 -1
- package/types/toolbox-web-grid-angular-features-undo-redo.d.ts.map +1 -1
- package/types/toolbox-web-grid-angular-features-visibility.d.ts.map +1 -1
- package/types/toolbox-web-grid-angular.d.ts.map +1 -1
|
@@ -67,7 +67,7 @@ import '@toolbox-web/grid/features/export';
|
|
|
67
67
|
function injectGridExport() {
|
|
68
68
|
const elementRef = inject(ElementRef);
|
|
69
69
|
const destroyRef = inject(DestroyRef);
|
|
70
|
-
const isReady = signal(false, ...(ngDevMode ? [{ debugName: "isReady" }] : []));
|
|
70
|
+
const isReady = signal(false, ...(ngDevMode ? [{ debugName: "isReady" }] : /* istanbul ignore next */ []));
|
|
71
71
|
// Lazy discovery: cached grid reference
|
|
72
72
|
let cachedGrid = null;
|
|
73
73
|
let readyPromiseStarted = false;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"toolbox-web-grid-angular-features-export.mjs","sources":["../../../../libs/grid-angular/features/export/src/index.ts","../../../../libs/grid-angular/features/export/src/toolbox-web-grid-angular-features-export.ts"],"sourcesContent":["/**\n * Export feature for @toolbox-web/grid-angular\n *\n * Import this module to enable the `export` input on Grid directive.\n * Also exports `injectGridExport()` for programmatic export control.\n *\n * @example\n * ```typescript\n * import '@toolbox-web/grid-angular/features/export';\n *\n * <tbw-grid [export]=\"true\" />\n * <tbw-grid [export]=\"{ fileName: 'data.csv' }\" />\n * ```\n *\n * @example Using injectGridExport\n * ```typescript\n * import { injectGridExport } from '@toolbox-web/grid-angular/features/export';\n *\n * @Component({...})\n * export class MyComponent {\n * private gridExport = injectGridExport();\n *\n * exportData() {\n * this.gridExport.exportToCsv('employees.csv');\n * }\n * }\n * ```\n *\n * @packageDocumentation\n */\n\nimport { afterNextRender, DestroyRef, ElementRef, inject, signal, type Signal } from '@angular/core';\nimport type { DataGridElement } from '@toolbox-web/grid';\nimport '@toolbox-web/grid/features/export';\nimport { ExportPlugin, type ExportFormat, type ExportParams } from '@toolbox-web/grid/plugins/export';\n\n/**\n * Export methods returned from injectGridExport.\n *\n * Uses lazy discovery - the grid is found on first method call, not during initialization.\n * This ensures it works with lazy-rendered tabs, conditional rendering, etc.\n */\nexport interface ExportMethods {\n /**\n * Export grid data to CSV file.\n * @param filename - Optional filename (defaults to 'export.csv')\n * @param params - Optional export parameters\n */\n exportToCsv: (filename?: string, params?: Partial<ExportParams>) => void;\n\n /**\n * Export grid data to Excel file (XML Spreadsheet format).\n * @param filename - Optional filename (defaults to 'export.xlsx')\n * @param params - Optional export parameters\n */\n exportToExcel: (filename?: string, params?: Partial<ExportParams>) => void;\n\n /**\n * Export grid data to JSON file.\n * @param filename - Optional filename (defaults to 'export.json')\n * @param params - Optional export parameters\n */\n exportToJson: (filename?: string, params?: Partial<ExportParams>) => void;\n\n /**\n * Check if an export is currently in progress.\n */\n isExporting: () => boolean;\n\n /**\n * Get information about the last export.\n */\n getLastExport: () => { format: ExportFormat; timestamp: Date } | null;\n\n /**\n * Signal indicating if grid is ready.\n * The grid is discovered lazily, so this updates when first method call succeeds.\n */\n isReady: Signal<boolean>;\n}\n\n/**\n * Angular inject function for programmatic export control.\n *\n * Uses **lazy grid discovery** - the grid element is found when methods are called,\n * not during initialization. This ensures it works reliably with:\n * - Lazy-rendered tabs\n * - Conditional rendering (*ngIf)\n * - Dynamic component loading\n *\n * @example\n * ```typescript\n * import { Component } from '@angular/core';\n * import { Grid } from '@toolbox-web/grid-angular';\n * import '@toolbox-web/grid-angular/features/export';\n * import { injectGridExport } from '@toolbox-web/grid-angular/features/export';\n *\n * @Component({\n * selector: 'app-my-grid',\n * imports: [Grid],\n * template: `\n * <button (click)=\"handleExport()\">Export CSV</button>\n * <tbw-grid [rows]=\"rows\" [export]=\"true\"></tbw-grid>\n * `\n * })\n * export class MyGridComponent {\n * gridExport = injectGridExport();\n *\n * handleExport() {\n * this.gridExport.exportToCsv('employees.csv');\n * }\n * }\n * ```\n */\nexport function injectGridExport(): ExportMethods {\n const elementRef = inject(ElementRef);\n const destroyRef = inject(DestroyRef);\n const isReady = signal(false);\n\n // Lazy discovery: cached grid reference\n let cachedGrid: DataGridElement | null = null;\n let readyPromiseStarted = false;\n\n /**\n * Lazily find the grid element. Called on each method invocation.\n * Caches the reference once found and triggers ready() check.\n */\n const getGrid = (): DataGridElement | null => {\n if (cachedGrid) return cachedGrid;\n\n const grid = elementRef.nativeElement.querySelector('tbw-grid') as DataGridElement | null;\n if (grid) {\n cachedGrid = grid;\n // Start ready() check only once\n if (!readyPromiseStarted) {\n readyPromiseStarted = true;\n grid.ready?.().then(() => isReady.set(true));\n }\n }\n return grid;\n };\n\n const getPlugin = (): ExportPlugin | undefined => {\n return getGrid()?.getPluginByName('export') as ExportPlugin | undefined;\n };\n\n // Eagerly discover the grid after the first render so isReady updates\n // without requiring a programmatic method call. Falls back to a\n // MutationObserver for lazy-rendered tabs, *ngIf, @defer, etc.\n afterNextRender(() => {\n if (getGrid()) return;\n\n const host = elementRef.nativeElement as HTMLElement;\n const observer = new MutationObserver(() => {\n if (getGrid()) observer.disconnect();\n });\n observer.observe(host, { childList: true, subtree: true });\n\n destroyRef.onDestroy(() => observer.disconnect());\n });\n\n return {\n isReady: isReady.asReadonly(),\n\n exportToCsv: (filename?: string, params?: Partial<ExportParams>) => {\n const plugin = getPlugin();\n if (!plugin) {\n console.warn(\n `[tbw-grid:export] ExportPlugin not found.\\n\\n` +\n ` → Enable export on the grid:\\n` +\n ` <tbw-grid [export]=\"true\" />`,\n );\n return;\n }\n plugin.exportCsv({ ...params, fileName: filename ?? params?.fileName ?? 'export.csv' });\n },\n\n exportToExcel: (filename?: string, params?: Partial<ExportParams>) => {\n const plugin = getPlugin();\n if (!plugin) {\n console.warn(\n `[tbw-grid:export] ExportPlugin not found.\\n\\n` +\n ` → Enable export on the grid:\\n` +\n ` <tbw-grid [export]=\"true\" />`,\n );\n return;\n }\n plugin.exportExcel({ ...params, fileName: filename ?? params?.fileName ?? 'export.xlsx' });\n },\n\n exportToJson: (filename?: string, params?: Partial<ExportParams>) => {\n const plugin = getPlugin();\n if (!plugin) {\n console.warn(\n `[tbw-grid:export] ExportPlugin not found.\\n\\n` +\n ` → Enable export on the grid:\\n` +\n ` <tbw-grid [export]=\"true\" />`,\n );\n return;\n }\n plugin.exportJson({ ...params, fileName: filename ?? params?.fileName ?? 'export.json' });\n },\n\n isExporting: () => {\n return getPlugin()?.isExporting() ?? false;\n },\n\n getLastExport: () => {\n return getPlugin()?.getLastExport() ?? null;\n },\n };\n}\n","/**\n * Generated bundle index. Do not edit.\n */\n\nexport * from './index';\n"],"names":[],"mappings":";;;AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AA6BG;AAoDH;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AAgCG;SACa,gBAAgB,GAAA;AAC9B,IAAA,MAAM,UAAU,GAAG,MAAM,CAAC,UAAU,CAAC;AACrC,IAAA,MAAM,UAAU,GAAG,MAAM,CAAC,UAAU,CAAC;AACrC,IAAA,MAAM,OAAO,GAAG,MAAM,CAAC,KAAK,
|
|
1
|
+
{"version":3,"file":"toolbox-web-grid-angular-features-export.mjs","sources":["../../../../libs/grid-angular/features/export/src/index.ts","../../../../libs/grid-angular/features/export/src/toolbox-web-grid-angular-features-export.ts"],"sourcesContent":["/**\n * Export feature for @toolbox-web/grid-angular\n *\n * Import this module to enable the `export` input on Grid directive.\n * Also exports `injectGridExport()` for programmatic export control.\n *\n * @example\n * ```typescript\n * import '@toolbox-web/grid-angular/features/export';\n *\n * <tbw-grid [export]=\"true\" />\n * <tbw-grid [export]=\"{ fileName: 'data.csv' }\" />\n * ```\n *\n * @example Using injectGridExport\n * ```typescript\n * import { injectGridExport } from '@toolbox-web/grid-angular/features/export';\n *\n * @Component({...})\n * export class MyComponent {\n * private gridExport = injectGridExport();\n *\n * exportData() {\n * this.gridExport.exportToCsv('employees.csv');\n * }\n * }\n * ```\n *\n * @packageDocumentation\n */\n\nimport { afterNextRender, DestroyRef, ElementRef, inject, signal, type Signal } from '@angular/core';\nimport type { DataGridElement } from '@toolbox-web/grid';\nimport '@toolbox-web/grid/features/export';\nimport { ExportPlugin, type ExportFormat, type ExportParams } from '@toolbox-web/grid/plugins/export';\n\n/**\n * Export methods returned from injectGridExport.\n *\n * Uses lazy discovery - the grid is found on first method call, not during initialization.\n * This ensures it works with lazy-rendered tabs, conditional rendering, etc.\n */\nexport interface ExportMethods {\n /**\n * Export grid data to CSV file.\n * @param filename - Optional filename (defaults to 'export.csv')\n * @param params - Optional export parameters\n */\n exportToCsv: (filename?: string, params?: Partial<ExportParams>) => void;\n\n /**\n * Export grid data to Excel file (XML Spreadsheet format).\n * @param filename - Optional filename (defaults to 'export.xlsx')\n * @param params - Optional export parameters\n */\n exportToExcel: (filename?: string, params?: Partial<ExportParams>) => void;\n\n /**\n * Export grid data to JSON file.\n * @param filename - Optional filename (defaults to 'export.json')\n * @param params - Optional export parameters\n */\n exportToJson: (filename?: string, params?: Partial<ExportParams>) => void;\n\n /**\n * Check if an export is currently in progress.\n */\n isExporting: () => boolean;\n\n /**\n * Get information about the last export.\n */\n getLastExport: () => { format: ExportFormat; timestamp: Date } | null;\n\n /**\n * Signal indicating if grid is ready.\n * The grid is discovered lazily, so this updates when first method call succeeds.\n */\n isReady: Signal<boolean>;\n}\n\n/**\n * Angular inject function for programmatic export control.\n *\n * Uses **lazy grid discovery** - the grid element is found when methods are called,\n * not during initialization. This ensures it works reliably with:\n * - Lazy-rendered tabs\n * - Conditional rendering (*ngIf)\n * - Dynamic component loading\n *\n * @example\n * ```typescript\n * import { Component } from '@angular/core';\n * import { Grid } from '@toolbox-web/grid-angular';\n * import '@toolbox-web/grid-angular/features/export';\n * import { injectGridExport } from '@toolbox-web/grid-angular/features/export';\n *\n * @Component({\n * selector: 'app-my-grid',\n * imports: [Grid],\n * template: `\n * <button (click)=\"handleExport()\">Export CSV</button>\n * <tbw-grid [rows]=\"rows\" [export]=\"true\"></tbw-grid>\n * `\n * })\n * export class MyGridComponent {\n * gridExport = injectGridExport();\n *\n * handleExport() {\n * this.gridExport.exportToCsv('employees.csv');\n * }\n * }\n * ```\n */\nexport function injectGridExport(): ExportMethods {\n const elementRef = inject(ElementRef);\n const destroyRef = inject(DestroyRef);\n const isReady = signal(false);\n\n // Lazy discovery: cached grid reference\n let cachedGrid: DataGridElement | null = null;\n let readyPromiseStarted = false;\n\n /**\n * Lazily find the grid element. Called on each method invocation.\n * Caches the reference once found and triggers ready() check.\n */\n const getGrid = (): DataGridElement | null => {\n if (cachedGrid) return cachedGrid;\n\n const grid = elementRef.nativeElement.querySelector('tbw-grid') as DataGridElement | null;\n if (grid) {\n cachedGrid = grid;\n // Start ready() check only once\n if (!readyPromiseStarted) {\n readyPromiseStarted = true;\n grid.ready?.().then(() => isReady.set(true));\n }\n }\n return grid;\n };\n\n const getPlugin = (): ExportPlugin | undefined => {\n return getGrid()?.getPluginByName('export') as ExportPlugin | undefined;\n };\n\n // Eagerly discover the grid after the first render so isReady updates\n // without requiring a programmatic method call. Falls back to a\n // MutationObserver for lazy-rendered tabs, *ngIf, @defer, etc.\n afterNextRender(() => {\n if (getGrid()) return;\n\n const host = elementRef.nativeElement as HTMLElement;\n const observer = new MutationObserver(() => {\n if (getGrid()) observer.disconnect();\n });\n observer.observe(host, { childList: true, subtree: true });\n\n destroyRef.onDestroy(() => observer.disconnect());\n });\n\n return {\n isReady: isReady.asReadonly(),\n\n exportToCsv: (filename?: string, params?: Partial<ExportParams>) => {\n const plugin = getPlugin();\n if (!plugin) {\n console.warn(\n `[tbw-grid:export] ExportPlugin not found.\\n\\n` +\n ` → Enable export on the grid:\\n` +\n ` <tbw-grid [export]=\"true\" />`,\n );\n return;\n }\n plugin.exportCsv({ ...params, fileName: filename ?? params?.fileName ?? 'export.csv' });\n },\n\n exportToExcel: (filename?: string, params?: Partial<ExportParams>) => {\n const plugin = getPlugin();\n if (!plugin) {\n console.warn(\n `[tbw-grid:export] ExportPlugin not found.\\n\\n` +\n ` → Enable export on the grid:\\n` +\n ` <tbw-grid [export]=\"true\" />`,\n );\n return;\n }\n plugin.exportExcel({ ...params, fileName: filename ?? params?.fileName ?? 'export.xlsx' });\n },\n\n exportToJson: (filename?: string, params?: Partial<ExportParams>) => {\n const plugin = getPlugin();\n if (!plugin) {\n console.warn(\n `[tbw-grid:export] ExportPlugin not found.\\n\\n` +\n ` → Enable export on the grid:\\n` +\n ` <tbw-grid [export]=\"true\" />`,\n );\n return;\n }\n plugin.exportJson({ ...params, fileName: filename ?? params?.fileName ?? 'export.json' });\n },\n\n isExporting: () => {\n return getPlugin()?.isExporting() ?? false;\n },\n\n getLastExport: () => {\n return getPlugin()?.getLastExport() ?? null;\n },\n };\n}\n","/**\n * Generated bundle index. Do not edit.\n */\n\nexport * from './index';\n"],"names":[],"mappings":"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"}
|
|
@@ -67,7 +67,7 @@ import '@toolbox-web/grid/features/filtering';
|
|
|
67
67
|
function injectGridFiltering() {
|
|
68
68
|
const elementRef = inject(ElementRef);
|
|
69
69
|
const destroyRef = inject(DestroyRef);
|
|
70
|
-
const isReady = signal(false, ...(ngDevMode ? [{ debugName: "isReady" }] : []));
|
|
70
|
+
const isReady = signal(false, ...(ngDevMode ? [{ debugName: "isReady" }] : /* istanbul ignore next */ []));
|
|
71
71
|
let cachedGrid = null;
|
|
72
72
|
let readyPromiseStarted = false;
|
|
73
73
|
const getGrid = () => {
|
|
@@ -147,6 +147,18 @@ function injectGridFiltering() {
|
|
|
147
147
|
isFieldFiltered: (field) => getPlugin()?.isFieldFiltered(field) ?? false,
|
|
148
148
|
getFilteredRowCount: () => getPlugin()?.getFilteredRowCount() ?? 0,
|
|
149
149
|
getUniqueValues: (field) => getPlugin()?.getUniqueValues(field) ?? [],
|
|
150
|
+
getStaleFilters: () => getPlugin()?.getStaleFilters() ?? [],
|
|
151
|
+
getBlankMode: (field) => getPlugin()?.getBlankMode(field) ?? 'all',
|
|
152
|
+
toggleBlankFilter: (field, mode) => {
|
|
153
|
+
const plugin = getPlugin();
|
|
154
|
+
if (!plugin) {
|
|
155
|
+
console.warn(`[tbw-grid:filtering] FilteringPlugin not found.\n\n` +
|
|
156
|
+
` → Enable filtering on the grid:\n` +
|
|
157
|
+
` <tbw-grid [filtering]="true" />`);
|
|
158
|
+
return;
|
|
159
|
+
}
|
|
160
|
+
plugin.toggleBlankFilter(field, mode);
|
|
161
|
+
},
|
|
150
162
|
};
|
|
151
163
|
}
|
|
152
164
|
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"toolbox-web-grid-angular-features-filtering.mjs","sources":["../../../../libs/grid-angular/features/filtering/src/index.ts","../../../../libs/grid-angular/features/filtering/src/toolbox-web-grid-angular-features-filtering.ts"],"sourcesContent":["/**\n * Filtering feature for @toolbox-web/grid-angular\n *\n * Import this module to enable the `filtering` input on Grid directive.\n * Also exports `injectGridFiltering()` for programmatic filter control.\n *\n * @example\n * ```typescript\n * import '@toolbox-web/grid-angular/features/filtering';\n *\n * <tbw-grid [filtering]=\"true\" />\n * <tbw-grid [filtering]=\"{ debounceMs: 200 }\" />\n * ```\n *\n * @example Using injectGridFiltering\n * ```typescript\n * import { injectGridFiltering } from '@toolbox-web/grid-angular/features/filtering';\n *\n * @Component({...})\n * export class MyComponent {\n * private filtering = injectGridFiltering();\n *\n * filterByStatus(status: string) {\n * this.filtering.setFilter('status', { operator: 'equals', value: status });\n * }\n * }\n * ```\n *\n * @packageDocumentation\n */\n\nimport { afterNextRender, DestroyRef, ElementRef, inject, signal, type Signal } from '@angular/core';\nimport type { DataGridElement } from '@toolbox-web/grid';\nimport '@toolbox-web/grid/features/filtering';\nimport { FilteringPlugin, type FilterModel } from '@toolbox-web/grid/plugins/filtering';\n\n/**\n * Filtering methods returned from injectGridFiltering.\n *\n * Uses lazy discovery - the grid is found on first method call, not during initialization.\n */\nexport interface FilteringMethods {\n /**\n * Set a filter on a specific field.\n * @param field - The field name to filter\n * @param filter - Filter configuration, or null to remove\n */\n setFilter: (field: string, filter: Omit<FilterModel, 'field'> | null) => void;\n\n /**\n * Get the current filter for a field.\n */\n getFilter: (field: string) => FilterModel | undefined;\n\n /**\n * Get all active filters.\n */\n getFilters: () => FilterModel[];\n\n /**\n * Set all filters at once (replaces existing).\n */\n setFilterModel: (filters: FilterModel[]) => void;\n\n /**\n * Clear all active filters.\n */\n clearAllFilters: () => void;\n\n /**\n * Clear filter for a specific field.\n */\n clearFieldFilter: (field: string) => void;\n\n /**\n * Check if a field has an active filter.\n */\n isFieldFiltered: (field: string) => boolean;\n\n /**\n * Get the count of rows after filtering.\n */\n getFilteredRowCount: () => number;\n\n /**\n * Get unique values for a field (for building filter dropdowns).\n */\n getUniqueValues: (field: string) => unknown[];\n\n /**\n * Signal indicating if grid is ready.\n */\n isReady: Signal<boolean>;\n}\n\n/**\n * Angular inject function for programmatic filter control.\n *\n * Uses **lazy grid discovery** - the grid element is found when methods are called,\n * not during initialization.\n *\n * @example\n * ```typescript\n * import { Component } from '@angular/core';\n * import { Grid } from '@toolbox-web/grid-angular';\n * import '@toolbox-web/grid-angular/features/filtering';\n * import { injectGridFiltering } from '@toolbox-web/grid-angular/features/filtering';\n *\n * @Component({\n * selector: 'app-my-grid',\n * imports: [Grid],\n * template: `\n * <input (input)=\"applyFilter($event)\" placeholder=\"Filter by name...\" />\n * <span>{{ filtering.getFilteredRowCount() }} results</span>\n * <button (click)=\"filtering.clearAllFilters()\">Clear</button>\n * <tbw-grid [rows]=\"rows\" [filtering]=\"true\"></tbw-grid>\n * `\n * })\n * export class MyGridComponent {\n * filtering = injectGridFiltering();\n *\n * applyFilter(event: Event) {\n * const value = (event.target as HTMLInputElement).value;\n * this.filtering.setFilter('name', value ? { operator: 'contains', value } : null);\n * }\n * }\n * ```\n */\nexport function injectGridFiltering(): FilteringMethods {\n const elementRef = inject(ElementRef);\n const destroyRef = inject(DestroyRef);\n const isReady = signal(false);\n\n let cachedGrid: DataGridElement | null = null;\n let readyPromiseStarted = false;\n\n const getGrid = (): DataGridElement | null => {\n if (cachedGrid) return cachedGrid;\n\n const grid = elementRef.nativeElement.querySelector('tbw-grid') as DataGridElement | null;\n if (grid) {\n cachedGrid = grid;\n if (!readyPromiseStarted) {\n readyPromiseStarted = true;\n grid.ready?.().then(() => isReady.set(true));\n }\n }\n return grid;\n };\n\n const getPlugin = (): FilteringPlugin | undefined => {\n return getGrid()?.getPluginByName('filtering') as FilteringPlugin | undefined;\n };\n\n // Eagerly discover the grid after the first render so isReady updates\n // without requiring a programmatic method call. Falls back to a\n // MutationObserver for lazy-rendered tabs, *ngIf, @defer, etc.\n afterNextRender(() => {\n if (getGrid()) return;\n\n const host = elementRef.nativeElement as HTMLElement;\n const observer = new MutationObserver(() => {\n if (getGrid()) observer.disconnect();\n });\n observer.observe(host, { childList: true, subtree: true });\n\n destroyRef.onDestroy(() => observer.disconnect());\n });\n\n return {\n isReady: isReady.asReadonly(),\n\n setFilter: (field: string, filter: Omit<FilterModel, 'field'> | null) => {\n const plugin = getPlugin();\n if (!plugin) {\n console.warn(\n `[tbw-grid:filtering] FilteringPlugin not found.\\n\\n` +\n ` → Enable filtering on the grid:\\n` +\n ` <tbw-grid [filtering]=\"true\" />`,\n );\n return;\n }\n plugin.setFilter(field, filter);\n },\n\n getFilter: (field: string) => getPlugin()?.getFilter(field),\n\n getFilters: () => getPlugin()?.getFilters() ?? [],\n\n setFilterModel: (filters: FilterModel[]) => {\n const plugin = getPlugin();\n if (!plugin) {\n console.warn(\n `[tbw-grid:filtering] FilteringPlugin not found.\\n\\n` +\n ` → Enable filtering on the grid:\\n` +\n ` <tbw-grid [filtering]=\"true\" />`,\n );\n return;\n }\n plugin.setFilterModel(filters);\n },\n\n clearAllFilters: () => {\n const plugin = getPlugin();\n if (!plugin) {\n console.warn(\n `[tbw-grid:filtering] FilteringPlugin not found.\\n\\n` +\n ` → Enable filtering on the grid:\\n` +\n ` <tbw-grid [filtering]=\"true\" />`,\n );\n return;\n }\n plugin.clearAllFilters();\n },\n\n clearFieldFilter: (field: string) => {\n const plugin = getPlugin();\n if (!plugin) {\n console.warn(\n `[tbw-grid:filtering] FilteringPlugin not found.\\n\\n` +\n ` → Enable filtering on the grid:\\n` +\n ` <tbw-grid [filtering]=\"true\" />`,\n );\n return;\n }\n plugin.clearFieldFilter(field);\n },\n\n isFieldFiltered: (field: string) => getPlugin()?.isFieldFiltered(field) ?? false,\n\n getFilteredRowCount: () => getPlugin()?.getFilteredRowCount() ?? 0,\n\n getUniqueValues: (field: string) => getPlugin()?.getUniqueValues(field) ?? [],\n };\n}\n","/**\n * Generated bundle index. Do not edit.\n */\n\nexport * from './index';\n"],"names":[],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"toolbox-web-grid-angular-features-filtering.mjs","sources":["../../../../libs/grid-angular/features/filtering/src/index.ts","../../../../libs/grid-angular/features/filtering/src/toolbox-web-grid-angular-features-filtering.ts"],"sourcesContent":["/**\n * Filtering feature for @toolbox-web/grid-angular\n *\n * Import this module to enable the `filtering` input on Grid directive.\n * Also exports `injectGridFiltering()` for programmatic filter control.\n *\n * @example\n * ```typescript\n * import '@toolbox-web/grid-angular/features/filtering';\n *\n * <tbw-grid [filtering]=\"true\" />\n * <tbw-grid [filtering]=\"{ debounceMs: 200 }\" />\n * ```\n *\n * @example Using injectGridFiltering\n * ```typescript\n * import { injectGridFiltering } from '@toolbox-web/grid-angular/features/filtering';\n *\n * @Component({...})\n * export class MyComponent {\n * private filtering = injectGridFiltering();\n *\n * filterByStatus(status: string) {\n * this.filtering.setFilter('status', { operator: 'equals', value: status });\n * }\n * }\n * ```\n *\n * @packageDocumentation\n */\n\nimport { afterNextRender, DestroyRef, ElementRef, inject, signal, type Signal } from '@angular/core';\nimport type { DataGridElement } from '@toolbox-web/grid';\nimport '@toolbox-web/grid/features/filtering';\nimport { FilteringPlugin, type BlankMode, type FilterModel } from '@toolbox-web/grid/plugins/filtering';\n\n/**\n * Filtering methods returned from injectGridFiltering.\n *\n * Uses lazy discovery - the grid is found on first method call, not during initialization.\n */\nexport interface FilteringMethods {\n /**\n * Set a filter on a specific field.\n * @param field - The field name to filter\n * @param filter - Filter configuration, or null to remove\n */\n setFilter: (field: string, filter: Omit<FilterModel, 'field'> | null) => void;\n\n /**\n * Get the current filter for a field.\n */\n getFilter: (field: string) => FilterModel | undefined;\n\n /**\n * Get all active filters.\n */\n getFilters: () => FilterModel[];\n\n /**\n * Set all filters at once (replaces existing).\n */\n setFilterModel: (filters: FilterModel[]) => void;\n\n /**\n * Clear all active filters.\n */\n clearAllFilters: () => void;\n\n /**\n * Clear filter for a specific field.\n */\n clearFieldFilter: (field: string) => void;\n\n /**\n * Check if a field has an active filter.\n */\n isFieldFiltered: (field: string) => boolean;\n\n /**\n * Get the count of rows after filtering.\n */\n getFilteredRowCount: () => number;\n\n /**\n * Get unique values for a field (for building filter dropdowns).\n */\n getUniqueValues: (field: string) => unknown[];\n\n /**\n * Get set filters whose values no longer match any rows in the current data.\n */\n getStaleFilters: () => FilterModel[];\n\n /**\n * Get the current blank mode for a field.\n */\n getBlankMode: (field: string) => BlankMode;\n\n /**\n * Toggle blank filter mode for a field.\n */\n toggleBlankFilter: (field: string, mode: BlankMode) => void;\n\n /**\n * Signal indicating if grid is ready.\n */\n isReady: Signal<boolean>;\n}\n\n/**\n * Angular inject function for programmatic filter control.\n *\n * Uses **lazy grid discovery** - the grid element is found when methods are called,\n * not during initialization.\n *\n * @example\n * ```typescript\n * import { Component } from '@angular/core';\n * import { Grid } from '@toolbox-web/grid-angular';\n * import '@toolbox-web/grid-angular/features/filtering';\n * import { injectGridFiltering } from '@toolbox-web/grid-angular/features/filtering';\n *\n * @Component({\n * selector: 'app-my-grid',\n * imports: [Grid],\n * template: `\n * <input (input)=\"applyFilter($event)\" placeholder=\"Filter by name...\" />\n * <span>{{ filtering.getFilteredRowCount() }} results</span>\n * <button (click)=\"filtering.clearAllFilters()\">Clear</button>\n * <tbw-grid [rows]=\"rows\" [filtering]=\"true\"></tbw-grid>\n * `\n * })\n * export class MyGridComponent {\n * filtering = injectGridFiltering();\n *\n * applyFilter(event: Event) {\n * const value = (event.target as HTMLInputElement).value;\n * this.filtering.setFilter('name', value ? { operator: 'contains', value } : null);\n * }\n * }\n * ```\n */\nexport function injectGridFiltering(): FilteringMethods {\n const elementRef = inject(ElementRef);\n const destroyRef = inject(DestroyRef);\n const isReady = signal(false);\n\n let cachedGrid: DataGridElement | null = null;\n let readyPromiseStarted = false;\n\n const getGrid = (): DataGridElement | null => {\n if (cachedGrid) return cachedGrid;\n\n const grid = elementRef.nativeElement.querySelector('tbw-grid') as DataGridElement | null;\n if (grid) {\n cachedGrid = grid;\n if (!readyPromiseStarted) {\n readyPromiseStarted = true;\n grid.ready?.().then(() => isReady.set(true));\n }\n }\n return grid;\n };\n\n const getPlugin = (): FilteringPlugin | undefined => {\n return getGrid()?.getPluginByName('filtering') as FilteringPlugin | undefined;\n };\n\n // Eagerly discover the grid after the first render so isReady updates\n // without requiring a programmatic method call. Falls back to a\n // MutationObserver for lazy-rendered tabs, *ngIf, @defer, etc.\n afterNextRender(() => {\n if (getGrid()) return;\n\n const host = elementRef.nativeElement as HTMLElement;\n const observer = new MutationObserver(() => {\n if (getGrid()) observer.disconnect();\n });\n observer.observe(host, { childList: true, subtree: true });\n\n destroyRef.onDestroy(() => observer.disconnect());\n });\n\n return {\n isReady: isReady.asReadonly(),\n\n setFilter: (field: string, filter: Omit<FilterModel, 'field'> | null) => {\n const plugin = getPlugin();\n if (!plugin) {\n console.warn(\n `[tbw-grid:filtering] FilteringPlugin not found.\\n\\n` +\n ` → Enable filtering on the grid:\\n` +\n ` <tbw-grid [filtering]=\"true\" />`,\n );\n return;\n }\n plugin.setFilter(field, filter);\n },\n\n getFilter: (field: string) => getPlugin()?.getFilter(field),\n\n getFilters: () => getPlugin()?.getFilters() ?? [],\n\n setFilterModel: (filters: FilterModel[]) => {\n const plugin = getPlugin();\n if (!plugin) {\n console.warn(\n `[tbw-grid:filtering] FilteringPlugin not found.\\n\\n` +\n ` → Enable filtering on the grid:\\n` +\n ` <tbw-grid [filtering]=\"true\" />`,\n );\n return;\n }\n plugin.setFilterModel(filters);\n },\n\n clearAllFilters: () => {\n const plugin = getPlugin();\n if (!plugin) {\n console.warn(\n `[tbw-grid:filtering] FilteringPlugin not found.\\n\\n` +\n ` → Enable filtering on the grid:\\n` +\n ` <tbw-grid [filtering]=\"true\" />`,\n );\n return;\n }\n plugin.clearAllFilters();\n },\n\n clearFieldFilter: (field: string) => {\n const plugin = getPlugin();\n if (!plugin) {\n console.warn(\n `[tbw-grid:filtering] FilteringPlugin not found.\\n\\n` +\n ` → Enable filtering on the grid:\\n` +\n ` <tbw-grid [filtering]=\"true\" />`,\n );\n return;\n }\n plugin.clearFieldFilter(field);\n },\n\n isFieldFiltered: (field: string) => getPlugin()?.isFieldFiltered(field) ?? false,\n\n getFilteredRowCount: () => getPlugin()?.getFilteredRowCount() ?? 0,\n\n getUniqueValues: (field: string) => getPlugin()?.getUniqueValues(field) ?? [],\n\n getStaleFilters: () => getPlugin()?.getStaleFilters() ?? [],\n\n getBlankMode: (field: string) => getPlugin()?.getBlankMode(field) ?? 'all',\n\n toggleBlankFilter: (field: string, mode: BlankMode) => {\n const plugin = getPlugin();\n if (!plugin) {\n console.warn(\n `[tbw-grid:filtering] FilteringPlugin not found.\\n\\n` +\n ` → Enable filtering on the grid:\\n` +\n ` <tbw-grid [filtering]=\"true\" />`,\n );\n return;\n }\n plugin.toggleBlankFilter(field, mode);\n },\n };\n}\n","/**\n * Generated bundle index. Do not edit.\n */\n\nexport * from './index';\n"],"names":[],"mappings":"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"}
|
|
@@ -66,7 +66,7 @@ import '@toolbox-web/grid/features/print';
|
|
|
66
66
|
function injectGridPrint() {
|
|
67
67
|
const elementRef = inject(ElementRef);
|
|
68
68
|
const destroyRef = inject(DestroyRef);
|
|
69
|
-
const isReady = signal(false, ...(ngDevMode ? [{ debugName: "isReady" }] : []));
|
|
69
|
+
const isReady = signal(false, ...(ngDevMode ? [{ debugName: "isReady" }] : /* istanbul ignore next */ []));
|
|
70
70
|
let cachedGrid = null;
|
|
71
71
|
let readyPromiseStarted = false;
|
|
72
72
|
const getGrid = () => {
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"toolbox-web-grid-angular-features-print.mjs","sources":["../../../../libs/grid-angular/features/print/src/index.ts","../../../../libs/grid-angular/features/print/src/toolbox-web-grid-angular-features-print.ts"],"sourcesContent":["/**\n * Print feature for @toolbox-web/grid-angular\n *\n * Import this module to enable the `print` input on Grid directive.\n * Also exports `injectGridPrint()` for programmatic print control.\n *\n * @example\n * ```typescript\n * import '@toolbox-web/grid-angular/features/print';\n *\n * <tbw-grid [print]=\"true\" />\n * ```\n *\n * @example Using injectGridPrint\n * ```typescript\n * import { injectGridPrint } from '@toolbox-web/grid-angular/features/print';\n *\n * @Component({...})\n * export class MyComponent {\n * private gridPrint = injectGridPrint();\n *\n * printReport() {\n * this.gridPrint.print({ title: 'My Report' });\n * }\n * }\n * ```\n *\n * @packageDocumentation\n */\n\nimport { afterNextRender, DestroyRef, ElementRef, inject, signal, type Signal } from '@angular/core';\nimport type { DataGridElement } from '@toolbox-web/grid';\nimport '@toolbox-web/grid/features/print';\nimport { PrintPlugin, type PrintParams } from '@toolbox-web/grid/plugins/print';\n\n/**\n * Print methods returned from injectGridPrint.\n *\n * Uses lazy discovery - the grid is found on first method call, not during initialization.\n */\nexport interface PrintMethods {\n /**\n * Print the grid.\n * Opens browser print dialog after preparing the grid for printing.\n * @param params - Optional print parameters\n */\n print: (params?: PrintParams) => Promise<void>;\n\n /**\n * Check if a print operation is currently in progress.\n */\n isPrinting: () => boolean;\n\n /**\n * Signal indicating if grid is ready.\n */\n isReady: Signal<boolean>;\n}\n\n/**\n * Angular inject function for programmatic print control.\n *\n * Uses **lazy grid discovery** - the grid element is found when methods are called,\n * not during initialization.\n *\n * @example\n * ```typescript\n * import { Component } from '@angular/core';\n * import { Grid } from '@toolbox-web/grid-angular';\n * import '@toolbox-web/grid-angular/features/print';\n * import { injectGridPrint } from '@toolbox-web/grid-angular/features/print';\n *\n * @Component({\n * selector: 'app-my-grid',\n * imports: [Grid],\n * template: `\n * <button (click)=\"handlePrint()\" [disabled]=\"gridPrint.isPrinting()\">\n * {{ gridPrint.isPrinting() ? 'Printing...' : 'Print' }}\n * </button>\n * <tbw-grid [rows]=\"rows\" [print]=\"true\"></tbw-grid>\n * `\n * })\n * export class MyGridComponent {\n * gridPrint = injectGridPrint();\n *\n * async handlePrint() {\n * await this.gridPrint.print({ title: 'Employee Report', isolate: true });\n * console.log('Print dialog closed');\n * }\n * }\n * ```\n */\nexport function injectGridPrint(): PrintMethods {\n const elementRef = inject(ElementRef);\n const destroyRef = inject(DestroyRef);\n const isReady = signal(false);\n\n let cachedGrid: DataGridElement | null = null;\n let readyPromiseStarted = false;\n\n const getGrid = (): DataGridElement | null => {\n if (cachedGrid) return cachedGrid;\n\n const grid = elementRef.nativeElement.querySelector('tbw-grid') as DataGridElement | null;\n if (grid) {\n cachedGrid = grid;\n if (!readyPromiseStarted) {\n readyPromiseStarted = true;\n grid.ready?.().then(() => isReady.set(true));\n }\n }\n return grid;\n };\n\n const getPlugin = (): PrintPlugin | undefined => {\n return getGrid()?.getPluginByName('print');\n };\n\n // Eagerly discover the grid after the first render so isReady updates\n // without requiring a programmatic method call. Falls back to a\n // MutationObserver for lazy-rendered tabs, *ngIf, @defer, etc.\n afterNextRender(() => {\n if (getGrid()) return;\n\n const host = elementRef.nativeElement as HTMLElement;\n const observer = new MutationObserver(() => {\n if (getGrid()) observer.disconnect();\n });\n observer.observe(host, { childList: true, subtree: true });\n\n destroyRef.onDestroy(() => observer.disconnect());\n });\n\n return {\n isReady: isReady.asReadonly(),\n\n print: async (params?: PrintParams) => {\n const plugin = getPlugin();\n if (!plugin) {\n console.warn(\n `[tbw-grid:print] PrintPlugin not found.\\n\\n` +\n ` → Enable print on the grid:\\n` +\n ` <tbw-grid [print]=\"true\" />`,\n );\n return;\n }\n await plugin.print(params);\n },\n\n isPrinting: () => getPlugin()?.isPrinting() ?? false,\n };\n}\n","/**\n * Generated bundle index. Do not edit.\n */\n\nexport * from './index';\n"],"names":[],"mappings":";;;AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;AA4BG;AA+BH;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AAgCG;SACa,eAAe,GAAA;AAC7B,IAAA,MAAM,UAAU,GAAG,MAAM,CAAC,UAAU,CAAC;AACrC,IAAA,MAAM,UAAU,GAAG,MAAM,CAAC,UAAU,CAAC;AACrC,IAAA,MAAM,OAAO,GAAG,MAAM,CAAC,KAAK,
|
|
1
|
+
{"version":3,"file":"toolbox-web-grid-angular-features-print.mjs","sources":["../../../../libs/grid-angular/features/print/src/index.ts","../../../../libs/grid-angular/features/print/src/toolbox-web-grid-angular-features-print.ts"],"sourcesContent":["/**\n * Print feature for @toolbox-web/grid-angular\n *\n * Import this module to enable the `print` input on Grid directive.\n * Also exports `injectGridPrint()` for programmatic print control.\n *\n * @example\n * ```typescript\n * import '@toolbox-web/grid-angular/features/print';\n *\n * <tbw-grid [print]=\"true\" />\n * ```\n *\n * @example Using injectGridPrint\n * ```typescript\n * import { injectGridPrint } from '@toolbox-web/grid-angular/features/print';\n *\n * @Component({...})\n * export class MyComponent {\n * private gridPrint = injectGridPrint();\n *\n * printReport() {\n * this.gridPrint.print({ title: 'My Report' });\n * }\n * }\n * ```\n *\n * @packageDocumentation\n */\n\nimport { afterNextRender, DestroyRef, ElementRef, inject, signal, type Signal } from '@angular/core';\nimport type { DataGridElement } from '@toolbox-web/grid';\nimport '@toolbox-web/grid/features/print';\nimport { PrintPlugin, type PrintParams } from '@toolbox-web/grid/plugins/print';\n\n/**\n * Print methods returned from injectGridPrint.\n *\n * Uses lazy discovery - the grid is found on first method call, not during initialization.\n */\nexport interface PrintMethods {\n /**\n * Print the grid.\n * Opens browser print dialog after preparing the grid for printing.\n * @param params - Optional print parameters\n */\n print: (params?: PrintParams) => Promise<void>;\n\n /**\n * Check if a print operation is currently in progress.\n */\n isPrinting: () => boolean;\n\n /**\n * Signal indicating if grid is ready.\n */\n isReady: Signal<boolean>;\n}\n\n/**\n * Angular inject function for programmatic print control.\n *\n * Uses **lazy grid discovery** - the grid element is found when methods are called,\n * not during initialization.\n *\n * @example\n * ```typescript\n * import { Component } from '@angular/core';\n * import { Grid } from '@toolbox-web/grid-angular';\n * import '@toolbox-web/grid-angular/features/print';\n * import { injectGridPrint } from '@toolbox-web/grid-angular/features/print';\n *\n * @Component({\n * selector: 'app-my-grid',\n * imports: [Grid],\n * template: `\n * <button (click)=\"handlePrint()\" [disabled]=\"gridPrint.isPrinting()\">\n * {{ gridPrint.isPrinting() ? 'Printing...' : 'Print' }}\n * </button>\n * <tbw-grid [rows]=\"rows\" [print]=\"true\"></tbw-grid>\n * `\n * })\n * export class MyGridComponent {\n * gridPrint = injectGridPrint();\n *\n * async handlePrint() {\n * await this.gridPrint.print({ title: 'Employee Report', isolate: true });\n * console.log('Print dialog closed');\n * }\n * }\n * ```\n */\nexport function injectGridPrint(): PrintMethods {\n const elementRef = inject(ElementRef);\n const destroyRef = inject(DestroyRef);\n const isReady = signal(false);\n\n let cachedGrid: DataGridElement | null = null;\n let readyPromiseStarted = false;\n\n const getGrid = (): DataGridElement | null => {\n if (cachedGrid) return cachedGrid;\n\n const grid = elementRef.nativeElement.querySelector('tbw-grid') as DataGridElement | null;\n if (grid) {\n cachedGrid = grid;\n if (!readyPromiseStarted) {\n readyPromiseStarted = true;\n grid.ready?.().then(() => isReady.set(true));\n }\n }\n return grid;\n };\n\n const getPlugin = (): PrintPlugin | undefined => {\n return getGrid()?.getPluginByName('print');\n };\n\n // Eagerly discover the grid after the first render so isReady updates\n // without requiring a programmatic method call. Falls back to a\n // MutationObserver for lazy-rendered tabs, *ngIf, @defer, etc.\n afterNextRender(() => {\n if (getGrid()) return;\n\n const host = elementRef.nativeElement as HTMLElement;\n const observer = new MutationObserver(() => {\n if (getGrid()) observer.disconnect();\n });\n observer.observe(host, { childList: true, subtree: true });\n\n destroyRef.onDestroy(() => observer.disconnect());\n });\n\n return {\n isReady: isReady.asReadonly(),\n\n print: async (params?: PrintParams) => {\n const plugin = getPlugin();\n if (!plugin) {\n console.warn(\n `[tbw-grid:print] PrintPlugin not found.\\n\\n` +\n ` → Enable print on the grid:\\n` +\n ` <tbw-grid [print]=\"true\" />`,\n );\n return;\n }\n await plugin.print(params);\n },\n\n isPrinting: () => getPlugin()?.isPrinting() ?? false,\n };\n}\n","/**\n * Generated bundle index. Do not edit.\n */\n\nexport * from './index';\n"],"names":[],"mappings":";;;AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;AA4BG;AA+BH;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AAgCG;SACa,eAAe,GAAA;AAC7B,IAAA,MAAM,UAAU,GAAG,MAAM,CAAC,UAAU,CAAC;AACrC,IAAA,MAAM,UAAU,GAAG,MAAM,CAAC,UAAU,CAAC;AACrC,IAAA,MAAM,OAAO,GAAG,MAAM,CAAC,KAAK,8EAAC;IAE7B,IAAI,UAAU,GAA2B,IAAI;IAC7C,IAAI,mBAAmB,GAAG,KAAK;IAE/B,MAAM,OAAO,GAAG,MAA6B;AAC3C,QAAA,IAAI,UAAU;AAAE,YAAA,OAAO,UAAU;QAEjC,MAAM,IAAI,GAAG,UAAU,CAAC,aAAa,CAAC,aAAa,CAAC,UAAU,CAA2B;QACzF,IAAI,IAAI,EAAE;YACR,UAAU,GAAG,IAAI;YACjB,IAAI,CAAC,mBAAmB,EAAE;gBACxB,mBAAmB,GAAG,IAAI;AAC1B,gBAAA,IAAI,CAAC,KAAK,IAAI,CAAC,IAAI,CAAC,MAAM,OAAO,CAAC,GAAG,CAAC,IAAI,CAAC,CAAC;YAC9C;QACF;AACA,QAAA,OAAO,IAAI;AACb,IAAA,CAAC;IAED,MAAM,SAAS,GAAG,MAA8B;AAC9C,QAAA,OAAO,OAAO,EAAE,EAAE,eAAe,CAAC,OAAO,CAAC;AAC5C,IAAA,CAAC;;;;IAKD,eAAe,CAAC,MAAK;AACnB,QAAA,IAAI,OAAO,EAAE;YAAE;AAEf,QAAA,MAAM,IAAI,GAAG,UAAU,CAAC,aAA4B;AACpD,QAAA,MAAM,QAAQ,GAAG,IAAI,gBAAgB,CAAC,MAAK;AACzC,YAAA,IAAI,OAAO,EAAE;gBAAE,QAAQ,CAAC,UAAU,EAAE;AACtC,QAAA,CAAC,CAAC;AACF,QAAA,QAAQ,CAAC,OAAO,CAAC,IAAI,EAAE,EAAE,SAAS,EAAE,IAAI,EAAE,OAAO,EAAE,IAAI,EAAE,CAAC;QAE1D,UAAU,CAAC,SAAS,CAAC,MAAM,QAAQ,CAAC,UAAU,EAAE,CAAC;AACnD,IAAA,CAAC,CAAC;IAEF,OAAO;AACL,QAAA,OAAO,EAAE,OAAO,CAAC,UAAU,EAAE;AAE7B,QAAA,KAAK,EAAE,OAAO,MAAoB,KAAI;AACpC,YAAA,MAAM,MAAM,GAAG,SAAS,EAAE;YAC1B,IAAI,CAAC,MAAM,EAAE;gBACX,OAAO,CAAC,IAAI,CACV,CAAA,2CAAA,CAA6C;oBAC3C,CAAA,+BAAA,CAAiC;AACjC,oBAAA,CAAA,+BAAA,CAAiC,CACpC;gBACD;YACF;AACA,YAAA,MAAM,MAAM,CAAC,KAAK,CAAC,MAAM,CAAC;QAC5B,CAAC;QAED,UAAU,EAAE,MAAM,SAAS,EAAE,EAAE,UAAU,EAAE,IAAI,KAAK;KACrD;AACH;;ACvJA;;AAEG;;;;"}
|
|
@@ -76,11 +76,11 @@ import '@toolbox-web/grid/features/selection';
|
|
|
76
76
|
function injectGridSelection() {
|
|
77
77
|
const elementRef = inject(ElementRef);
|
|
78
78
|
const destroyRef = inject(DestroyRef);
|
|
79
|
-
const isReady = signal(false, ...(ngDevMode ? [{ debugName: "isReady" }] : []));
|
|
79
|
+
const isReady = signal(false, ...(ngDevMode ? [{ debugName: "isReady" }] : /* istanbul ignore next */ []));
|
|
80
80
|
// Reactive selection state
|
|
81
|
-
const selectionSignal = signal(null, ...(ngDevMode ? [{ debugName: "selectionSignal" }] : []));
|
|
82
|
-
const selectedRowIndicesSignal = signal([], ...(ngDevMode ? [{ debugName: "selectedRowIndicesSignal" }] : []));
|
|
83
|
-
const selectedRowsSignal = signal([], ...(ngDevMode ? [{ debugName: "selectedRowsSignal" }] : []));
|
|
81
|
+
const selectionSignal = signal(null, ...(ngDevMode ? [{ debugName: "selectionSignal" }] : /* istanbul ignore next */ []));
|
|
82
|
+
const selectedRowIndicesSignal = signal([], ...(ngDevMode ? [{ debugName: "selectedRowIndicesSignal" }] : /* istanbul ignore next */ []));
|
|
83
|
+
const selectedRowsSignal = signal([], ...(ngDevMode ? [{ debugName: "selectedRowsSignal" }] : /* istanbul ignore next */ []));
|
|
84
84
|
// Lazy discovery: cached grid reference
|
|
85
85
|
let cachedGrid = null;
|
|
86
86
|
let readyPromiseStarted = false;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"toolbox-web-grid-angular-features-selection.mjs","sources":["../../../../libs/grid-angular/features/selection/src/index.ts","../../../../libs/grid-angular/features/selection/src/toolbox-web-grid-angular-features-selection.ts"],"sourcesContent":["/**\n * Selection feature for @toolbox-web/grid-angular\n *\n * Import this module to enable the `selection` input on Grid directive.\n * Also exports `injectGridSelection()` for programmatic selection control.\n *\n * @example\n * ```typescript\n * import '@toolbox-web/grid-angular/features/selection';\n *\n * <tbw-grid [selection]=\"'range'\" />\n * ```\n *\n * @example Using injectGridSelection\n * ```typescript\n * import { injectGridSelection } from '@toolbox-web/grid-angular/features/selection';\n *\n * @Component({...})\n * export class MyComponent {\n * private selection = injectGridSelection<Employee>();\n *\n * selectAll() {\n * this.selection.selectAll();\n * }\n *\n * getSelected() {\n * return this.selection.getSelection();\n * }\n * }\n * ```\n *\n * @packageDocumentation\n */\n\nimport { afterNextRender, DestroyRef, ElementRef, inject, signal, type Signal } from '@angular/core';\nimport type { DataGridElement } from '@toolbox-web/grid';\nimport '@toolbox-web/grid/features/selection';\nimport {\n SelectionPlugin,\n type CellRange,\n type SelectionChangeDetail,\n type SelectionResult,\n} from '@toolbox-web/grid/plugins/selection';\n\n/**\n * Selection methods returned from injectGridSelection.\n *\n * Uses lazy discovery - the grid is found on first method call, not during initialization.\n * This ensures it works with lazy-rendered tabs, conditional rendering, etc.\n */\nexport interface SelectionMethods<TRow = unknown> {\n /**\n * Select all rows (row mode) or all cells (range mode).\n */\n selectAll: () => void;\n\n /**\n * Clear all selection.\n */\n clearSelection: () => void;\n\n /**\n * Get the current selection state (imperative, point-in-time snapshot).\n * For reactive selection state, use the `selection` signal instead.\n */\n getSelection: () => SelectionResult | null;\n\n /**\n * Check if a specific cell is selected.\n */\n isCellSelected: (row: number, col: number) => boolean;\n\n /**\n * Set selection ranges programmatically.\n */\n setRanges: (ranges: CellRange[]) => void;\n\n /**\n * Reactive selection state. Updates automatically whenever the selection changes.\n * Null when no SelectionPlugin is active or no selection has been made yet.\n *\n * @example\n * ```typescript\n * readonly selection = injectGridSelection();\n *\n * // In template:\n * // {{ selection.selection()?.ranges?.length ?? 0 }} cells selected\n *\n * // In computed:\n * readonly hasSelection = computed(() => (this.selection.selection()?.ranges?.length ?? 0) > 0);\n * ```\n */\n selection: Signal<SelectionResult | null>;\n\n /**\n * Reactive selected row indices (sorted ascending). Updates automatically.\n * Convenience signal for row-mode selection — returns `[]` in cell/range modes\n * or when nothing is selected.\n *\n * **Prefer `selectedRows`** for getting actual row objects — it handles\n * index-to-object resolution correctly regardless of sorting/filtering.\n *\n * @example\n * ```typescript\n * readonly selection = injectGridSelection();\n *\n * // In template:\n * // {{ selection.selectedRowIndices().length }} rows selected\n * ```\n */\n selectedRowIndices: Signal<number[]>;\n\n /**\n * Reactive selected row objects. Updates automatically whenever the selection changes.\n * Works in all selection modes (row, cell, range) — returns the actual row objects\n * from the grid's processed (sorted/filtered) rows.\n *\n * This is the recommended way to get selected rows. Unlike manual index mapping,\n * it correctly resolves rows even when the grid is sorted or filtered.\n *\n * @example\n * ```typescript\n * readonly selection = injectGridSelection<Employee>();\n *\n * // In template:\n * // {{ selection.selectedRows().length }} rows selected\n *\n * // In computed:\n * readonly hasSelection = computed(() => this.selection.selectedRows().length > 0);\n * ```\n */\n selectedRows: Signal<TRow[]>;\n\n /**\n * Signal indicating if grid is ready.\n * The grid is discovered lazily, so this updates when first method call succeeds.\n */\n isReady: Signal<boolean>;\n}\n\n/**\n * Angular inject function for programmatic selection control.\n *\n * Uses **lazy grid discovery** - the grid element is found when methods are called,\n * not during initialization. This ensures it works reliably with:\n * - Lazy-rendered tabs\n * - Conditional rendering (*ngIf)\n * - Dynamic component loading\n *\n * @example\n * ```typescript\n * import { Component } from '@angular/core';\n * import { Grid } from '@toolbox-web/grid-angular';\n * import '@toolbox-web/grid-angular/features/selection';\n * import { injectGridSelection } from '@toolbox-web/grid-angular/features/selection';\n *\n * @Component({\n * selector: 'app-my-grid',\n * imports: [Grid],\n * template: `\n * <button (click)=\"handleSelectAll()\">Select All</button>\n * <tbw-grid [rows]=\"rows\" [selection]=\"'range'\"></tbw-grid>\n * `\n * })\n * export class MyGridComponent {\n * selection = injectGridSelection();\n *\n * handleSelectAll() {\n * this.selection.selectAll();\n * }\n *\n * getSelectedRows() {\n * const selection = this.selection.getSelection();\n * if (!selection) return [];\n * // Derive rows from selection.ranges as needed\n * }\n * }\n * ```\n */\nexport function injectGridSelection<TRow = unknown>(): SelectionMethods<TRow> {\n const elementRef = inject(ElementRef);\n const destroyRef = inject(DestroyRef);\n const isReady = signal(false);\n\n // Reactive selection state\n const selectionSignal = signal<SelectionResult | null>(null);\n const selectedRowIndicesSignal = signal<number[]>([]);\n const selectedRowsSignal = signal<TRow[]>([]);\n\n // Lazy discovery: cached grid reference\n let cachedGrid: DataGridElement<TRow> | null = null;\n let readyPromiseStarted = false;\n let listenerAttached = false;\n\n /**\n * Handle selection-change events from the grid.\n * Updates both reactive signals.\n */\n const onSelectionChange = (detail: SelectionChangeDetail): void => {\n const plugin = getPlugin();\n if (plugin) {\n selectionSignal.set(plugin.getSelection());\n selectedRowIndicesSignal.set(detail.mode === 'row' ? plugin.getSelectedRowIndices() : []);\n selectedRowsSignal.set(plugin.getSelectedRows<TRow>());\n }\n };\n\n /**\n * Attach the selection-change event listener to the grid element.\n * Called once when the grid is first discovered.\n */\n const attachListener = (grid: DataGridElement<TRow>): void => {\n if (listenerAttached) return;\n listenerAttached = true;\n\n const unsub = grid.on('selection-change', onSelectionChange);\n\n destroyRef.onDestroy(() => {\n unsub();\n });\n };\n\n /**\n * Lazily find the grid element. Called on each method invocation.\n * Caches the reference once found and triggers ready() check.\n */\n const getGrid = (): DataGridElement<TRow> | null => {\n if (cachedGrid) return cachedGrid;\n\n const grid = elementRef.nativeElement.querySelector('tbw-grid') as DataGridElement<TRow> | null;\n if (grid) {\n cachedGrid = grid;\n attachListener(grid);\n // Start ready() check only once\n if (!readyPromiseStarted) {\n readyPromiseStarted = true;\n grid.ready?.().then(() => isReady.set(true));\n }\n }\n return grid;\n };\n\n const getPlugin = (): SelectionPlugin | undefined => {\n return getGrid()?.getPluginByName('selection') as SelectionPlugin | undefined;\n };\n\n /**\n * Sync reactive signals with the current plugin state.\n * Called once when the grid is first discovered and ready.\n */\n const syncSignals = (): void => {\n const plugin = getPlugin();\n if (plugin) {\n selectionSignal.set(plugin.getSelection());\n const mode = (plugin as any).config?.mode;\n selectedRowIndicesSignal.set(mode === 'row' ? plugin.getSelectedRowIndices() : []);\n selectedRowsSignal.set(plugin.getSelectedRows<TRow>());\n }\n };\n\n // Discover the grid after the first render so the selection-change\n // listener is attached without requiring a programmatic method call.\n // Uses a MutationObserver as fallback for lazy-rendered tabs, *ngIf,\n // @defer, etc. where the grid may not be in the DOM on first render.\n afterNextRender(() => {\n const grid = getGrid();\n if (grid) {\n grid.ready?.().then(syncSignals);\n return;\n }\n\n // Grid not in DOM yet — watch for it to appear.\n const host = elementRef.nativeElement as HTMLElement;\n const observer = new MutationObserver(() => {\n const discovered = getGrid();\n if (discovered) {\n observer.disconnect();\n discovered.ready?.().then(syncSignals);\n }\n });\n observer.observe(host, { childList: true, subtree: true });\n\n destroyRef.onDestroy(() => observer.disconnect());\n });\n\n return {\n isReady: isReady.asReadonly(),\n selection: selectionSignal.asReadonly(),\n selectedRowIndices: selectedRowIndicesSignal.asReadonly(),\n selectedRows: selectedRowsSignal.asReadonly(),\n\n selectAll: () => {\n const plugin = getPlugin();\n if (!plugin) {\n console.warn(\n `[tbw-grid:selection] SelectionPlugin not found.\\n\\n` +\n ` → Enable selection on the grid:\\n` +\n ` <tbw-grid [selection]=\"'range'\" />`,\n );\n return;\n }\n const grid = getGrid();\n // Cast to any to access protected config\n const mode = (plugin as any).config?.mode;\n\n if (mode === 'row') {\n const rowCount = grid?.rows?.length ?? 0;\n const allIndices = new Set<number>();\n for (let i = 0; i < rowCount; i++) allIndices.add(i);\n (plugin as any).selected = allIndices;\n (plugin as any).requestAfterRender?.();\n } else if (mode === 'range') {\n const rowCount = grid?.rows?.length ?? 0;\n const colCount = (grid as any)?._columns?.length ?? 0;\n if (rowCount > 0 && colCount > 0) {\n plugin.setRanges([{ from: { row: 0, col: 0 }, to: { row: rowCount - 1, col: colCount - 1 } }]);\n }\n }\n },\n\n clearSelection: () => {\n getPlugin()?.clearSelection();\n },\n\n getSelection: () => {\n return getPlugin()?.getSelection() ?? null;\n },\n\n isCellSelected: (row: number, col: number) => {\n return getPlugin()?.isCellSelected(row, col) ?? false;\n },\n\n setRanges: (ranges: CellRange[]) => {\n getPlugin()?.setRanges(ranges);\n },\n };\n}\n","/**\n * Generated bundle index. Do not edit.\n */\n\nexport * from './index';\n"],"names":[],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"toolbox-web-grid-angular-features-selection.mjs","sources":["../../../../libs/grid-angular/features/selection/src/index.ts","../../../../libs/grid-angular/features/selection/src/toolbox-web-grid-angular-features-selection.ts"],"sourcesContent":["/**\n * Selection feature for @toolbox-web/grid-angular\n *\n * Import this module to enable the `selection` input on Grid directive.\n * Also exports `injectGridSelection()` for programmatic selection control.\n *\n * @example\n * ```typescript\n * import '@toolbox-web/grid-angular/features/selection';\n *\n * <tbw-grid [selection]=\"'range'\" />\n * ```\n *\n * @example Using injectGridSelection\n * ```typescript\n * import { injectGridSelection } from '@toolbox-web/grid-angular/features/selection';\n *\n * @Component({...})\n * export class MyComponent {\n * private selection = injectGridSelection<Employee>();\n *\n * selectAll() {\n * this.selection.selectAll();\n * }\n *\n * getSelected() {\n * return this.selection.getSelection();\n * }\n * }\n * ```\n *\n * @packageDocumentation\n */\n\nimport { afterNextRender, DestroyRef, ElementRef, inject, signal, type Signal } from '@angular/core';\nimport type { DataGridElement } from '@toolbox-web/grid';\nimport '@toolbox-web/grid/features/selection';\nimport {\n SelectionPlugin,\n type CellRange,\n type SelectionChangeDetail,\n type SelectionResult,\n} from '@toolbox-web/grid/plugins/selection';\n\n/**\n * Selection methods returned from injectGridSelection.\n *\n * Uses lazy discovery - the grid is found on first method call, not during initialization.\n * This ensures it works with lazy-rendered tabs, conditional rendering, etc.\n */\nexport interface SelectionMethods<TRow = unknown> {\n /**\n * Select all rows (row mode) or all cells (range mode).\n */\n selectAll: () => void;\n\n /**\n * Clear all selection.\n */\n clearSelection: () => void;\n\n /**\n * Get the current selection state (imperative, point-in-time snapshot).\n * For reactive selection state, use the `selection` signal instead.\n */\n getSelection: () => SelectionResult | null;\n\n /**\n * Check if a specific cell is selected.\n */\n isCellSelected: (row: number, col: number) => boolean;\n\n /**\n * Set selection ranges programmatically.\n */\n setRanges: (ranges: CellRange[]) => void;\n\n /**\n * Reactive selection state. Updates automatically whenever the selection changes.\n * Null when no SelectionPlugin is active or no selection has been made yet.\n *\n * @example\n * ```typescript\n * readonly selection = injectGridSelection();\n *\n * // In template:\n * // {{ selection.selection()?.ranges?.length ?? 0 }} cells selected\n *\n * // In computed:\n * readonly hasSelection = computed(() => (this.selection.selection()?.ranges?.length ?? 0) > 0);\n * ```\n */\n selection: Signal<SelectionResult | null>;\n\n /**\n * Reactive selected row indices (sorted ascending). Updates automatically.\n * Convenience signal for row-mode selection — returns `[]` in cell/range modes\n * or when nothing is selected.\n *\n * **Prefer `selectedRows`** for getting actual row objects — it handles\n * index-to-object resolution correctly regardless of sorting/filtering.\n *\n * @example\n * ```typescript\n * readonly selection = injectGridSelection();\n *\n * // In template:\n * // {{ selection.selectedRowIndices().length }} rows selected\n * ```\n */\n selectedRowIndices: Signal<number[]>;\n\n /**\n * Reactive selected row objects. Updates automatically whenever the selection changes.\n * Works in all selection modes (row, cell, range) — returns the actual row objects\n * from the grid's processed (sorted/filtered) rows.\n *\n * This is the recommended way to get selected rows. Unlike manual index mapping,\n * it correctly resolves rows even when the grid is sorted or filtered.\n *\n * @example\n * ```typescript\n * readonly selection = injectGridSelection<Employee>();\n *\n * // In template:\n * // {{ selection.selectedRows().length }} rows selected\n *\n * // In computed:\n * readonly hasSelection = computed(() => this.selection.selectedRows().length > 0);\n * ```\n */\n selectedRows: Signal<TRow[]>;\n\n /**\n * Signal indicating if grid is ready.\n * The grid is discovered lazily, so this updates when first method call succeeds.\n */\n isReady: Signal<boolean>;\n}\n\n/**\n * Angular inject function for programmatic selection control.\n *\n * Uses **lazy grid discovery** - the grid element is found when methods are called,\n * not during initialization. This ensures it works reliably with:\n * - Lazy-rendered tabs\n * - Conditional rendering (*ngIf)\n * - Dynamic component loading\n *\n * @example\n * ```typescript\n * import { Component } from '@angular/core';\n * import { Grid } from '@toolbox-web/grid-angular';\n * import '@toolbox-web/grid-angular/features/selection';\n * import { injectGridSelection } from '@toolbox-web/grid-angular/features/selection';\n *\n * @Component({\n * selector: 'app-my-grid',\n * imports: [Grid],\n * template: `\n * <button (click)=\"handleSelectAll()\">Select All</button>\n * <tbw-grid [rows]=\"rows\" [selection]=\"'range'\"></tbw-grid>\n * `\n * })\n * export class MyGridComponent {\n * selection = injectGridSelection();\n *\n * handleSelectAll() {\n * this.selection.selectAll();\n * }\n *\n * getSelectedRows() {\n * const selection = this.selection.getSelection();\n * if (!selection) return [];\n * // Derive rows from selection.ranges as needed\n * }\n * }\n * ```\n */\nexport function injectGridSelection<TRow = unknown>(): SelectionMethods<TRow> {\n const elementRef = inject(ElementRef);\n const destroyRef = inject(DestroyRef);\n const isReady = signal(false);\n\n // Reactive selection state\n const selectionSignal = signal<SelectionResult | null>(null);\n const selectedRowIndicesSignal = signal<number[]>([]);\n const selectedRowsSignal = signal<TRow[]>([]);\n\n // Lazy discovery: cached grid reference\n let cachedGrid: DataGridElement<TRow> | null = null;\n let readyPromiseStarted = false;\n let listenerAttached = false;\n\n /**\n * Handle selection-change events from the grid.\n * Updates both reactive signals.\n */\n const onSelectionChange = (detail: SelectionChangeDetail): void => {\n const plugin = getPlugin();\n if (plugin) {\n selectionSignal.set(plugin.getSelection());\n selectedRowIndicesSignal.set(detail.mode === 'row' ? plugin.getSelectedRowIndices() : []);\n selectedRowsSignal.set(plugin.getSelectedRows<TRow>());\n }\n };\n\n /**\n * Attach the selection-change event listener to the grid element.\n * Called once when the grid is first discovered.\n */\n const attachListener = (grid: DataGridElement<TRow>): void => {\n if (listenerAttached) return;\n listenerAttached = true;\n\n const unsub = grid.on('selection-change', onSelectionChange);\n\n destroyRef.onDestroy(() => {\n unsub();\n });\n };\n\n /**\n * Lazily find the grid element. Called on each method invocation.\n * Caches the reference once found and triggers ready() check.\n */\n const getGrid = (): DataGridElement<TRow> | null => {\n if (cachedGrid) return cachedGrid;\n\n const grid = elementRef.nativeElement.querySelector('tbw-grid') as DataGridElement<TRow> | null;\n if (grid) {\n cachedGrid = grid;\n attachListener(grid);\n // Start ready() check only once\n if (!readyPromiseStarted) {\n readyPromiseStarted = true;\n grid.ready?.().then(() => isReady.set(true));\n }\n }\n return grid;\n };\n\n const getPlugin = (): SelectionPlugin | undefined => {\n return getGrid()?.getPluginByName('selection') as SelectionPlugin | undefined;\n };\n\n /**\n * Sync reactive signals with the current plugin state.\n * Called once when the grid is first discovered and ready.\n */\n const syncSignals = (): void => {\n const plugin = getPlugin();\n if (plugin) {\n selectionSignal.set(plugin.getSelection());\n const mode = (plugin as any).config?.mode;\n selectedRowIndicesSignal.set(mode === 'row' ? plugin.getSelectedRowIndices() : []);\n selectedRowsSignal.set(plugin.getSelectedRows<TRow>());\n }\n };\n\n // Discover the grid after the first render so the selection-change\n // listener is attached without requiring a programmatic method call.\n // Uses a MutationObserver as fallback for lazy-rendered tabs, *ngIf,\n // @defer, etc. where the grid may not be in the DOM on first render.\n afterNextRender(() => {\n const grid = getGrid();\n if (grid) {\n grid.ready?.().then(syncSignals);\n return;\n }\n\n // Grid not in DOM yet — watch for it to appear.\n const host = elementRef.nativeElement as HTMLElement;\n const observer = new MutationObserver(() => {\n const discovered = getGrid();\n if (discovered) {\n observer.disconnect();\n discovered.ready?.().then(syncSignals);\n }\n });\n observer.observe(host, { childList: true, subtree: true });\n\n destroyRef.onDestroy(() => observer.disconnect());\n });\n\n return {\n isReady: isReady.asReadonly(),\n selection: selectionSignal.asReadonly(),\n selectedRowIndices: selectedRowIndicesSignal.asReadonly(),\n selectedRows: selectedRowsSignal.asReadonly(),\n\n selectAll: () => {\n const plugin = getPlugin();\n if (!plugin) {\n console.warn(\n `[tbw-grid:selection] SelectionPlugin not found.\\n\\n` +\n ` → Enable selection on the grid:\\n` +\n ` <tbw-grid [selection]=\"'range'\" />`,\n );\n return;\n }\n const grid = getGrid();\n // Cast to any to access protected config\n const mode = (plugin as any).config?.mode;\n\n if (mode === 'row') {\n const rowCount = grid?.rows?.length ?? 0;\n const allIndices = new Set<number>();\n for (let i = 0; i < rowCount; i++) allIndices.add(i);\n (plugin as any).selected = allIndices;\n (plugin as any).requestAfterRender?.();\n } else if (mode === 'range') {\n const rowCount = grid?.rows?.length ?? 0;\n const colCount = (grid as any)?._columns?.length ?? 0;\n if (rowCount > 0 && colCount > 0) {\n plugin.setRanges([{ from: { row: 0, col: 0 }, to: { row: rowCount - 1, col: colCount - 1 } }]);\n }\n }\n },\n\n clearSelection: () => {\n getPlugin()?.clearSelection();\n },\n\n getSelection: () => {\n return getPlugin()?.getSelection() ?? null;\n },\n\n isCellSelected: (row: number, col: number) => {\n return getPlugin()?.isCellSelected(row, col) ?? false;\n },\n\n setRanges: (ranges: CellRange[]) => {\n getPlugin()?.setRanges(ranges);\n },\n };\n}\n","/**\n * Generated bundle index. Do not edit.\n */\n\nexport * from './index';\n"],"names":[],"mappings":";;;AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AAgCG;AA4GH;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AAsCG;SACa,mBAAmB,GAAA;AACjC,IAAA,MAAM,UAAU,GAAG,MAAM,CAAC,UAAU,CAAC;AACrC,IAAA,MAAM,UAAU,GAAG,MAAM,CAAC,UAAU,CAAC;AACrC,IAAA,MAAM,OAAO,GAAG,MAAM,CAAC,KAAK,8EAAC;;AAG7B,IAAA,MAAM,eAAe,GAAG,MAAM,CAAyB,IAAI,sFAAC;AAC5D,IAAA,MAAM,wBAAwB,GAAG,MAAM,CAAW,EAAE,+FAAC;AACrD,IAAA,MAAM,kBAAkB,GAAG,MAAM,CAAS,EAAE,yFAAC;;IAG7C,IAAI,UAAU,GAAiC,IAAI;IACnD,IAAI,mBAAmB,GAAG,KAAK;IAC/B,IAAI,gBAAgB,GAAG,KAAK;AAE5B;;;AAGG;AACH,IAAA,MAAM,iBAAiB,GAAG,CAAC,MAA6B,KAAU;AAChE,QAAA,MAAM,MAAM,GAAG,SAAS,EAAE;QAC1B,IAAI,MAAM,EAAE;YACV,eAAe,CAAC,GAAG,CAAC,MAAM,CAAC,YAAY,EAAE,CAAC;YAC1C,wBAAwB,CAAC,GAAG,CAAC,MAAM,CAAC,IAAI,KAAK,KAAK,GAAG,MAAM,CAAC,qBAAqB,EAAE,GAAG,EAAE,CAAC;YACzF,kBAAkB,CAAC,GAAG,CAAC,MAAM,CAAC,eAAe,EAAQ,CAAC;QACxD;AACF,IAAA,CAAC;AAED;;;AAGG;AACH,IAAA,MAAM,cAAc,GAAG,CAAC,IAA2B,KAAU;AAC3D,QAAA,IAAI,gBAAgB;YAAE;QACtB,gBAAgB,GAAG,IAAI;QAEvB,MAAM,KAAK,GAAG,IAAI,CAAC,EAAE,CAAC,kBAAkB,EAAE,iBAAiB,CAAC;AAE5D,QAAA,UAAU,CAAC,SAAS,CAAC,MAAK;AACxB,YAAA,KAAK,EAAE;AACT,QAAA,CAAC,CAAC;AACJ,IAAA,CAAC;AAED;;;AAGG;IACH,MAAM,OAAO,GAAG,MAAmC;AACjD,QAAA,IAAI,UAAU;AAAE,YAAA,OAAO,UAAU;QAEjC,MAAM,IAAI,GAAG,UAAU,CAAC,aAAa,CAAC,aAAa,CAAC,UAAU,CAAiC;QAC/F,IAAI,IAAI,EAAE;YACR,UAAU,GAAG,IAAI;YACjB,cAAc,CAAC,IAAI,CAAC;;YAEpB,IAAI,CAAC,mBAAmB,EAAE;gBACxB,mBAAmB,GAAG,IAAI;AAC1B,gBAAA,IAAI,CAAC,KAAK,IAAI,CAAC,IAAI,CAAC,MAAM,OAAO,CAAC,GAAG,CAAC,IAAI,CAAC,CAAC;YAC9C;QACF;AACA,QAAA,OAAO,IAAI;AACb,IAAA,CAAC;IAED,MAAM,SAAS,GAAG,MAAkC;AAClD,QAAA,OAAO,OAAO,EAAE,EAAE,eAAe,CAAC,WAAW,CAAgC;AAC/E,IAAA,CAAC;AAED;;;AAGG;IACH,MAAM,WAAW,GAAG,MAAW;AAC7B,QAAA,MAAM,MAAM,GAAG,SAAS,EAAE;QAC1B,IAAI,MAAM,EAAE;YACV,eAAe,CAAC,GAAG,CAAC,MAAM,CAAC,YAAY,EAAE,CAAC;AAC1C,YAAA,MAAM,IAAI,GAAI,MAAc,CAAC,MAAM,EAAE,IAAI;AACzC,YAAA,wBAAwB,CAAC,GAAG,CAAC,IAAI,KAAK,KAAK,GAAG,MAAM,CAAC,qBAAqB,EAAE,GAAG,EAAE,CAAC;YAClF,kBAAkB,CAAC,GAAG,CAAC,MAAM,CAAC,eAAe,EAAQ,CAAC;QACxD;AACF,IAAA,CAAC;;;;;IAMD,eAAe,CAAC,MAAK;AACnB,QAAA,MAAM,IAAI,GAAG,OAAO,EAAE;QACtB,IAAI,IAAI,EAAE;YACR,IAAI,CAAC,KAAK,IAAI,CAAC,IAAI,CAAC,WAAW,CAAC;YAChC;QACF;;AAGA,QAAA,MAAM,IAAI,GAAG,UAAU,CAAC,aAA4B;AACpD,QAAA,MAAM,QAAQ,GAAG,IAAI,gBAAgB,CAAC,MAAK;AACzC,YAAA,MAAM,UAAU,GAAG,OAAO,EAAE;YAC5B,IAAI,UAAU,EAAE;gBACd,QAAQ,CAAC,UAAU,EAAE;gBACrB,UAAU,CAAC,KAAK,IAAI,CAAC,IAAI,CAAC,WAAW,CAAC;YACxC;AACF,QAAA,CAAC,CAAC;AACF,QAAA,QAAQ,CAAC,OAAO,CAAC,IAAI,EAAE,EAAE,SAAS,EAAE,IAAI,EAAE,OAAO,EAAE,IAAI,EAAE,CAAC;QAE1D,UAAU,CAAC,SAAS,CAAC,MAAM,QAAQ,CAAC,UAAU,EAAE,CAAC;AACnD,IAAA,CAAC,CAAC;IAEF,OAAO;AACL,QAAA,OAAO,EAAE,OAAO,CAAC,UAAU,EAAE;AAC7B,QAAA,SAAS,EAAE,eAAe,CAAC,UAAU,EAAE;AACvC,QAAA,kBAAkB,EAAE,wBAAwB,CAAC,UAAU,EAAE;AACzD,QAAA,YAAY,EAAE,kBAAkB,CAAC,UAAU,EAAE;QAE7C,SAAS,EAAE,MAAK;AACd,YAAA,MAAM,MAAM,GAAG,SAAS,EAAE;YAC1B,IAAI,CAAC,MAAM,EAAE;gBACX,OAAO,CAAC,IAAI,CACV,CAAA,mDAAA,CAAqD;oBACnD,CAAA,mCAAA,CAAqC;AACrC,oBAAA,CAAA,sCAAA,CAAwC,CAC3C;gBACD;YACF;AACA,YAAA,MAAM,IAAI,GAAG,OAAO,EAAE;;AAEtB,YAAA,MAAM,IAAI,GAAI,MAAc,CAAC,MAAM,EAAE,IAAI;AAEzC,YAAA,IAAI,IAAI,KAAK,KAAK,EAAE;gBAClB,MAAM,QAAQ,GAAG,IAAI,EAAE,IAAI,EAAE,MAAM,IAAI,CAAC;AACxC,gBAAA,MAAM,UAAU,GAAG,IAAI,GAAG,EAAU;gBACpC,KAAK,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,QAAQ,EAAE,CAAC,EAAE;AAAE,oBAAA,UAAU,CAAC,GAAG,CAAC,CAAC,CAAC;AACnD,gBAAA,MAAc,CAAC,QAAQ,GAAG,UAAU;AACpC,gBAAA,MAAc,CAAC,kBAAkB,IAAI;YACxC;AAAO,iBAAA,IAAI,IAAI,KAAK,OAAO,EAAE;gBAC3B,MAAM,QAAQ,GAAG,IAAI,EAAE,IAAI,EAAE,MAAM,IAAI,CAAC;gBACxC,MAAM,QAAQ,GAAI,IAAY,EAAE,QAAQ,EAAE,MAAM,IAAI,CAAC;gBACrD,IAAI,QAAQ,GAAG,CAAC,IAAI,QAAQ,GAAG,CAAC,EAAE;AAChC,oBAAA,MAAM,CAAC,SAAS,CAAC,CAAC,EAAE,IAAI,EAAE,EAAE,GAAG,EAAE,CAAC,EAAE,GAAG,EAAE,CAAC,EAAE,EAAE,EAAE,EAAE,EAAE,GAAG,EAAE,QAAQ,GAAG,CAAC,EAAE,GAAG,EAAE,QAAQ,GAAG,CAAC,EAAE,EAAE,CAAC,CAAC;gBAChG;YACF;QACF,CAAC;QAED,cAAc,EAAE,MAAK;AACnB,YAAA,SAAS,EAAE,EAAE,cAAc,EAAE;QAC/B,CAAC;QAED,YAAY,EAAE,MAAK;AACjB,YAAA,OAAO,SAAS,EAAE,EAAE,YAAY,EAAE,IAAI,IAAI;QAC5C,CAAC;AAED,QAAA,cAAc,EAAE,CAAC,GAAW,EAAE,GAAW,KAAI;YAC3C,OAAO,SAAS,EAAE,EAAE,cAAc,CAAC,GAAG,EAAE,GAAG,CAAC,IAAI,KAAK;QACvD,CAAC;AAED,QAAA,SAAS,EAAE,CAAC,MAAmB,KAAI;AACjC,YAAA,SAAS,EAAE,EAAE,SAAS,CAAC,MAAM,CAAC;QAChC,CAAC;KACF;AACH;;AChVA;;AAEG;;;;"}
|
|
@@ -62,10 +62,10 @@ import '@toolbox-web/grid/features/undo-redo';
|
|
|
62
62
|
function injectGridUndoRedo() {
|
|
63
63
|
const elementRef = inject(ElementRef);
|
|
64
64
|
const destroyRef = inject(DestroyRef);
|
|
65
|
-
const isReady = signal(false, ...(ngDevMode ? [{ debugName: "isReady" }] : []));
|
|
65
|
+
const isReady = signal(false, ...(ngDevMode ? [{ debugName: "isReady" }] : /* istanbul ignore next */ []));
|
|
66
66
|
// Reactive undo/redo availability signals
|
|
67
|
-
const canUndoSignal = signal(false, ...(ngDevMode ? [{ debugName: "canUndoSignal" }] : []));
|
|
68
|
-
const canRedoSignal = signal(false, ...(ngDevMode ? [{ debugName: "canRedoSignal" }] : []));
|
|
67
|
+
const canUndoSignal = signal(false, ...(ngDevMode ? [{ debugName: "canUndoSignal" }] : /* istanbul ignore next */ []));
|
|
68
|
+
const canRedoSignal = signal(false, ...(ngDevMode ? [{ debugName: "canRedoSignal" }] : /* istanbul ignore next */ []));
|
|
69
69
|
let cachedGrid = null;
|
|
70
70
|
let readyPromiseStarted = false;
|
|
71
71
|
let listenerAttached = false;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"toolbox-web-grid-angular-features-undo-redo.mjs","sources":["../../../../libs/grid-angular/features/undo-redo/src/index.ts","../../../../libs/grid-angular/features/undo-redo/src/toolbox-web-grid-angular-features-undo-redo.ts"],"sourcesContent":["/**\n * Undo/Redo feature for @toolbox-web/grid-angular\n *\n * Import this module to enable the `undoRedo` input on Grid directive.\n * Also exports `injectGridUndoRedo()` for programmatic undo/redo control.\n * Requires editing feature to be enabled.\n *\n * @example\n * ```typescript\n * import '@toolbox-web/grid-angular/features/editing';\n * import '@toolbox-web/grid-angular/features/undo-redo';\n *\n * <tbw-grid [editing]=\"'dblclick'\" [undoRedo]=\"true\" />\n * ```\n *\n * @example Using injectGridUndoRedo\n * ```typescript\n * import { injectGridUndoRedo } from '@toolbox-web/grid-angular/features/undo-redo';\n *\n * @Component({...})\n * export class MyComponent {\n * private undoRedo = injectGridUndoRedo();\n *\n * undo() { this.undoRedo.undo(); }\n * redo() { this.undoRedo.redo(); }\n * }\n * ```\n *\n * @packageDocumentation\n */\n\nimport { afterNextRender, DestroyRef, ElementRef, inject, signal, type Signal } from '@angular/core';\nimport type { DataGridElement } from '@toolbox-web/grid';\nimport '@toolbox-web/grid/features/undo-redo';\nimport { UndoRedoPlugin, type UndoRedoAction } from '@toolbox-web/grid/plugins/undo-redo';\n\n/**\n * Undo/Redo methods returned from injectGridUndoRedo.\n *\n * Uses lazy discovery - the grid is found on first method call, not during initialization.\n */\nexport interface UndoRedoMethods {\n /**\n * Undo the last edit action.\n * @returns The undone action (or compound action), or null if nothing to undo\n */\n undo: () => UndoRedoAction | null;\n\n /**\n * Redo the last undone action.\n * @returns The redone action (or compound action), or null if nothing to redo\n */\n redo: () => UndoRedoAction | null;\n\n /**\n * Reactive signal indicating whether undo is available.\n * Updates automatically when edits are made, undone, redone, or history is cleared.\n *\n * @example\n * ```typescript\n * // In template:\n * // <button [disabled]=\"!undoRedo.canUndo()\">Undo</button>\n *\n * // In computed:\n * readonly undoAvailable = computed(() => this.undoRedo.canUndo());\n * ```\n */\n canUndo: Signal<boolean>;\n\n /**\n * Reactive signal indicating whether redo is available.\n * Updates automatically when edits are made, undone, redone, or history is cleared.\n *\n * @example\n * ```typescript\n * // In template:\n * // <button [disabled]=\"!undoRedo.canRedo()\">Redo</button>\n *\n * // In computed:\n * readonly redoAvailable = computed(() => this.undoRedo.canRedo());\n * ```\n */\n canRedo: Signal<boolean>;\n\n /**\n * Clear all undo/redo history.\n */\n clearHistory: () => void;\n\n /**\n * Get a copy of the current undo stack.\n */\n getUndoStack: () => UndoRedoAction[];\n\n /**\n * Get a copy of the current redo stack.\n */\n getRedoStack: () => UndoRedoAction[];\n\n /**\n * Manually record an edit action.\n * If a transaction is active, the action is buffered; otherwise it's pushed to the undo stack.\n */\n recordEdit: (rowIndex: number, field: string, oldValue: unknown, newValue: unknown) => void;\n\n /**\n * Begin a transaction. All edits recorded until `endTransaction()` are grouped\n * into a single compound action for undo/redo.\n * @throws If a transaction is already active\n */\n beginTransaction: () => void;\n\n /**\n * End the active transaction and push the compound action to the undo stack.\n * If only one edit was recorded, it's pushed as a plain EditAction.\n * If no edits were recorded, the transaction is discarded.\n * @throws If no transaction is active\n */\n endTransaction: () => void;\n\n /**\n * Signal indicating if grid is ready.\n */\n isReady: Signal<boolean>;\n}\n\n/**\n * Angular inject function for programmatic undo/redo control.\n *\n * Uses **lazy grid discovery** - the grid element is found when methods are called,\n * not during initialization.\n *\n * @example\n * ```typescript\n * import { Component } from '@angular/core';\n * import { Grid } from '@toolbox-web/grid-angular';\n * import '@toolbox-web/grid-angular/features/editing';\n * import '@toolbox-web/grid-angular/features/undo-redo';\n * import { injectGridUndoRedo } from '@toolbox-web/grid-angular/features/undo-redo';\n *\n * @Component({\n * selector: 'app-my-grid',\n * imports: [Grid],\n * template: `\n * <button (click)=\"undoRedo.undo()\" [disabled]=\"!undoRedo.canUndo()\">Undo</button>\n * <button (click)=\"undoRedo.redo()\" [disabled]=\"!undoRedo.canRedo()\">Redo</button>\n * <tbw-grid [rows]=\"rows\" [editing]=\"'dblclick'\" [undoRedo]=\"true\"></tbw-grid>\n * `\n * })\n * export class MyGridComponent {\n * undoRedo = injectGridUndoRedo();\n * }\n * ```\n */\nexport function injectGridUndoRedo(): UndoRedoMethods {\n const elementRef = inject(ElementRef);\n const destroyRef = inject(DestroyRef);\n const isReady = signal(false);\n\n // Reactive undo/redo availability signals\n const canUndoSignal = signal(false);\n const canRedoSignal = signal(false);\n\n let cachedGrid: DataGridElement | null = null;\n let readyPromiseStarted = false;\n let listenerAttached = false;\n\n /**\n * Sync canUndo/canRedo signals with the current plugin state.\n */\n const syncSignals = (): void => {\n const plugin = getPlugin();\n if (plugin) {\n canUndoSignal.set(plugin.canUndo());\n canRedoSignal.set(plugin.canRedo());\n }\n };\n\n /**\n * Attach event listeners to the grid for undo/redo state changes.\n * Listens for `undo`, `redo`, and `cell-commit` DOM events.\n */\n const attachListeners = (grid: DataGridElement): void => {\n if (listenerAttached) return;\n listenerAttached = true;\n\n const unsubs = [grid.on('undo', syncSignals), grid.on('redo', syncSignals), grid.on('cell-commit', syncSignals)];\n\n destroyRef.onDestroy(() => {\n unsubs.forEach((fn) => fn());\n });\n };\n\n const getGrid = (): DataGridElement | null => {\n if (cachedGrid) return cachedGrid;\n\n const grid = elementRef.nativeElement.querySelector('tbw-grid') as DataGridElement | null;\n if (grid) {\n cachedGrid = grid;\n attachListeners(grid);\n if (!readyPromiseStarted) {\n readyPromiseStarted = true;\n grid.ready?.().then(() => isReady.set(true));\n }\n }\n return grid;\n };\n\n const getPlugin = (): UndoRedoPlugin | undefined => {\n return getGrid()?.getPluginByName('undoRedo');\n };\n\n // Eagerly discover the grid after the first render so event listeners\n // are attached and isReady updates without requiring a programmatic\n // method call. Falls back to MutationObserver for lazy-rendered content.\n afterNextRender(() => {\n const grid = getGrid();\n if (grid) {\n grid.ready?.().then(syncSignals);\n return;\n }\n\n const host = elementRef.nativeElement as HTMLElement;\n const observer = new MutationObserver(() => {\n const discovered = getGrid();\n if (discovered) {\n observer.disconnect();\n discovered.ready?.().then(syncSignals);\n }\n });\n observer.observe(host, { childList: true, subtree: true });\n\n destroyRef.onDestroy(() => observer.disconnect());\n });\n\n return {\n isReady: isReady.asReadonly(),\n canUndo: canUndoSignal.asReadonly(),\n canRedo: canRedoSignal.asReadonly(),\n\n undo: () => {\n const plugin = getPlugin();\n if (!plugin) {\n console.warn(\n `[tbw-grid:undoRedo] UndoRedoPlugin not found.\\n\\n` +\n ` → Enable undo/redo on the grid:\\n` +\n ` <tbw-grid [editing]=\"'dblclick'\" [undoRedo]=\"true\" />`,\n );\n return null;\n }\n const result = plugin.undo();\n syncSignals();\n return result;\n },\n\n redo: () => {\n const plugin = getPlugin();\n if (!plugin) {\n console.warn(\n `[tbw-grid:undoRedo] UndoRedoPlugin not found.\\n\\n` +\n ` → Enable undo/redo on the grid:\\n` +\n ` <tbw-grid [editing]=\"'dblclick'\" [undoRedo]=\"true\" />`,\n );\n return null;\n }\n const result = plugin.redo();\n syncSignals();\n return result;\n },\n\n clearHistory: () => {\n const plugin = getPlugin();\n if (!plugin) {\n console.warn(\n `[tbw-grid:undoRedo] UndoRedoPlugin not found.\\n\\n` +\n ` → Enable undo/redo on the grid:\\n` +\n ` <tbw-grid [editing]=\"'dblclick'\" [undoRedo]=\"true\" />`,\n );\n return;\n }\n plugin.clearHistory();\n syncSignals();\n },\n\n getUndoStack: () => getPlugin()?.getUndoStack() ?? [],\n\n getRedoStack: () => getPlugin()?.getRedoStack() ?? [],\n\n recordEdit: (rowIndex: number, field: string, oldValue: unknown, newValue: unknown) => {\n const plugin = getPlugin();\n if (!plugin) {\n console.warn(\n `[tbw-grid:undoRedo] UndoRedoPlugin not found.\\n\\n` +\n ` → Enable undo/redo on the grid:\\n` +\n ` <tbw-grid [editing]=\"'dblclick'\" [undoRedo]=\"true\" />`,\n );\n return;\n }\n plugin.recordEdit(rowIndex, field, oldValue, newValue);\n syncSignals();\n },\n\n beginTransaction: () => {\n const plugin = getPlugin();\n if (!plugin) {\n console.warn(\n `[tbw-grid:undoRedo] UndoRedoPlugin not found.\\n\\n` +\n ` → Enable undo/redo on the grid:\\n` +\n ` <tbw-grid [editing]=\"'dblclick'\" [undoRedo]=\"true\" />`,\n );\n return;\n }\n plugin.beginTransaction();\n },\n\n endTransaction: () => {\n const plugin = getPlugin();\n if (!plugin) {\n console.warn(\n `[tbw-grid:undoRedo] UndoRedoPlugin not found.\\n\\n` +\n ` → Enable undo/redo on the grid:\\n` +\n ` <tbw-grid [editing]=\"'dblclick'\" [undoRedo]=\"true\" />`,\n );\n return;\n }\n plugin.endTransaction();\n syncSignals();\n },\n };\n}\n","/**\n * Generated bundle index. Do not edit.\n */\n\nexport * from './index';\n"],"names":[],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"toolbox-web-grid-angular-features-undo-redo.mjs","sources":["../../../../libs/grid-angular/features/undo-redo/src/index.ts","../../../../libs/grid-angular/features/undo-redo/src/toolbox-web-grid-angular-features-undo-redo.ts"],"sourcesContent":["/**\n * Undo/Redo feature for @toolbox-web/grid-angular\n *\n * Import this module to enable the `undoRedo` input on Grid directive.\n * Also exports `injectGridUndoRedo()` for programmatic undo/redo control.\n * Requires editing feature to be enabled.\n *\n * @example\n * ```typescript\n * import '@toolbox-web/grid-angular/features/editing';\n * import '@toolbox-web/grid-angular/features/undo-redo';\n *\n * <tbw-grid [editing]=\"'dblclick'\" [undoRedo]=\"true\" />\n * ```\n *\n * @example Using injectGridUndoRedo\n * ```typescript\n * import { injectGridUndoRedo } from '@toolbox-web/grid-angular/features/undo-redo';\n *\n * @Component({...})\n * export class MyComponent {\n * private undoRedo = injectGridUndoRedo();\n *\n * undo() { this.undoRedo.undo(); }\n * redo() { this.undoRedo.redo(); }\n * }\n * ```\n *\n * @packageDocumentation\n */\n\nimport { afterNextRender, DestroyRef, ElementRef, inject, signal, type Signal } from '@angular/core';\nimport type { DataGridElement } from '@toolbox-web/grid';\nimport '@toolbox-web/grid/features/undo-redo';\nimport { UndoRedoPlugin, type UndoRedoAction } from '@toolbox-web/grid/plugins/undo-redo';\n\n/**\n * Undo/Redo methods returned from injectGridUndoRedo.\n *\n * Uses lazy discovery - the grid is found on first method call, not during initialization.\n */\nexport interface UndoRedoMethods {\n /**\n * Undo the last edit action.\n * @returns The undone action (or compound action), or null if nothing to undo\n */\n undo: () => UndoRedoAction | null;\n\n /**\n * Redo the last undone action.\n * @returns The redone action (or compound action), or null if nothing to redo\n */\n redo: () => UndoRedoAction | null;\n\n /**\n * Reactive signal indicating whether undo is available.\n * Updates automatically when edits are made, undone, redone, or history is cleared.\n *\n * @example\n * ```typescript\n * // In template:\n * // <button [disabled]=\"!undoRedo.canUndo()\">Undo</button>\n *\n * // In computed:\n * readonly undoAvailable = computed(() => this.undoRedo.canUndo());\n * ```\n */\n canUndo: Signal<boolean>;\n\n /**\n * Reactive signal indicating whether redo is available.\n * Updates automatically when edits are made, undone, redone, or history is cleared.\n *\n * @example\n * ```typescript\n * // In template:\n * // <button [disabled]=\"!undoRedo.canRedo()\">Redo</button>\n *\n * // In computed:\n * readonly redoAvailable = computed(() => this.undoRedo.canRedo());\n * ```\n */\n canRedo: Signal<boolean>;\n\n /**\n * Clear all undo/redo history.\n */\n clearHistory: () => void;\n\n /**\n * Get a copy of the current undo stack.\n */\n getUndoStack: () => UndoRedoAction[];\n\n /**\n * Get a copy of the current redo stack.\n */\n getRedoStack: () => UndoRedoAction[];\n\n /**\n * Manually record an edit action.\n * If a transaction is active, the action is buffered; otherwise it's pushed to the undo stack.\n */\n recordEdit: (rowIndex: number, field: string, oldValue: unknown, newValue: unknown) => void;\n\n /**\n * Begin a transaction. All edits recorded until `endTransaction()` are grouped\n * into a single compound action for undo/redo.\n * @throws If a transaction is already active\n */\n beginTransaction: () => void;\n\n /**\n * End the active transaction and push the compound action to the undo stack.\n * If only one edit was recorded, it's pushed as a plain EditAction.\n * If no edits were recorded, the transaction is discarded.\n * @throws If no transaction is active\n */\n endTransaction: () => void;\n\n /**\n * Signal indicating if grid is ready.\n */\n isReady: Signal<boolean>;\n}\n\n/**\n * Angular inject function for programmatic undo/redo control.\n *\n * Uses **lazy grid discovery** - the grid element is found when methods are called,\n * not during initialization.\n *\n * @example\n * ```typescript\n * import { Component } from '@angular/core';\n * import { Grid } from '@toolbox-web/grid-angular';\n * import '@toolbox-web/grid-angular/features/editing';\n * import '@toolbox-web/grid-angular/features/undo-redo';\n * import { injectGridUndoRedo } from '@toolbox-web/grid-angular/features/undo-redo';\n *\n * @Component({\n * selector: 'app-my-grid',\n * imports: [Grid],\n * template: `\n * <button (click)=\"undoRedo.undo()\" [disabled]=\"!undoRedo.canUndo()\">Undo</button>\n * <button (click)=\"undoRedo.redo()\" [disabled]=\"!undoRedo.canRedo()\">Redo</button>\n * <tbw-grid [rows]=\"rows\" [editing]=\"'dblclick'\" [undoRedo]=\"true\"></tbw-grid>\n * `\n * })\n * export class MyGridComponent {\n * undoRedo = injectGridUndoRedo();\n * }\n * ```\n */\nexport function injectGridUndoRedo(): UndoRedoMethods {\n const elementRef = inject(ElementRef);\n const destroyRef = inject(DestroyRef);\n const isReady = signal(false);\n\n // Reactive undo/redo availability signals\n const canUndoSignal = signal(false);\n const canRedoSignal = signal(false);\n\n let cachedGrid: DataGridElement | null = null;\n let readyPromiseStarted = false;\n let listenerAttached = false;\n\n /**\n * Sync canUndo/canRedo signals with the current plugin state.\n */\n const syncSignals = (): void => {\n const plugin = getPlugin();\n if (plugin) {\n canUndoSignal.set(plugin.canUndo());\n canRedoSignal.set(plugin.canRedo());\n }\n };\n\n /**\n * Attach event listeners to the grid for undo/redo state changes.\n * Listens for `undo`, `redo`, and `cell-commit` DOM events.\n */\n const attachListeners = (grid: DataGridElement): void => {\n if (listenerAttached) return;\n listenerAttached = true;\n\n const unsubs = [grid.on('undo', syncSignals), grid.on('redo', syncSignals), grid.on('cell-commit', syncSignals)];\n\n destroyRef.onDestroy(() => {\n unsubs.forEach((fn) => fn());\n });\n };\n\n const getGrid = (): DataGridElement | null => {\n if (cachedGrid) return cachedGrid;\n\n const grid = elementRef.nativeElement.querySelector('tbw-grid') as DataGridElement | null;\n if (grid) {\n cachedGrid = grid;\n attachListeners(grid);\n if (!readyPromiseStarted) {\n readyPromiseStarted = true;\n grid.ready?.().then(() => isReady.set(true));\n }\n }\n return grid;\n };\n\n const getPlugin = (): UndoRedoPlugin | undefined => {\n return getGrid()?.getPluginByName('undoRedo');\n };\n\n // Eagerly discover the grid after the first render so event listeners\n // are attached and isReady updates without requiring a programmatic\n // method call. Falls back to MutationObserver for lazy-rendered content.\n afterNextRender(() => {\n const grid = getGrid();\n if (grid) {\n grid.ready?.().then(syncSignals);\n return;\n }\n\n const host = elementRef.nativeElement as HTMLElement;\n const observer = new MutationObserver(() => {\n const discovered = getGrid();\n if (discovered) {\n observer.disconnect();\n discovered.ready?.().then(syncSignals);\n }\n });\n observer.observe(host, { childList: true, subtree: true });\n\n destroyRef.onDestroy(() => observer.disconnect());\n });\n\n return {\n isReady: isReady.asReadonly(),\n canUndo: canUndoSignal.asReadonly(),\n canRedo: canRedoSignal.asReadonly(),\n\n undo: () => {\n const plugin = getPlugin();\n if (!plugin) {\n console.warn(\n `[tbw-grid:undoRedo] UndoRedoPlugin not found.\\n\\n` +\n ` → Enable undo/redo on the grid:\\n` +\n ` <tbw-grid [editing]=\"'dblclick'\" [undoRedo]=\"true\" />`,\n );\n return null;\n }\n const result = plugin.undo();\n syncSignals();\n return result;\n },\n\n redo: () => {\n const plugin = getPlugin();\n if (!plugin) {\n console.warn(\n `[tbw-grid:undoRedo] UndoRedoPlugin not found.\\n\\n` +\n ` → Enable undo/redo on the grid:\\n` +\n ` <tbw-grid [editing]=\"'dblclick'\" [undoRedo]=\"true\" />`,\n );\n return null;\n }\n const result = plugin.redo();\n syncSignals();\n return result;\n },\n\n clearHistory: () => {\n const plugin = getPlugin();\n if (!plugin) {\n console.warn(\n `[tbw-grid:undoRedo] UndoRedoPlugin not found.\\n\\n` +\n ` → Enable undo/redo on the grid:\\n` +\n ` <tbw-grid [editing]=\"'dblclick'\" [undoRedo]=\"true\" />`,\n );\n return;\n }\n plugin.clearHistory();\n syncSignals();\n },\n\n getUndoStack: () => getPlugin()?.getUndoStack() ?? [],\n\n getRedoStack: () => getPlugin()?.getRedoStack() ?? [],\n\n recordEdit: (rowIndex: number, field: string, oldValue: unknown, newValue: unknown) => {\n const plugin = getPlugin();\n if (!plugin) {\n console.warn(\n `[tbw-grid:undoRedo] UndoRedoPlugin not found.\\n\\n` +\n ` → Enable undo/redo on the grid:\\n` +\n ` <tbw-grid [editing]=\"'dblclick'\" [undoRedo]=\"true\" />`,\n );\n return;\n }\n plugin.recordEdit(rowIndex, field, oldValue, newValue);\n syncSignals();\n },\n\n beginTransaction: () => {\n const plugin = getPlugin();\n if (!plugin) {\n console.warn(\n `[tbw-grid:undoRedo] UndoRedoPlugin not found.\\n\\n` +\n ` → Enable undo/redo on the grid:\\n` +\n ` <tbw-grid [editing]=\"'dblclick'\" [undoRedo]=\"true\" />`,\n );\n return;\n }\n plugin.beginTransaction();\n },\n\n endTransaction: () => {\n const plugin = getPlugin();\n if (!plugin) {\n console.warn(\n `[tbw-grid:undoRedo] UndoRedoPlugin not found.\\n\\n` +\n ` → Enable undo/redo on the grid:\\n` +\n ` <tbw-grid [editing]=\"'dblclick'\" [undoRedo]=\"true\" />`,\n );\n return;\n }\n plugin.endTransaction();\n syncSignals();\n },\n };\n}\n","/**\n * Generated bundle index. Do not edit.\n */\n\nexport * from './index';\n"],"names":[],"mappings":"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"}
|