@trudb/tru-common-lib 0.2.473 → 0.2.476

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.
@@ -8600,6 +8600,8 @@ class TruDataGrid {
8600
8600
  rowFocuedOnMousedown = null;
8601
8601
  copiedRowData = [];
8602
8602
  scrollOffsetCleanup = null;
8603
+ detailResizeCleanup = null;
8604
+ pendingResizeFrameId = null;
8603
8605
  constructor(dataContext, componentLookup, searchResultViewManager, appEnvironment, searchViewEventHandler, uiNotification, connectionHub, windowEventHandler, dataGridClipboard, util, app, cdr, hostElement, desktopViewEventNotifier, tabGroupEventNotifier) {
8604
8606
  this.dataContext = dataContext;
8605
8607
  this.componentLookup = componentLookup;
@@ -9206,6 +9208,7 @@ class TruDataGrid {
9206
9208
  if (this.config?.view && this.desktopViewEventNotifier) {
9207
9209
  this.subs.push(this.desktopViewEventNotifier.onActiveStateChanged().pipe(skip(1)).subscribe(() => this.resizeGrid()));
9208
9210
  }
9211
+ this.setupDetailResizeObservers();
9209
9212
  }
9210
9213
  ngOnChanges(changes) {
9211
9214
  this.runSearch();
@@ -9213,6 +9216,7 @@ class TruDataGrid {
9213
9216
  }
9214
9217
  ngOnDestroy() {
9215
9218
  this.teardownScrollObservers();
9219
+ this.teardownDetailResizeObservers();
9216
9220
  this.subs.forEach(s => s.unsubscribe());
9217
9221
  }
9218
9222
  //this only applies to grids inside detail views and tab containers.
@@ -9282,6 +9286,71 @@ class TruDataGrid {
9282
9286
  this.scrollOffsetCleanup = null;
9283
9287
  }
9284
9288
  };
9289
+ scheduleResizeGrid = () => {
9290
+ if (this.pendingResizeFrameId !== null)
9291
+ return;
9292
+ this.pendingResizeFrameId = window.requestAnimationFrame(() => {
9293
+ this.pendingResizeFrameId = null;
9294
+ this.resizeGrid();
9295
+ });
9296
+ };
9297
+ setupDetailResizeObservers = () => {
9298
+ this.teardownDetailResizeObservers();
9299
+ const gridType = this.gridType;
9300
+ if (gridType === TruDataGridTypes.Search)
9301
+ return;
9302
+ const hostEl = this.hostElement.nativeElement;
9303
+ if (!hostEl || !hostEl.isConnected)
9304
+ return;
9305
+ const detailContent = hostEl.closest('.detail-content');
9306
+ if (!detailContent)
9307
+ return;
9308
+ // Make sure we re-measure when the grid is scrolled into view (common when the initial window height is short).
9309
+ const onScroll = () => this.scheduleResizeGrid();
9310
+ let intersectionObserver = null;
9311
+ if (typeof IntersectionObserver !== 'undefined') {
9312
+ intersectionObserver = new IntersectionObserver((entries) => {
9313
+ if (entries.some(e => e.isIntersecting)) {
9314
+ this.scheduleResizeGrid();
9315
+ }
9316
+ }, { root: detailContent, threshold: 0 });
9317
+ intersectionObserver.observe(hostEl);
9318
+ }
9319
+ else {
9320
+ detailContent.addEventListener('scroll', onScroll, { passive: true });
9321
+ }
9322
+ let resizeObserver = null;
9323
+ if (typeof ResizeObserver !== 'undefined') {
9324
+ resizeObserver = new ResizeObserver(() => this.scheduleResizeGrid());
9325
+ resizeObserver.observe(detailContent);
9326
+ }
9327
+ this.detailResizeCleanup = () => {
9328
+ if (intersectionObserver) {
9329
+ intersectionObserver.disconnect();
9330
+ intersectionObserver = null;
9331
+ }
9332
+ else {
9333
+ detailContent.removeEventListener('scroll', onScroll);
9334
+ }
9335
+ if (resizeObserver) {
9336
+ resizeObserver.disconnect();
9337
+ resizeObserver = null;
9338
+ }
9339
+ if (this.pendingResizeFrameId !== null) {
9340
+ window.cancelAnimationFrame(this.pendingResizeFrameId);
9341
+ this.pendingResizeFrameId = null;
9342
+ }
9343
+ this.detailResizeCleanup = null;
9344
+ };
9345
+ // Kick an initial measurement once layout settles.
9346
+ this.scheduleResizeGrid();
9347
+ };
9348
+ teardownDetailResizeObservers = () => {
9349
+ if (this.detailResizeCleanup) {
9350
+ this.detailResizeCleanup();
9351
+ this.detailResizeCleanup = null;
9352
+ }
9353
+ };
9285
9354
  //Adjusts grid height to fill available detail space, honoring fill/min/max rows.
9286
9355
  //this doesn't affect search grids.
9287
9356
  resizeGrid = () => {
@@ -9300,12 +9369,6 @@ class TruDataGrid {
9300
9369
  const firstGridTop = siblingGrids.length ? siblingGrids[0].getBoundingClientRect().top : hostEl.getBoundingClientRect().top;
9301
9370
  const detailRect = detailContent.getBoundingClientRect();
9302
9371
  const availableTotal = detailContent.clientHeight - (firstGridTop - detailRect.top) - 10; // small bottom padding
9303
- if (availableTotal <= 0)
9304
- return;
9305
- const perGridOverhead = 45; // toolbar + statusbar overhead (v6 does something similar i am just porting here)
9306
- const distributedHeight = siblingGrids.length > 1
9307
- ? (availableTotal - (siblingGrids.length - 1) * perGridOverhead) / siblingGrids.length
9308
- : availableTotal;
9309
9372
  const rowHeight = this.gridOptions?.rowHeight ?? 22;
9310
9373
  const headerHeight = 25;
9311
9374
  const minRows = this.config.minimumRows ?? 0;
@@ -9318,6 +9381,20 @@ class TruDataGrid {
9318
9381
  const contentMinPx = Math.max((minRows * rowHeight) + headerHeight, overlayMinPx);
9319
9382
  const minPx = contentMinPx + gridChromePx;
9320
9383
  const maxPx = typeof maxRows === 'number' ? ((maxRows * rowHeight) + headerHeight + gridChromePx) : undefined;
9384
+ // When the initial window height is short, the grid can start below the visible portion of the detail container.
9385
+ // In that case, we still need a minimum height so the parent can scroll to reveal the grid.
9386
+ if (availableTotal <= 0) {
9387
+ hostEl.style.height = `${minPx}px`;
9388
+ const apiAny = this.api;
9389
+ if (apiAny?.doLayout) {
9390
+ apiAny.doLayout();
9391
+ }
9392
+ return;
9393
+ }
9394
+ const perGridOverhead = 45; // toolbar + statusbar overhead (v6 does something similar i am just porting here)
9395
+ const distributedHeight = siblingGrids.length > 1
9396
+ ? (availableTotal - (siblingGrids.length - 1) * perGridOverhead) / siblingGrids.length
9397
+ : availableTotal;
9321
9398
  let targetHeight = distributedHeight;
9322
9399
  if (!this.config.fill) {
9323
9400
  if (maxPx !== undefined && maxPx < targetHeight)
@@ -11917,17 +11994,19 @@ class TruTabGroup {
11917
11994
  const list = new QueryList();
11918
11995
  list.reset([matTabsFromQueryList]);
11919
11996
  this.tabGroup._tabs = list;
11997
+ // Ensure the initially-selected tab is marked active so consumers (e.g. detail grids) can load/size correctly.
11998
+ // MatTabGroup won't emit selectedTabChange on initial render.
11999
+ setTimeout(() => {
12000
+ const selectedIndex = typeof this.tabGroup.selectedIndex === 'number' ? this.tabGroup.selectedIndex : 0;
12001
+ this.setActiveTabByIndex(selectedIndex);
12002
+ }, 0);
11920
12003
  }
11921
12004
  onChange(event) {
11922
- const selectedTabLabel = event.tab.textLabel;
11923
- this.tabs.forEach((tab) => {
11924
- if (selectedTabLabel === tab.label) {
11925
- tab.notifyListeners(true);
11926
- }
11927
- else {
11928
- tab.notifyListeners(false);
11929
- }
11930
- });
12005
+ this.setActiveTabByIndex(event.index);
12006
+ }
12007
+ setActiveTabByIndex(selectedIndex) {
12008
+ const allTabs = this.tabs?.toArray?.() ?? [];
12009
+ allTabs.forEach((tab, index) => tab.notifyListeners(index === selectedIndex));
11931
12010
  }
11932
12011
  static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "19.2.17", ngImport: i0, type: TruTabGroup, deps: [], target: i0.ɵɵFactoryTarget.Component });
11933
12012
  static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "19.2.17", type: TruTabGroup, isStandalone: true, selector: "tru-tab-group", queries: [{ propertyName: "tabs", predicate: TruTab }], viewQueries: [{ propertyName: "tabGroup", first: true, predicate: MatTabGroup, descendants: true }], ngImport: i0, template: "<mat-tab-group #tabGroup\r\n (selectedTabChange)=\"onChange($event)\"\r\n animationDuration=\"0ms\">\r\n <ng-content #outlet></ng-content>\r\n</mat-tab-group>\r\n", styles: [""], dependencies: [{ kind: "ngmodule", type: CommonModule }, { kind: "ngmodule", type: FormsModule }, { kind: "ngmodule", type: MatTabsModule }, { kind: "component", type: i2$2.MatTabGroup, selector: "mat-tab-group", inputs: ["color", "fitInkBarToContent", "mat-stretch-tabs", "mat-align-tabs", "dynamicHeight", "selectedIndex", "headerPosition", "animationDuration", "contentTabIndex", "disablePagination", "disableRipple", "preserveContent", "backgroundColor", "aria-label", "aria-labelledby"], outputs: ["selectedIndexChange", "focusChange", "animationDone", "selectedTabChange"], exportAs: ["matTabGroup"] }], encapsulation: i0.ViewEncapsulation.None });