@sd-angular/core 19.0.0-beta.18 → 19.0.0-beta.19

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.
@@ -1,4 +1,14 @@
1
1
  import * as i0 from "@angular/core";
2
+ /**
3
+ * Directive thêm hiệu ứng đổ bóng (elevation-2) vào cột sticky cuối cùng bên trái
4
+ * và cột sticky đầu tiên bên phải, tạo ngăn cách trực quan với phần được scroll.
5
+ *
6
+ * Chỉ dùng nội bộ trong sd-table, không chìa ra ngoài.
7
+ *
8
+ * Gắn vào scroll container của table:
9
+ * @example
10
+ * <div class="c-table" stickyShadow>...</div>
11
+ */
2
12
  export declare class StickyShadowDirective {
3
13
  #private;
4
14
  constructor();
@@ -1,7 +1,7 @@
1
1
  import { TemplateRef } from '@angular/core';
2
2
  import { SdBadge } from '@sd-angular/core/components/badge';
3
3
  import { SdSearch } from '@sd-angular/core/forms';
4
- import { SdColor, SdOperator } from '@sd-angular/core/utilities';
4
+ import { SdColor, SdNestedKeyOf, SdOperator } from '@sd-angular/core/utilities';
5
5
  export type SdTableColumn<T = any> = SdTableColumnText<T> | SdTableColumnNumber<T> | SdTableColumnBool<T> | SdTableColumnDate<T> | SdTableColumnValues<T> | SdTableColumnLazyValues<T> | SdTableColumnChildren<T>;
6
6
  export type SdTableColumnTransformFunc<T = any> = (value: any, rowData: T, args?: {
7
7
  isExport?: boolean;
@@ -45,14 +45,14 @@ interface SdTableColumnBase<T = any> {
45
45
  copiable?: boolean;
46
46
  }
47
47
  interface SdTableColumnText<T = any> extends SdTableColumnBase<T> {
48
- field: Extract<keyof T, string>;
48
+ field: SdNestedKeyOf<T>;
49
49
  type: 'string';
50
50
  badge?: (value: any, rowData: T) => SdColor;
51
51
  badgeIcon?: (value: any, rowData: T) => string;
52
52
  badgeType?: SdBadge['type'];
53
53
  }
54
54
  interface SdTableColumnNumber<T = any> extends SdTableColumnBase<T> {
55
- field: Extract<keyof T, string>;
55
+ field: SdNestedKeyOf<T>;
56
56
  type: 'number';
57
57
  badge?: (value: any, rowData: T) => SdColor;
58
58
  badgeIcon?: (value: any, rowData: T) => string;
@@ -62,7 +62,7 @@ interface SdTableColumnNumber<T = any> extends SdTableColumnBase<T> {
62
62
  };
63
63
  }
64
64
  interface SdTableColumnBool<T = any> extends SdTableColumnBase<T> {
65
- field: Extract<keyof T, string>;
65
+ field: SdNestedKeyOf<T>;
66
66
  type: 'boolean';
67
67
  option?: {
68
68
  displayOnTrue?: string;
@@ -70,14 +70,14 @@ interface SdTableColumnBool<T = any> extends SdTableColumnBase<T> {
70
70
  };
71
71
  }
72
72
  interface SdTableColumnDate<T = any> extends SdTableColumnBase<T> {
73
- field: Extract<keyof T, string>;
73
+ field: SdNestedKeyOf<T>;
74
74
  type: 'date' | 'datetime' | 'time';
75
75
  filter?: SdTableColumnBase['filter'] & {
76
76
  type?: 'daterange' | 'date' | 'split-date';
77
77
  };
78
78
  }
79
79
  export interface SdTableColumnValues<T = any> extends SdTableColumnBase<T> {
80
- field: Extract<keyof T, string>;
80
+ field: SdNestedKeyOf<T>;
81
81
  type: 'values';
82
82
  badge?: (value: any, rowData: T) => SdColor;
83
83
  badgeIcon?: (value: any, rowData: T) => string;
@@ -90,7 +90,7 @@ export interface SdTableColumnValues<T = any> extends SdTableColumnBase<T> {
90
90
  };
91
91
  }
92
92
  export interface SdTableColumnLazyValues<T = any> extends SdTableColumnBase<T> {
93
- field: Extract<keyof T, string>;
93
+ field: SdNestedKeyOf<T>;
94
94
  type: 'lazy-values';
95
95
  option: {
96
96
  valueField: string;
@@ -1,3 +1,4 @@
1
+ import { SdNestedKeyOf } from '@sd-angular/core/utilities';
1
2
  import { SdTableFilterRequest } from '../services/table-filter/table-filter.model';
2
3
  export type SdTableOptionExport<T = any> = SdTableOptionExportDefault<T> | SdTableOptionExportCustom;
3
4
  export interface SdTableOptionExportDefault<T = any> {
@@ -22,7 +23,7 @@ export interface SdTableOptionExportCustom {
22
23
  onExport: (filterRequest: SdTableFilterRequest) => Promise<void>;
23
24
  }
24
25
  export interface SdTableOptionExportColumn<T = any> {
25
- field: Extract<keyof T, string>;
26
+ field: SdNestedKeyOf<T>;
26
27
  title: string;
27
28
  description?: string;
28
29
  width?: string;
@@ -35,7 +36,7 @@ export interface SdTableOptionExportSheet<T = any> {
35
36
  name: string;
36
37
  items: T[] | (() => T[] | Promise<T[]>);
37
38
  headers: {
38
- value: Extract<keyof T, string>;
39
+ value: SdNestedKeyOf<T>;
39
40
  display: string;
40
41
  }[];
41
42
  }
@@ -2,7 +2,7 @@ import { Observable } from 'rxjs';
2
2
  import { SdTableColumn } from '../../models/table-column.model';
3
3
  import { TemplateRef } from '@angular/core';
4
4
  import { SdSearch } from '@sd-angular/core/forms';
5
- import { SdOperator, SdOrder, SdPagingReq } from '@sd-angular/core/utilities';
5
+ import { SdNestedKeyOf, SdOperator, SdOrder, SdPagingReq } from '@sd-angular/core/utilities';
6
6
  export interface SdTableQuickFilter {
7
7
  code: string;
8
8
  columnFilter: Record<string, any>;
@@ -20,7 +20,7 @@ export interface TableFilterValue {
20
20
  }
21
21
  export interface SdTableFilterRequest<T = any> {
22
22
  columnOperator: Record<string, SdOperator>;
23
- rawColumnFilter: Record<keyof T, any>;
23
+ rawColumnFilter: Record<SdNestedKeyOf<T>, any>;
24
24
  rawExternalFilter: Record<string, any>;
25
25
  pageNumber: number;
26
26
  pageSize: number;
@@ -1866,31 +1866,69 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.2.17", ngImpo
1866
1866
  }] } });
1867
1867
 
1868
1868
  // sticky-shadow.directive.ts
1869
+ /**
1870
+ * Directive thêm hiệu ứng đổ bóng (elevation-2) vào cột sticky cuối cùng bên trái
1871
+ * và cột sticky đầu tiên bên phải, tạo ngăn cách trực quan với phần được scroll.
1872
+ *
1873
+ * Chỉ dùng nội bộ trong sd-table, không chìa ra ngoài.
1874
+ *
1875
+ * Gắn vào scroll container của table:
1876
+ * @example
1877
+ * <div class="c-table" stickyShadow>...</div>
1878
+ */
1869
1879
  class StickyShadowDirective {
1870
1880
  #el = inject((ElementRef));
1871
1881
  #destroyRef = inject(DestroyRef);
1872
1882
  constructor() {
1873
1883
  afterNextRender(() => {
1874
1884
  const container = this.#el.nativeElement;
1875
- this.#updateShadow(container);
1885
+ // Dùng MutationObserver để detect khi CDK render rows mới vào table
1886
+ // (data load async, phân trang, ...) — lúc này td mới có đủ sticky classes
1887
+ const mutationObserver = new MutationObserver(() => {
1888
+ this.#updateShadow(container);
1889
+ });
1890
+ mutationObserver.observe(container, {
1891
+ childList: true, // Theo dõi thêm/bớt các node con
1892
+ subtree: true, // Bao gồm tất cả các cấp con cháu
1893
+ });
1894
+ // Cập nhật shadow mỗi khi user scroll ngang
1876
1895
  fromEvent(container, 'scroll')
1877
1896
  .pipe(debounceTime(10), takeUntilDestroyed(this.#destroyRef))
1878
1897
  .subscribe(() => this.#updateShadow(container));
1898
+ // Disconnect MutationObserver khi directive bị destroy
1899
+ this.#destroyRef.onDestroy(() => mutationObserver.disconnect());
1879
1900
  });
1880
1901
  }
1902
+ /**
1903
+ * Toggle class shadow lên tất cả th và td của một cột.
1904
+ * Dùng cdk-column-{field} để xác định cột vì Angular CDK
1905
+ * add class này đồng nhất lên cả th lẫn td.
1906
+ */
1881
1907
  #setShadow(container, colClass, shadowClass, add) {
1882
- container.querySelectorAll(`th.${colClass}, td.${colClass}`)
1883
- .forEach(el => el.classList.toggle(shadowClass, add));
1908
+ container.querySelectorAll(`th.${colClass}, td.${colClass}`).forEach(el => el.classList.toggle(shadowClass, add));
1884
1909
  }
1910
+ /**
1911
+ * Tính toán và cập nhật shadow dựa trên vị trí scroll hiện tại.
1912
+ *
1913
+ * Angular Material đánh dấu sticky left bằng class `mat-mdc-table-sticky-border-elem-left`
1914
+ * và sticky right bằng `mat-mdc-table-sticky-border-elem-right` — dùng các class này
1915
+ * để detect thay vì getComputedStyle vì reliable hơn.
1916
+ *
1917
+ * Chỉ apply shadow cho:
1918
+ * - Cột cuối cùng trong nhóm sticky-left (sát phần scroll)
1919
+ * - Cột đầu tiên trong nhóm sticky-right (sát phần scroll)
1920
+ */
1885
1921
  #updateShadow(container) {
1886
1922
  const scrollLeft = container.scrollLeft;
1887
1923
  const scrollRight = container.scrollWidth - container.clientWidth - scrollLeft;
1924
+ // Query trên header row đầu tiên để xác định các cột sticky
1925
+ // td sẽ được xử lý thông qua #setShadow theo cdk-column class
1888
1926
  const headerRow = container.querySelector('tr.c-first-header');
1889
1927
  if (!headerRow)
1890
1928
  return;
1891
- const allStickyLeft = Array.from(headerRow.querySelectorAll('th.mat-mdc-table-sticky:not(.mat-mdc-table-sticky-border-elem-right)'));
1929
+ const allStickyLeft = Array.from(headerRow.querySelectorAll('th.mat-mdc-table-sticky-border-elem-left'));
1892
1930
  const allStickyRight = Array.from(headerRow.querySelectorAll('th.mat-mdc-table-sticky-border-elem-right'));
1893
- // Reset tất cả trước
1931
+ // Reset shadow toàn bộ các cột sticky trước khi tính lại
1894
1932
  allStickyLeft.forEach(th => {
1895
1933
  const colClass = [...th.classList].find(c => c.startsWith('cdk-column-'));
1896
1934
  if (colClass)
@@ -1901,14 +1939,14 @@ class StickyShadowDirective {
1901
1939
  if (colClass)
1902
1940
  this.#setShadow(container, colClass, 'sticky-shadow-left', false);
1903
1941
  });
1904
- // Chỉ cột cuối sticky-left mới có shadow
1942
+ // Chỉ cột cuối cùng sticky-left có shadow khi đang scroll sang phải
1905
1943
  const lastStickyLeft = allStickyLeft.at(-1);
1906
1944
  if (lastStickyLeft && scrollLeft > 0) {
1907
1945
  const colClass = [...lastStickyLeft.classList].find(c => c.startsWith('cdk-column-'));
1908
1946
  if (colClass)
1909
1947
  this.#setShadow(container, colClass, 'sticky-shadow-right', true);
1910
1948
  }
1911
- // Chỉ cột đầu sticky-right mới có shadow
1949
+ // Chỉ cột đầu tiên sticky-right có shadow khi chưa scroll hết sang phải
1912
1950
  const firstStickyRight = allStickyRight.at(0);
1913
1951
  if (firstStickyRight && scrollRight > 0) {
1914
1952
  const colClass = [...firstStickyRight.classList].find(c => c.startsWith('cdk-column-'));