slickgrid-react 5.7.1 → 5.9.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +8 -0
- package/dist/cjs/components/slickgrid-react.js +53 -30
- package/dist/cjs/components/slickgrid-react.js.map +1 -1
- package/dist/cjs/extensions/slickRowDetailView.js +316 -0
- package/dist/cjs/extensions/slickRowDetailView.js.map +1 -0
- package/dist/cjs/global-grid-options.js +9 -0
- package/dist/cjs/global-grid-options.js.map +1 -1
- package/dist/cjs/index.js +3 -2
- package/dist/cjs/index.js.map +1 -1
- package/dist/cjs/models/index.js +0 -17
- package/dist/cjs/models/index.js.map +1 -1
- package/dist/cjs/models/rowDetailView.interface.js +3 -0
- package/dist/cjs/models/rowDetailView.interface.js.map +1 -0
- package/dist/cjs/models/viewModelBindableData.interface.js +3 -0
- package/dist/cjs/models/viewModelBindableData.interface.js.map +1 -0
- package/dist/cjs/models/viewModelBindableInputData.interface.js +3 -0
- package/dist/cjs/models/viewModelBindableInputData.interface.js.map +1 -0
- package/dist/cjs/services/index.js +0 -1
- package/dist/cjs/services/index.js.map +1 -1
- package/dist/cjs/services/reactUtils.js +20 -0
- package/dist/cjs/services/reactUtils.js.map +1 -0
- package/dist/esm/components/slickgrid-react.js +53 -30
- package/dist/esm/components/slickgrid-react.js.map +1 -1
- package/dist/esm/extensions/slickRowDetailView.js +312 -0
- package/dist/esm/extensions/slickRowDetailView.js.map +1 -0
- package/dist/esm/global-grid-options.js +9 -0
- package/dist/esm/global-grid-options.js.map +1 -1
- package/dist/esm/index.js +3 -2
- package/dist/esm/index.js.map +1 -1
- package/dist/esm/models/index.js +1 -3
- package/dist/esm/models/index.js.map +1 -1
- package/dist/esm/models/rowDetailView.interface.js +2 -0
- package/dist/esm/models/rowDetailView.interface.js.map +1 -0
- package/dist/esm/models/viewModelBindableData.interface.js +2 -0
- package/dist/esm/models/viewModelBindableData.interface.js.map +1 -0
- package/dist/esm/models/viewModelBindableInputData.interface.js +2 -0
- package/dist/esm/models/viewModelBindableInputData.interface.js.map +1 -0
- package/dist/esm/services/index.js +0 -1
- package/dist/esm/services/index.js.map +1 -1
- package/dist/esm/services/reactUtils.js +14 -0
- package/dist/esm/services/reactUtils.js.map +1 -0
- package/dist/types/components/slickgrid-react.d.ts +14 -14
- package/dist/types/components/slickgrid-react.d.ts.map +1 -1
- package/dist/types/components/slickgridReactProps.d.ts +0 -2
- package/dist/types/components/slickgridReactProps.d.ts.map +1 -1
- package/dist/types/extensions/slickRowDetailView.d.ts +82 -0
- package/dist/types/extensions/slickRowDetailView.d.ts.map +1 -0
- package/dist/types/global-grid-options.d.ts.map +1 -1
- package/dist/types/index.d.ts +4 -3
- package/dist/types/index.d.ts.map +1 -1
- package/dist/types/models/gridOption.interface.d.ts +3 -0
- package/dist/types/models/gridOption.interface.d.ts.map +1 -1
- package/dist/types/models/index.d.ts +6 -3
- package/dist/types/models/index.d.ts.map +1 -1
- package/dist/types/models/rowDetailView.interface.d.ts +13 -0
- package/dist/types/models/rowDetailView.interface.d.ts.map +1 -0
- package/dist/types/models/slickgridReactInstance.interface.d.ts +4 -2
- package/dist/types/models/slickgridReactInstance.interface.d.ts.map +1 -1
- package/dist/types/models/viewModelBindableData.interface.d.ts +10 -0
- package/dist/types/models/viewModelBindableData.interface.d.ts.map +1 -0
- package/dist/types/models/viewModelBindableInputData.interface.d.ts +9 -0
- package/dist/types/models/viewModelBindableInputData.interface.d.ts.map +1 -0
- package/dist/types/services/index.d.ts +0 -1
- package/dist/types/services/index.d.ts.map +1 -1
- package/dist/types/services/reactUtils.d.ts +6 -0
- package/dist/types/services/reactUtils.d.ts.map +1 -0
- package/package.json +52 -72
- package/src/slickgrid-react/components/slickgrid-react.tsx +67 -42
- package/src/slickgrid-react/components/slickgridReactProps.ts +0 -2
- package/src/slickgrid-react/extensions/slickRowDetailView.ts +383 -0
- package/src/slickgrid-react/global-grid-options.ts +10 -1
- package/src/slickgrid-react/index.ts +5 -2
- package/src/slickgrid-react/models/gridOption.interface.ts +5 -0
- package/src/slickgrid-react/models/index.ts +6 -3
- package/src/slickgrid-react/models/rowDetailView.interface.ts +15 -0
- package/src/slickgrid-react/models/slickgridReactInstance.interface.ts +5 -2
- package/src/slickgrid-react/models/viewModelBindableData.interface.ts +10 -0
- package/src/slickgrid-react/models/viewModelBindableInputData.interface.ts +9 -0
- package/src/slickgrid-react/services/index.ts +0 -1
- package/src/slickgrid-react/services/reactUtils.ts +15 -0
- package/dist/cjs/services/reactUtil.service.js +0 -30
- package/dist/cjs/services/reactUtil.service.js.map +0 -1
- package/dist/esm/services/reactUtil.service.js +0 -23
- package/dist/esm/services/reactUtil.service.js.map +0 -1
- package/dist/types/services/reactUtil.service.d.ts +0 -6
- package/dist/types/services/reactUtil.service.d.ts.map +0 -1
- package/src/slickgrid-react/services/reactUtil.service.ts +0 -26
|
@@ -0,0 +1,383 @@
|
|
|
1
|
+
import {
|
|
2
|
+
addToArrayWhenNotExists,
|
|
3
|
+
type EventSubscription,
|
|
4
|
+
type OnBeforeRowDetailToggleArgs,
|
|
5
|
+
type OnRowBackToViewportRangeArgs,
|
|
6
|
+
SlickEventData,
|
|
7
|
+
type SlickEventHandler,
|
|
8
|
+
type SlickGrid,
|
|
9
|
+
SlickRowSelectionModel,
|
|
10
|
+
unsubscribeAll,
|
|
11
|
+
} from '@slickgrid-universal/common';
|
|
12
|
+
import { type EventPubSubService } from '@slickgrid-universal/event-pub-sub';
|
|
13
|
+
import { SlickRowDetailView as UniversalSlickRowDetailView } from '@slickgrid-universal/row-detail-view-plugin';
|
|
14
|
+
import type { Root } from 'react-dom/client';
|
|
15
|
+
|
|
16
|
+
import type { GridOption, RowDetailView, ViewModelBindableInputData } from '../models/index';
|
|
17
|
+
import { loadReactComponentDynamically } from '../services/reactUtils';
|
|
18
|
+
|
|
19
|
+
const ROW_DETAIL_CONTAINER_PREFIX = 'container_';
|
|
20
|
+
const PRELOAD_CONTAINER_PREFIX = 'container_loading';
|
|
21
|
+
|
|
22
|
+
export interface CreatedView {
|
|
23
|
+
id: string | number;
|
|
24
|
+
dataContext: any;
|
|
25
|
+
root: Root | null;
|
|
26
|
+
}
|
|
27
|
+
// interface SRDV extends React.Component<Props, State>, UniversalSlickRowDetailView {}s
|
|
28
|
+
|
|
29
|
+
export class SlickRowDetailView extends UniversalSlickRowDetailView {
|
|
30
|
+
protected _component?: any;
|
|
31
|
+
protected _preloadComponent?: any;
|
|
32
|
+
protected _views: CreatedView[] = [];
|
|
33
|
+
protected _subscriptions: EventSubscription[] = [];
|
|
34
|
+
protected _userProcessFn?: (item: any) => Promise<any>;
|
|
35
|
+
protected gridContainerElement!: HTMLElement;
|
|
36
|
+
_root?: Root;
|
|
37
|
+
|
|
38
|
+
constructor(
|
|
39
|
+
private readonly eventPubSubService: EventPubSubService,
|
|
40
|
+
) {
|
|
41
|
+
super(eventPubSubService);
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
get addonOptions() {
|
|
45
|
+
return this.getOptions();
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
protected get datasetIdPropName(): string {
|
|
49
|
+
return this.gridOptions.datasetIdPropertyName || 'id';
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
get eventHandler(): SlickEventHandler {
|
|
53
|
+
return this._eventHandler;
|
|
54
|
+
}
|
|
55
|
+
set eventHandler(eventHandler: SlickEventHandler) {
|
|
56
|
+
this._eventHandler = eventHandler;
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
get gridOptions(): GridOption {
|
|
60
|
+
return (this._grid?.getOptions() || {}) as GridOption;
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
get rowDetailViewOptions(): RowDetailView | undefined {
|
|
64
|
+
return this.gridOptions.rowDetailView;
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
/** Dispose of the RowDetailView Extension */
|
|
68
|
+
dispose() {
|
|
69
|
+
this.disposeAllViewComponents();
|
|
70
|
+
unsubscribeAll(this._subscriptions);
|
|
71
|
+
super.dispose();
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
/** Dispose of all the opened Row Detail Panels Components */
|
|
75
|
+
disposeAllViewComponents() {
|
|
76
|
+
if (Array.isArray(this._views)) {
|
|
77
|
+
this._views.forEach((view) => this.disposeViewComponent(view));
|
|
78
|
+
}
|
|
79
|
+
this._views = [];
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
/** Get the instance of the SlickGrid addon (control or plugin). */
|
|
83
|
+
getAddonInstance(): SlickRowDetailView | null {
|
|
84
|
+
return this;
|
|
85
|
+
}
|
|
86
|
+
|
|
87
|
+
init(grid: SlickGrid) {
|
|
88
|
+
this._grid = grid;
|
|
89
|
+
super.init(this._grid);
|
|
90
|
+
this.gridContainerElement = grid.getContainerNode();
|
|
91
|
+
this.register(grid?.getSelectionModel() as SlickRowSelectionModel);
|
|
92
|
+
}
|
|
93
|
+
|
|
94
|
+
/**
|
|
95
|
+
* Create the plugin before the Grid creation, else it will behave oddly.
|
|
96
|
+
* Mostly because the column definitions might change after the grid creation
|
|
97
|
+
*/
|
|
98
|
+
register(rowSelectionPlugin?: SlickRowSelectionModel) {
|
|
99
|
+
if (typeof this.gridOptions.rowDetailView?.process === 'function') {
|
|
100
|
+
// we need to keep the user "process" method and replace it with our own execution method
|
|
101
|
+
// we do this because when we get the item detail, we need to call "onAsyncResponse.notify" for the plugin to work
|
|
102
|
+
this._userProcessFn = this.gridOptions.rowDetailView.process as (item: any) => Promise<any>; // keep user's process method
|
|
103
|
+
this.addonOptions.process = (item) => this.onProcessing(item); // replace process method & run our internal one
|
|
104
|
+
} else {
|
|
105
|
+
throw new Error('[Slickgrid-React] You need to provide a "process" function for the Row Detail Extension to work properly');
|
|
106
|
+
}
|
|
107
|
+
|
|
108
|
+
if (this._grid && this.gridOptions?.rowDetailView) {
|
|
109
|
+
// load the Preload & RowDetail Templates (could be straight HTML or React Components)
|
|
110
|
+
// when those are React Components, we need to create View Component & provide the html containers to the Plugin (preTemplate/postTemplate methods)
|
|
111
|
+
if (!this.gridOptions.rowDetailView.preTemplate) {
|
|
112
|
+
this._preloadComponent = this.gridOptions?.rowDetailView?.preloadComponent;
|
|
113
|
+
this.addonOptions.preTemplate = () => this._grid.sanitizeHtmlString(`<div class="${PRELOAD_CONTAINER_PREFIX}"></div>`) as string;
|
|
114
|
+
}
|
|
115
|
+
if (!this.gridOptions.rowDetailView.postTemplate) {
|
|
116
|
+
this._component = this.gridOptions?.rowDetailView?.viewComponent;
|
|
117
|
+
this.addonOptions.postTemplate = (itemDetail: any) => {
|
|
118
|
+
return this._grid.sanitizeHtmlString(`<div class="${ROW_DETAIL_CONTAINER_PREFIX}${itemDetail[this.datasetIdPropName]}"></div>`) as string
|
|
119
|
+
};
|
|
120
|
+
}
|
|
121
|
+
|
|
122
|
+
if (this._grid && this.gridOptions) {
|
|
123
|
+
// this also requires the Row Selection Model to be registered as well
|
|
124
|
+
if (!rowSelectionPlugin || !this._grid.getSelectionModel()) {
|
|
125
|
+
rowSelectionPlugin = new SlickRowSelectionModel(this.gridOptions.rowSelectionOptions || { selectActiveRow: true });
|
|
126
|
+
this._grid.setSelectionModel(rowSelectionPlugin);
|
|
127
|
+
}
|
|
128
|
+
|
|
129
|
+
// hook all events
|
|
130
|
+
if (this._grid && this.rowDetailViewOptions) {
|
|
131
|
+
if (this.rowDetailViewOptions.onExtensionRegistered) {
|
|
132
|
+
this.rowDetailViewOptions.onExtensionRegistered(this);
|
|
133
|
+
}
|
|
134
|
+
|
|
135
|
+
if (this.onAsyncResponse) {
|
|
136
|
+
this._eventHandler.subscribe(this.onAsyncResponse, (event, args) => {
|
|
137
|
+
if (typeof this.rowDetailViewOptions?.onAsyncResponse === 'function') {
|
|
138
|
+
this.rowDetailViewOptions.onAsyncResponse(event, args);
|
|
139
|
+
}
|
|
140
|
+
});
|
|
141
|
+
}
|
|
142
|
+
|
|
143
|
+
if (this.onAsyncEndUpdate) {
|
|
144
|
+
this._eventHandler.subscribe(this.onAsyncEndUpdate, async (event, args) => {
|
|
145
|
+
// triggers after backend called "onAsyncResponse.notify()"
|
|
146
|
+
await this.renderViewModel(args?.item);
|
|
147
|
+
|
|
148
|
+
if (typeof this.rowDetailViewOptions?.onAsyncEndUpdate === 'function') {
|
|
149
|
+
this.rowDetailViewOptions.onAsyncEndUpdate(event, args);
|
|
150
|
+
}
|
|
151
|
+
});
|
|
152
|
+
}
|
|
153
|
+
|
|
154
|
+
if (this.onAfterRowDetailToggle) {
|
|
155
|
+
this._eventHandler.subscribe(this.onAfterRowDetailToggle, async (event, args) => {
|
|
156
|
+
// display preload template & re-render all the other Detail Views after toggling
|
|
157
|
+
// the preload View will eventually go away once the data gets loaded after the "onAsyncEndUpdate" event
|
|
158
|
+
await this.renderPreloadView(args.item);
|
|
159
|
+
this.renderAllViewModels();
|
|
160
|
+
|
|
161
|
+
if (typeof this.rowDetailViewOptions?.onAfterRowDetailToggle === 'function') {
|
|
162
|
+
this.rowDetailViewOptions.onAfterRowDetailToggle(event, args);
|
|
163
|
+
}
|
|
164
|
+
});
|
|
165
|
+
}
|
|
166
|
+
|
|
167
|
+
if (this.onBeforeRowDetailToggle) {
|
|
168
|
+
this._eventHandler.subscribe(this.onBeforeRowDetailToggle, (event, args) => {
|
|
169
|
+
// before toggling row detail, we need to create View Component if it doesn't exist
|
|
170
|
+
this.handleOnBeforeRowDetailToggle(event, args);
|
|
171
|
+
|
|
172
|
+
if (typeof this.rowDetailViewOptions?.onBeforeRowDetailToggle === 'function') {
|
|
173
|
+
return this.rowDetailViewOptions.onBeforeRowDetailToggle(event, args);
|
|
174
|
+
}
|
|
175
|
+
return true;
|
|
176
|
+
});
|
|
177
|
+
}
|
|
178
|
+
|
|
179
|
+
if (this.onRowBackToViewportRange) {
|
|
180
|
+
this._eventHandler.subscribe(this.onRowBackToViewportRange, async (event, args) => {
|
|
181
|
+
// when row is back to viewport range, we will re-render the View Component(s)
|
|
182
|
+
await this.handleOnRowBackToViewportRange(event, args);
|
|
183
|
+
|
|
184
|
+
if (typeof this.rowDetailViewOptions?.onRowBackToViewportRange === 'function') {
|
|
185
|
+
this.rowDetailViewOptions.onRowBackToViewportRange(event, args);
|
|
186
|
+
}
|
|
187
|
+
});
|
|
188
|
+
}
|
|
189
|
+
|
|
190
|
+
if (this.onRowOutOfViewportRange) {
|
|
191
|
+
this._eventHandler.subscribe(this.onRowOutOfViewportRange, (event, args) => {
|
|
192
|
+
if (typeof this.rowDetailViewOptions?.onRowOutOfViewportRange === 'function') {
|
|
193
|
+
this.rowDetailViewOptions.onRowOutOfViewportRange(event, args);
|
|
194
|
+
}
|
|
195
|
+
});
|
|
196
|
+
}
|
|
197
|
+
|
|
198
|
+
// --
|
|
199
|
+
// hook some events needed by the Plugin itself
|
|
200
|
+
|
|
201
|
+
// we need to redraw the open detail views if we change column position (column reorder)
|
|
202
|
+
this.eventHandler.subscribe(this._grid.onColumnsReordered, this.redrawAllViewComponents.bind(this));
|
|
203
|
+
|
|
204
|
+
// on row selection changed, we also need to redraw
|
|
205
|
+
if (this.gridOptions.enableRowSelection || this.gridOptions.enableCheckboxSelector) {
|
|
206
|
+
this._eventHandler.subscribe(this._grid.onSelectedRowsChanged, this.redrawAllViewComponents.bind(this));
|
|
207
|
+
}
|
|
208
|
+
|
|
209
|
+
// on column sort/reorder, all row detail are collapsed so we can dispose of all the Views as well
|
|
210
|
+
this._eventHandler.subscribe(this._grid.onSort, this.disposeAllViewComponents.bind(this));
|
|
211
|
+
|
|
212
|
+
// on filter changed, we need to re-render all Views
|
|
213
|
+
this._subscriptions.push(
|
|
214
|
+
this.eventPubSubService?.subscribe(['onFilterChanged', 'onGridMenuColumnsChanged', 'onColumnPickerColumnsChanged'], this.redrawAllViewComponents.bind(this)),
|
|
215
|
+
this.eventPubSubService?.subscribe(['onGridMenuClearAllFilters', 'onGridMenuClearAllSorting'], () => window.setTimeout(() => this.redrawAllViewComponents())),
|
|
216
|
+
);
|
|
217
|
+
}
|
|
218
|
+
}
|
|
219
|
+
}
|
|
220
|
+
|
|
221
|
+
return this;
|
|
222
|
+
}
|
|
223
|
+
|
|
224
|
+
/** Redraw (re-render) all the expanded row detail View Components */
|
|
225
|
+
async redrawAllViewComponents() {
|
|
226
|
+
await Promise.all(this._views.map(async x => this.redrawViewComponent(x)));
|
|
227
|
+
}
|
|
228
|
+
|
|
229
|
+
/** Render all the expanded row detail View Components */
|
|
230
|
+
async renderAllViewModels() {
|
|
231
|
+
await Promise.all(this._views.filter(x => x?.dataContext).map(async x => this.renderViewModel(x.dataContext)));
|
|
232
|
+
}
|
|
233
|
+
|
|
234
|
+
/** Redraw the necessary View Component */
|
|
235
|
+
async redrawViewComponent(view: CreatedView) {
|
|
236
|
+
const containerElement = this.gridContainerElement.getElementsByClassName(`${ROW_DETAIL_CONTAINER_PREFIX}${view.id}`);
|
|
237
|
+
if (containerElement?.length >= 0) {
|
|
238
|
+
await this.renderViewModel(view.dataContext);
|
|
239
|
+
}
|
|
240
|
+
}
|
|
241
|
+
|
|
242
|
+
/** Render (or re-render) the View Component (Row Detail) */
|
|
243
|
+
async renderPreloadView(item: any) {
|
|
244
|
+
const containerElements = this.gridContainerElement.getElementsByClassName(`${PRELOAD_CONTAINER_PREFIX}`);
|
|
245
|
+
if (this._preloadComponent && containerElements?.length) {
|
|
246
|
+
const detailContainer = document.createElement('section');
|
|
247
|
+
containerElements[containerElements.length - 1]!.appendChild(detailContainer);
|
|
248
|
+
|
|
249
|
+
console.log('elm', containerElements[containerElements.length - 1])
|
|
250
|
+
const { root } = await loadReactComponentDynamically(this._preloadComponent, detailContainer as HTMLElement);
|
|
251
|
+
const viewObj = this._views.find(obj => obj.id === item[this.datasetIdPropName]);
|
|
252
|
+
this._root = root;
|
|
253
|
+
if (viewObj) {
|
|
254
|
+
viewObj.root = root;
|
|
255
|
+
}
|
|
256
|
+
}
|
|
257
|
+
}
|
|
258
|
+
|
|
259
|
+
/** Render (or re-render) the View Component (Row Detail) */
|
|
260
|
+
async renderViewModel(item: any) {
|
|
261
|
+
const containerElements = this.gridContainerElement.getElementsByClassName(`${ROW_DETAIL_CONTAINER_PREFIX}${item[this.datasetIdPropName]}`);
|
|
262
|
+
if (this._component && containerElements?.length) {
|
|
263
|
+
const bindableData = {
|
|
264
|
+
model: item,
|
|
265
|
+
addon: this,
|
|
266
|
+
grid: this._grid,
|
|
267
|
+
dataView: this.dataView,
|
|
268
|
+
parent: this.rowDetailViewOptions?.parent,
|
|
269
|
+
} as ViewModelBindableInputData;
|
|
270
|
+
const viewObj = this._views.find(obj => obj.id === item[this.datasetIdPropName]);
|
|
271
|
+
|
|
272
|
+
// load our Row Detail React Component dynamically, typically we would want to use `root.render()` after the preload component (last argument below)
|
|
273
|
+
// BUT the root render doesn't seem to work and shows a blank element, so we'll use `createRoot()` every time even though it shows a console log in Dev
|
|
274
|
+
// that is the only way I got it working so let's use it anyway and console warnings are removed in production anyway
|
|
275
|
+
const { root } = await loadReactComponentDynamically(this._component, containerElements[containerElements.length - 1] as HTMLElement, bindableData /*, viewObj?.root */);
|
|
276
|
+
if (!viewObj) {
|
|
277
|
+
this.addViewInfoToViewsRef(item, root);
|
|
278
|
+
}
|
|
279
|
+
}
|
|
280
|
+
}
|
|
281
|
+
|
|
282
|
+
// --
|
|
283
|
+
// protected functions
|
|
284
|
+
// ------------------
|
|
285
|
+
|
|
286
|
+
protected addViewInfoToViewsRef(item: any, root: Root | null) {
|
|
287
|
+
const viewInfo: CreatedView = {
|
|
288
|
+
id: item[this.datasetIdPropName],
|
|
289
|
+
dataContext: item,
|
|
290
|
+
root
|
|
291
|
+
};
|
|
292
|
+
const idPropName = this.gridOptions.datasetIdPropertyName || 'id';
|
|
293
|
+
addToArrayWhenNotExists(this._views, viewInfo, idPropName);
|
|
294
|
+
}
|
|
295
|
+
|
|
296
|
+
protected disposeViewComponent(expandedView: CreatedView): CreatedView | void {
|
|
297
|
+
if (expandedView) {
|
|
298
|
+
if (expandedView?.root) {
|
|
299
|
+
const container = this.gridContainerElement.getElementsByClassName(`${ROW_DETAIL_CONTAINER_PREFIX}${this._views[0].id}`);
|
|
300
|
+
if (container?.length) {
|
|
301
|
+
expandedView.root.unmount();
|
|
302
|
+
container[0].textContent = '';
|
|
303
|
+
return expandedView;
|
|
304
|
+
}
|
|
305
|
+
}
|
|
306
|
+
}
|
|
307
|
+
}
|
|
308
|
+
|
|
309
|
+
/**
|
|
310
|
+
* Just before the row get expanded or collapsed we will do the following
|
|
311
|
+
* First determine if the row is expanding or collapsing,
|
|
312
|
+
* if it's expanding we will add it to our View Components reference array if we don't already have it
|
|
313
|
+
* or if it's collapsing we will remove it from our View Components reference array
|
|
314
|
+
*/
|
|
315
|
+
protected handleOnBeforeRowDetailToggle(_e: SlickEventData<OnBeforeRowDetailToggleArgs>, args: { grid: SlickGrid; item: any; }) {
|
|
316
|
+
// expanding
|
|
317
|
+
if (args?.item?.__collapsed) {
|
|
318
|
+
// expanding row detail
|
|
319
|
+
this.addViewInfoToViewsRef(args.item, null);
|
|
320
|
+
} else {
|
|
321
|
+
// collapsing, so dispose of the View
|
|
322
|
+
const foundViewIdx = this._views.findIndex((view: CreatedView) => view.id === args.item[this.datasetIdPropName]);
|
|
323
|
+
if (foundViewIdx >= 0 && this.disposeViewComponent(this._views[foundViewIdx])) {
|
|
324
|
+
this._views.splice(foundViewIdx, 1);
|
|
325
|
+
}
|
|
326
|
+
}
|
|
327
|
+
}
|
|
328
|
+
|
|
329
|
+
/** When Row comes back to Viewport Range, we need to redraw the View */
|
|
330
|
+
protected async handleOnRowBackToViewportRange(_e: SlickEventData<OnRowBackToViewportRangeArgs>, args: {
|
|
331
|
+
item: any;
|
|
332
|
+
rowId: string | number;
|
|
333
|
+
rowIndex: number;
|
|
334
|
+
expandedRows: (string | number)[];
|
|
335
|
+
rowIdsOutOfViewport: (string | number)[];
|
|
336
|
+
grid: SlickGrid;
|
|
337
|
+
}) {
|
|
338
|
+
if (args?.item) {
|
|
339
|
+
await this.redrawAllViewComponents();
|
|
340
|
+
}
|
|
341
|
+
}
|
|
342
|
+
|
|
343
|
+
/**
|
|
344
|
+
* notify the onAsyncResponse with the "args.item" (required property)
|
|
345
|
+
* the plugin will then use item to populate the row detail panel with the "postTemplate"
|
|
346
|
+
* @param item
|
|
347
|
+
*/
|
|
348
|
+
protected notifyTemplate(item: any) {
|
|
349
|
+
if (this.onAsyncResponse) {
|
|
350
|
+
this.onAsyncResponse.notify({ item, itemDetail: item }, new SlickEventData(), this);
|
|
351
|
+
}
|
|
352
|
+
}
|
|
353
|
+
|
|
354
|
+
/**
|
|
355
|
+
* On Processing, we will notify the plugin with the new item detail once backend server call completes
|
|
356
|
+
* @param item
|
|
357
|
+
*/
|
|
358
|
+
protected async onProcessing(item: any) {
|
|
359
|
+
if (item && typeof this._userProcessFn === 'function') {
|
|
360
|
+
let awaitedItemDetail: any;
|
|
361
|
+
const userProcessFn = this._userProcessFn(item);
|
|
362
|
+
|
|
363
|
+
// wait for the "userProcessFn", once resolved we will save it into the "collection"
|
|
364
|
+
const response: any | any[] = await userProcessFn;
|
|
365
|
+
|
|
366
|
+
if (response.hasOwnProperty(this.datasetIdPropName)) {
|
|
367
|
+
awaitedItemDetail = response; // from Promise
|
|
368
|
+
} else if (response instanceof Response && typeof response['json'] === 'function') {
|
|
369
|
+
awaitedItemDetail = await response['json'](); // from Fetch
|
|
370
|
+
} else if (response && response['content']) {
|
|
371
|
+
awaitedItemDetail = response['content']; // from http-client
|
|
372
|
+
}
|
|
373
|
+
|
|
374
|
+
if (!awaitedItemDetail || !awaitedItemDetail.hasOwnProperty(this.datasetIdPropName)) {
|
|
375
|
+
throw new Error('[Slickgrid-React] could not process the Row Detail, please make sure that your "process" callback ' +
|
|
376
|
+
'(a Promise or an HttpClient call returning an Observable) returns an item object that has an "${this.datasetIdPropName}" property');
|
|
377
|
+
}
|
|
378
|
+
|
|
379
|
+
// notify the plugin with the new item details
|
|
380
|
+
this.notifyTemplate(awaitedItemDetail || {});
|
|
381
|
+
}
|
|
382
|
+
}
|
|
383
|
+
}
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { type Column, DelimiterType, EventNamingStyle, FileType, Filters, OperatorType, type TreeDataOption } from '@slickgrid-universal/common';
|
|
2
|
-
import type { GridOption } from './models/index';
|
|
2
|
+
import type { GridOption, RowDetailView } from './models/index';
|
|
3
3
|
|
|
4
4
|
/**
|
|
5
5
|
* Default Options that can be passed to the Slickgrid-React
|
|
@@ -227,6 +227,15 @@ export const GlobalGridOptions: Partial<GridOption> = {
|
|
|
227
227
|
pageSize: 25,
|
|
228
228
|
totalItems: 0
|
|
229
229
|
},
|
|
230
|
+
rowDetailView: {
|
|
231
|
+
collapseAllOnSort: true,
|
|
232
|
+
cssClass: 'detail-view-toggle',
|
|
233
|
+
panelRows: 1,
|
|
234
|
+
keyPrefix: '__',
|
|
235
|
+
useRowClick: false,
|
|
236
|
+
useSimpleViewportCalc: true,
|
|
237
|
+
saveDetailViewOnScroll: false,
|
|
238
|
+
} as RowDetailView,
|
|
230
239
|
headerRowHeight: 35,
|
|
231
240
|
rowHeight: 35,
|
|
232
241
|
topPanelHeight: 30,
|
|
@@ -2,18 +2,19 @@ import 'regenerator-runtime/runtime.js';
|
|
|
2
2
|
export * from '@slickgrid-universal/common';
|
|
3
3
|
|
|
4
4
|
import { SlickgridReact } from './components/slickgrid-react';
|
|
5
|
+
import { SlickRowDetailView } from './extensions/slickRowDetailView';
|
|
5
6
|
import type { SlickgridEventAggregator } from './components/slickgridEventAggregator';
|
|
6
7
|
import type { SlickgridConfig } from './slickgrid-config';
|
|
7
8
|
|
|
8
9
|
import type {
|
|
9
10
|
SlickgridReactInstance,
|
|
10
11
|
SlickgridReactComponentOutput,
|
|
12
|
+
RowDetailView,
|
|
11
13
|
GridOption,
|
|
12
14
|
} from './models/index';
|
|
13
15
|
|
|
14
16
|
// expose all public classes
|
|
15
17
|
export {
|
|
16
|
-
ReactUtilService,
|
|
17
18
|
TranslaterService,
|
|
18
19
|
disposeAllSubscriptions
|
|
19
20
|
} from './services/index';
|
|
@@ -23,6 +24,8 @@ export {
|
|
|
23
24
|
type SlickgridReactInstance,
|
|
24
25
|
type SlickgridReactComponentOutput,
|
|
25
26
|
type GridOption,
|
|
27
|
+
type RowDetailView,
|
|
26
28
|
SlickgridReact,
|
|
27
|
-
SlickgridConfig
|
|
29
|
+
SlickgridConfig,
|
|
30
|
+
SlickRowDetailView,
|
|
28
31
|
};
|
|
@@ -1,7 +1,12 @@
|
|
|
1
1
|
import type { GridOption as UniversalGridOption } from '@slickgrid-universal/common';
|
|
2
2
|
import type * as i18next from 'i18next';
|
|
3
3
|
|
|
4
|
+
import type { RowDetailView } from './rowDetailView.interface';
|
|
5
|
+
|
|
4
6
|
export interface GridOption extends UniversalGridOption {
|
|
5
7
|
/** I18N translation service instance */
|
|
6
8
|
i18n?: i18next.i18n;
|
|
9
|
+
|
|
10
|
+
/** Row Detail View Plugin options & events (columnId, cssClass, toolTip, width) */
|
|
11
|
+
rowDetailView?: RowDetailView;
|
|
7
12
|
}
|
|
@@ -1,3 +1,6 @@
|
|
|
1
|
-
export * from './
|
|
2
|
-
export * from './reactComponentOutput.interface';
|
|
3
|
-
export * from './
|
|
1
|
+
export type * from './gridOption.interface';
|
|
2
|
+
export type * from './reactComponentOutput.interface';
|
|
3
|
+
export type * from './rowDetailView.interface';
|
|
4
|
+
export type * from './slickgridReactInstance.interface';
|
|
5
|
+
export type * from './viewModelBindableData.interface';
|
|
6
|
+
export type * from './viewModelBindableInputData.interface';
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
import type { RowDetailView as UniversalRowDetailView } from '@slickgrid-universal/common';
|
|
2
|
+
|
|
3
|
+
export interface RowDetailView extends UniversalRowDetailView {
|
|
4
|
+
/**
|
|
5
|
+
* Optionally pass your Parent Component reference to your Child Component (row detail component).
|
|
6
|
+
* note:: If anyone finds a better way of passing the parent to the row detail extension, please reach out and/or create a PR
|
|
7
|
+
*/
|
|
8
|
+
parent?: any;
|
|
9
|
+
|
|
10
|
+
/** View Model of the preload template which shows after opening row detail & before row detail data shows up */
|
|
11
|
+
preloadComponent?: any;
|
|
12
|
+
|
|
13
|
+
/** View Model template that will be loaded once the async function finishes */
|
|
14
|
+
viewComponent?: any;
|
|
15
|
+
}
|
|
@@ -5,7 +5,7 @@ import type {
|
|
|
5
5
|
GridEventService,
|
|
6
6
|
GridService,
|
|
7
7
|
GridStateService,
|
|
8
|
-
|
|
8
|
+
HeaderGroupingService,
|
|
9
9
|
PaginationService,
|
|
10
10
|
ResizerService,
|
|
11
11
|
SlickDataView,
|
|
@@ -53,8 +53,11 @@ export interface SlickgridReactInstance {
|
|
|
53
53
|
/** Grid State Service */
|
|
54
54
|
gridStateService: GridStateService;
|
|
55
55
|
|
|
56
|
+
/** @deprecated @use `headerGroupingService` */
|
|
57
|
+
groupingService: HeaderGroupingService;
|
|
58
|
+
|
|
56
59
|
/** Grouping (and colspan) Service */
|
|
57
|
-
|
|
60
|
+
headerGroupingService: HeaderGroupingService;
|
|
58
61
|
|
|
59
62
|
/** Pagination Service (allows you to programmatically go to first/last page, etc...) */
|
|
60
63
|
paginationService?: PaginationService;
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
import React from 'react';
|
|
2
|
+
import { createRef } from 'react';
|
|
3
|
+
import { createRoot, type Root } from 'react-dom/client';
|
|
4
|
+
|
|
5
|
+
export function loadReactComponentDynamically<T = any>(customComponent: any, targetElm: HTMLElement, props?: any, root?: Root | null): Promise<{ component: T, root: Root }> {
|
|
6
|
+
return new Promise(resolve => {
|
|
7
|
+
const compRef = createRef();
|
|
8
|
+
root ??= createRoot(targetElm);
|
|
9
|
+
root.render(React.createElement(customComponent, { ...props, ref: compRef }));
|
|
10
|
+
|
|
11
|
+
queueMicrotask(() => {
|
|
12
|
+
resolve({ component: compRef.current as T, root: root as Root });
|
|
13
|
+
});
|
|
14
|
+
});
|
|
15
|
+
}
|
|
@@ -1,30 +0,0 @@
|
|
|
1
|
-
"use strict";
|
|
2
|
-
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
3
|
-
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
4
|
-
};
|
|
5
|
-
Object.defineProperty(exports, "__esModule", { value: true });
|
|
6
|
-
exports.ReactUtilService = void 0;
|
|
7
|
-
const react_1 = __importDefault(require("react"));
|
|
8
|
-
const react_dom_1 = __importDefault(require("react-dom"));
|
|
9
|
-
class ReactUtilService {
|
|
10
|
-
createReactComponentAppendToDom(component, targetElement, clearTargetContent = false, props = undefined, children = []) {
|
|
11
|
-
const componentElement = react_1.default.createElement(component, props, children);
|
|
12
|
-
let componentInstance;
|
|
13
|
-
// Append DOM element to the HTML element specified
|
|
14
|
-
if (targetElement) {
|
|
15
|
-
if (clearTargetContent && targetElement.innerHTML) {
|
|
16
|
-
targetElement.innerHTML = '';
|
|
17
|
-
}
|
|
18
|
-
// @ts-ignore
|
|
19
|
-
componentInstance = react_dom_1.default.render(componentElement, targetElement);
|
|
20
|
-
}
|
|
21
|
-
else {
|
|
22
|
-
// @ts-ignore
|
|
23
|
-
componentInstance = react_dom_1.default.render(componentElement, document.body);
|
|
24
|
-
}
|
|
25
|
-
const domElement = react_dom_1.default.findDOMNode(componentInstance);
|
|
26
|
-
return { componentInstance, componentElement, domElement };
|
|
27
|
-
}
|
|
28
|
-
}
|
|
29
|
-
exports.ReactUtilService = ReactUtilService;
|
|
30
|
-
//# sourceMappingURL=reactUtil.service.js.map
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"reactUtil.service.js","sourceRoot":"","sources":["../../../src/slickgrid-react/services/reactUtil.service.ts"],"names":[],"mappings":";;;;;;AAAA,kDAA8C;AAC9C,0DAAiC;AAGjC,MAAa,gBAAgB;IAC3B,+BAA+B,CAAC,SAAc,EAAE,aAAqC,EAAE,kBAAkB,GAAG,KAAK,EAAE,QAAa,SAAS,EAAE,WAAwB,EAAE;QACnK,MAAM,gBAAgB,GAAG,eAAK,CAAC,aAAa,CAAC,SAAS,EAAE,KAAK,EAAE,QAAQ,CAAC,CAAC;QACzE,IAAI,iBAAsB,CAAC;QAE3B,mDAAmD;QACnD,IAAI,aAAa,EAAE,CAAC;YAClB,IAAI,kBAAkB,IAAI,aAAa,CAAC,SAAS,EAAE,CAAC;gBAClD,aAAa,CAAC,SAAS,GAAG,EAAE,CAAC;YAC/B,CAAC;YACD,aAAa;YACb,iBAAiB,GAAG,mBAAQ,CAAC,MAAM,CAAC,gBAAgB,EAAE,aAAa,CAAC,CAAC;QACvE,CAAC;aAAM,CAAC;YACN,aAAa;YACb,iBAAiB,GAAG,mBAAQ,CAAC,MAAM,CAAC,gBAAgB,EAAE,QAAQ,CAAC,IAAI,CAAC,CAAC;QACvE,CAAC;QAED,MAAM,UAAU,GAAG,mBAAQ,CAAC,WAAW,CAAC,iBAAiB,CAAC,CAAC;QAE3D,OAAO,EAAE,iBAAiB,EAAE,gBAAgB,EAAE,UAAU,EAAE,CAAC;IAC7D,CAAC;CACF;AArBD,4CAqBC"}
|
|
@@ -1,23 +0,0 @@
|
|
|
1
|
-
import React from 'react';
|
|
2
|
-
import ReactDOM from 'react-dom';
|
|
3
|
-
export class ReactUtilService {
|
|
4
|
-
createReactComponentAppendToDom(component, targetElement, clearTargetContent = false, props = undefined, children = []) {
|
|
5
|
-
const componentElement = React.createElement(component, props, children);
|
|
6
|
-
let componentInstance;
|
|
7
|
-
// Append DOM element to the HTML element specified
|
|
8
|
-
if (targetElement) {
|
|
9
|
-
if (clearTargetContent && targetElement.innerHTML) {
|
|
10
|
-
targetElement.innerHTML = '';
|
|
11
|
-
}
|
|
12
|
-
// @ts-ignore
|
|
13
|
-
componentInstance = ReactDOM.render(componentElement, targetElement);
|
|
14
|
-
}
|
|
15
|
-
else {
|
|
16
|
-
// @ts-ignore
|
|
17
|
-
componentInstance = ReactDOM.render(componentElement, document.body);
|
|
18
|
-
}
|
|
19
|
-
const domElement = ReactDOM.findDOMNode(componentInstance);
|
|
20
|
-
return { componentInstance, componentElement, domElement };
|
|
21
|
-
}
|
|
22
|
-
}
|
|
23
|
-
//# sourceMappingURL=reactUtil.service.js.map
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"reactUtil.service.js","sourceRoot":"","sources":["../../../src/slickgrid-react/services/reactUtil.service.ts"],"names":[],"mappings":"AAAA,OAAO,KAAyB,MAAM,OAAO,CAAC;AAC9C,OAAO,QAAQ,MAAM,WAAW,CAAC;AAGjC,MAAM,OAAO,gBAAgB;IAC3B,+BAA+B,CAAC,SAAc,EAAE,aAAqC,EAAE,kBAAkB,GAAG,KAAK,EAAE,QAAa,SAAS,EAAE,WAAwB,EAAE;QACnK,MAAM,gBAAgB,GAAG,KAAK,CAAC,aAAa,CAAC,SAAS,EAAE,KAAK,EAAE,QAAQ,CAAC,CAAC;QACzE,IAAI,iBAAsB,CAAC;QAE3B,mDAAmD;QACnD,IAAI,aAAa,EAAE,CAAC;YAClB,IAAI,kBAAkB,IAAI,aAAa,CAAC,SAAS,EAAE,CAAC;gBAClD,aAAa,CAAC,SAAS,GAAG,EAAE,CAAC;YAC/B,CAAC;YACD,aAAa;YACb,iBAAiB,GAAG,QAAQ,CAAC,MAAM,CAAC,gBAAgB,EAAE,aAAa,CAAC,CAAC;QACvE,CAAC;aAAM,CAAC;YACN,aAAa;YACb,iBAAiB,GAAG,QAAQ,CAAC,MAAM,CAAC,gBAAgB,EAAE,QAAQ,CAAC,IAAI,CAAC,CAAC;QACvE,CAAC;QAED,MAAM,UAAU,GAAG,QAAQ,CAAC,WAAW,CAAC,iBAAiB,CAAC,CAAC;QAE3D,OAAO,EAAE,iBAAiB,EAAE,gBAAgB,EAAE,UAAU,EAAE,CAAC;IAC7D,CAAC;CACF"}
|
|
@@ -1,6 +0,0 @@
|
|
|
1
|
-
import { type ReactNode } from 'react';
|
|
2
|
-
import type { SlickgridReactComponentOutput } from '../models/reactComponentOutput.interface';
|
|
3
|
-
export declare class ReactUtilService {
|
|
4
|
-
createReactComponentAppendToDom(component: any, targetElement?: HTMLElement | Element, clearTargetContent?: boolean, props?: any, children?: ReactNode[]): SlickgridReactComponentOutput;
|
|
5
|
-
}
|
|
6
|
-
//# sourceMappingURL=reactUtil.service.d.ts.map
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"reactUtil.service.d.ts","sourceRoot":"","sources":["../../../src/slickgrid-react/services/reactUtil.service.ts"],"names":[],"mappings":"AAAA,OAAc,EAAE,KAAK,SAAS,EAAE,MAAM,OAAO,CAAC;AAE9C,OAAO,KAAK,EAAE,6BAA6B,EAAE,MAAM,0CAA0C,CAAC;AAE9F,qBAAa,gBAAgB;IAC3B,+BAA+B,CAAC,SAAS,EAAE,GAAG,EAAE,aAAa,CAAC,EAAE,WAAW,GAAG,OAAO,EAAE,kBAAkB,UAAQ,EAAE,KAAK,GAAE,GAAe,EAAE,QAAQ,GAAE,SAAS,EAAO,GAAG,6BAA6B;CAoBtM"}
|
|
@@ -1,26 +0,0 @@
|
|
|
1
|
-
import React, { type ReactNode } from 'react';
|
|
2
|
-
import ReactDOM from 'react-dom';
|
|
3
|
-
import type { SlickgridReactComponentOutput } from '../models/reactComponentOutput.interface';
|
|
4
|
-
|
|
5
|
-
export class ReactUtilService {
|
|
6
|
-
createReactComponentAppendToDom(component: any, targetElement?: HTMLElement | Element, clearTargetContent = false, props: any = undefined, children: ReactNode[] = []): SlickgridReactComponentOutput {
|
|
7
|
-
const componentElement = React.createElement(component, props, children);
|
|
8
|
-
let componentInstance: any;
|
|
9
|
-
|
|
10
|
-
// Append DOM element to the HTML element specified
|
|
11
|
-
if (targetElement) {
|
|
12
|
-
if (clearTargetContent && targetElement.innerHTML) {
|
|
13
|
-
targetElement.innerHTML = '';
|
|
14
|
-
}
|
|
15
|
-
// @ts-ignore
|
|
16
|
-
componentInstance = ReactDOM.render(componentElement, targetElement);
|
|
17
|
-
} else {
|
|
18
|
-
// @ts-ignore
|
|
19
|
-
componentInstance = ReactDOM.render(componentElement, document.body);
|
|
20
|
-
}
|
|
21
|
-
|
|
22
|
-
const domElement = ReactDOM.findDOMNode(componentInstance);
|
|
23
|
-
|
|
24
|
-
return { componentInstance, componentElement, domElement };
|
|
25
|
-
}
|
|
26
|
-
}
|