@sdcorejs/angular 20.1.4 → 20.1.6

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.
@@ -8,6 +8,11 @@ import { SdViewed, SdViewedInput, SdFormControl } from '@sdcorejs/angular/forms/
8
8
  import { Size } from '@sdcorejs/utils/models';
9
9
 
10
10
  type SdDateModelValue = string | number | Date | undefined | null;
11
+ type SdDateKeyupEvent = Event | {
12
+ target?: {
13
+ value?: string | null;
14
+ };
15
+ };
11
16
  declare class SdDate implements OnDestroy, OnInit {
12
17
  #private;
13
18
  id: string;
@@ -81,7 +86,9 @@ declare class SdDate implements OnDestroy, OnInit {
81
86
  open: () => void;
82
87
  focusInputElement(): void;
83
88
  onKeyDown: (event: KeyboardEvent) => boolean;
84
- onKeyup: (event: any) => void;
89
+ onInput: (event: Event) => void;
90
+ /** Kept as a compatibility entry point for callers that used the old keyup handler. */
91
+ onKeyup: (event: SdDateKeyupEvent) => void;
85
92
  onChange: (event: MatDatepickerInputEvent<Date>) => void;
86
93
  clear: ($event: any) => void;
87
94
  static ɵfac: _angular_core.ɵɵFactoryDeclaration<SdDate, never>;
@@ -1,7 +1,10 @@
1
- import { InjectionToken, Signal } from '@angular/core';
1
+ import * as i0 from '@angular/core';
2
+ import { InjectionToken, Signal, Provider } from '@angular/core';
2
3
  import { MatFormFieldAppearance } from '@angular/material/form-field';
3
4
  import { FormControl, FormControlState, ValidatorFn, FormControlOptions, AsyncValidatorFn, AbstractControl, FormGroup, NgForm } from '@angular/forms';
4
5
  import { Subject } from 'rxjs';
6
+ import { DateFnsAdapter } from '@angular/material-date-fns-adapter';
7
+ import { MatDateFormats } from '@angular/material/core';
5
8
 
6
9
  interface ISdFormConfiguration {
7
10
  appearance?: MatFormFieldAppearance;
@@ -202,5 +205,28 @@ declare function ɵsdCoerceFormGroup(value: unknown): FormGroup | undefined;
202
205
  */
203
206
  declare function ɵsdFormControlConnector<TModel, TControl>(options: ɵSdFormControlConnectorOptions<TModel, TControl>): ɵSdFormControlConnector<TControl>;
204
207
 
205
- export { HandleSdCustomValidator, SD_FORM_CONFIGURATION, SdFormControl, SdInlineErrorValidator, sdFormControlState, sdViewedInline, sdViewedTransform, ɵsdCoerceFormGroup, ɵsdFormControlConnector };
208
+ /**
209
+ * DateAdapter từ chối mọi chuỗi người dùng chưa gõ xong.
210
+ *
211
+ * WHY cần đến mức này: `<input matInput [matDatepicker]>` khiến Material tự
212
+ * `parse()` lại ô nhập SAU MỖI PHÍM GÕ rồi ghi thẳng kết quả vào form control.
213
+ * Adapter mặc định quá dễ dãi trên hai đường:
214
+ *
215
+ * 1. `date-fns.parse` nhận năm thiếu chữ số → `11/12/2` thành năm 0002,
216
+ * `11/12/20` thành năm 0020. Ô nhập vừa gõ dở đã bị coi là hợp lệ (cờ lỗi
217
+ * bị xoá) và control ôm một ngày rác.
218
+ * 2. `parseISO` coi chuỗi 2 chữ số là thế kỷ → xoá lùi còn `11` ra năm 1100.
219
+ *
220
+ * Cả hai đường đều bị chặn ở đây: control chỉ nhận giá trị khi người dùng thực
221
+ * sự gõ xong.
222
+ */
223
+ declare class SdStrictDateFnsAdapter extends DateFnsAdapter {
224
+ parse(value: unknown, parseFormat: string | string[]): Date | null;
225
+ static ɵfac: i0.ɵɵFactoryDeclaration<SdStrictDateFnsAdapter, never>;
226
+ static ɵprov: i0.ɵɵInjectableDeclaration<SdStrictDateFnsAdapter>;
227
+ }
228
+ /** `provideDateFnsAdapter` + ép dùng adapter parse chặt ở trên. */
229
+ declare function provideSdStrictDateFnsAdapter(formats: MatDateFormats): Provider[];
230
+
231
+ export { HandleSdCustomValidator, SD_FORM_CONFIGURATION, SdFormControl, SdInlineErrorValidator, SdStrictDateFnsAdapter, provideSdStrictDateFnsAdapter, sdFormControlState, sdViewedInline, sdViewedTransform, ɵsdCoerceFormGroup, ɵsdFormControlConnector };
206
232
  export type { ISdFormConfiguration, SdCustomValidator, SdFormControlSnapshot, SdSearch, SdSearchReq, SdSelectionData, SdViewed, SdViewedInlineApi, SdViewedInput, ɵSdFormControlConnector, ɵSdFormControlConnectorOptions, ɵSdFormControlConnectorState, ɵSdFormControlParent };
package/i18n/index.d.ts CHANGED
@@ -465,6 +465,8 @@ declare const EN_MESSAGES: {
465
465
  readonly 'core.component.table.choose-filter-hint': "Please choose a filter to start";
466
466
  readonly 'core.component.table.no-data': "No data";
467
467
  readonly 'core.component.table.export-excel': "Export Excel";
468
+ readonly 'core.component.table.exporting': "Exporting...{percent}%";
469
+ readonly 'core.component.table.export': "Export";
468
470
  readonly 'core.component.table.export-csv': "Export CSV";
469
471
  readonly 'core.component.table.showing': "Showing:";
470
472
  readonly 'core.component.table.paginator.first-page': "First page";
@@ -498,7 +500,11 @@ declare const EN_MESSAGES: {
498
500
  readonly 'core.component.upload-file.preview-title': "Preview image";
499
501
  readonly 'core.module.layout.user.change-password': "Change password";
500
502
  readonly 'core.module.layout.user.logout': "Sign out";
503
+ readonly 'core.module.layout.user.update-profile': "Update profile";
504
+ readonly 'core.module.layout.user.setting': "Settings";
505
+ readonly 'core.module.layout.user.notification': "Notifications";
501
506
  readonly 'core.module.layout.sidebar.search': "Search";
507
+ readonly 'core.module.layout.sidebar.toggle': "Toggle sidebar";
502
508
  readonly 'core.module.layout.greeting.hello': "Hello, {name}";
503
509
  readonly 'core.module.layout.weekday.0': "Sunday";
504
510
  readonly 'core.module.layout.weekday.1': "Monday";
@@ -515,6 +521,8 @@ declare const EN_MESSAGES: {
515
521
  readonly 'core.module.layout.not-found.message': "The page you're looking for doesn't exist or has been removed. Please check the URL or go back to the home page to continue.";
516
522
  readonly 'core.module.layout.not-found.back': "Go back";
517
523
  readonly 'core.module.layout.home.tab-name': "Home";
524
+ readonly 'core.module.layout.not-found.tab-name': "Page Not Found";
525
+ readonly 'core.module.layout.forbidden.tab-name': "Access Denied";
518
526
  readonly 'core.module.layout.home.feature.data': "Data";
519
527
  readonly 'core.module.layout.home.feature.reports': "Reports";
520
528
  readonly 'core.module.layout.home.feature.users': "Users";
@@ -1,5 +1,5 @@
1
1
  import * as _angular_core from '@angular/core';
2
- import { InjectionToken, PipeTransform } from '@angular/core';
2
+ import { Signal, InjectionToken, PipeTransform } from '@angular/core';
3
3
  import * as i1$1 from '@angular/common';
4
4
  import * as i1 from '@angular/router';
5
5
  import { Params } from '@angular/router';
@@ -7,6 +7,7 @@ import { SdStorage } from '@sdcorejs/angular/services';
7
7
  import { SdViewport } from '@sdcorejs/angular/services/viewport';
8
8
  import * as _sdcorejs_angular_modules_layout from '@sdcorejs/angular/modules/layout';
9
9
  import { MaybeAsync } from '@sdcorejs/utils/models';
10
+ import { Observable } from 'rxjs';
10
11
 
11
12
  declare class HomeRoutingModule {
12
13
  static ɵfac: _angular_core.ɵɵFactoryDeclaration<HomeRoutingModule, never>;
@@ -91,13 +92,46 @@ declare class SdLayoutResponsiveService {
91
92
  static ɵprov: _angular_core.ɵɵInjectableDeclaration<SdLayoutResponsiveService>;
92
93
  }
93
94
 
95
+ /** Consumer-owned account action invoked without arguments by the shared user menu. */
96
+ type SdLayoutAccountAction = () => void | Promise<void>;
97
+ /** Notification badge source and the action that opens the consumer's notification experience. */
98
+ interface SdLayoutNotificationConfiguration {
99
+ /**
100
+ * Số lượng thông báo chưa đọc. Hỗ trợ giá trị tĩnh hoặc nguồn reactive dài hạn.
101
+ */
102
+ count: number | Signal<number> | Observable<number>;
103
+ /**
104
+ * Tác vụ do consumer xử lý khi người dùng chọn thông báo.
105
+ */
106
+ action: SdLayoutAccountAction;
107
+ }
94
108
  interface ISdLayoutConfiguration {
95
109
  homeUrl?: string;
96
110
  mobileBreakpoint?: number;
97
111
  sidebar: ISdSidebarConfiguration | (() => MaybeAsync<ISdSidebarConfiguration>);
98
112
  userInfo: SdLayoutUserInfo | (() => MaybeAsync<SdLayoutUserInfo>);
99
- signout: () => void | Promise<void>;
100
- changePassword?: () => void | Promise<void>;
113
+ signout: SdLayoutAccountAction;
114
+ changePassword?: SdLayoutAccountAction;
115
+ /**
116
+ * Tác vụ chỉnh sửa hồ sơ do consumer cung cấp.
117
+ */
118
+ updateProfile?: SdLayoutAccountAction;
119
+ /**
120
+ * Tác vụ mở thiết lập tài khoản do consumer cung cấp.
121
+ */
122
+ setting?: SdLayoutAccountAction;
123
+ /**
124
+ * Cấu hình số lượng và tác vụ thông báo của tài khoản.
125
+ */
126
+ notification?: SdLayoutNotificationConfiguration;
127
+ }
128
+ /** Optional role metadata rendered below the user's email when `text` is non-empty. */
129
+ interface SdLayoutUserRole {
130
+ text: string;
131
+ /** Icon name resolved by `SdIcon`. */
132
+ icon?: string;
133
+ /** CSS color applied to the role metadata. */
134
+ color?: string;
101
135
  }
102
136
  interface SdLayoutUserInfo {
103
137
  /**
@@ -121,6 +155,11 @@ interface SdLayoutUserInfo {
121
155
  * Hỗ trợ các định dạng: URL (http/https), chuỗi base64 (data:image), hoặc đường dẫn nội bộ.
122
156
  */
123
157
  avatar?: string;
158
+ /**
159
+ * Chức vụ hoặc vai trò hiển thị cùng thông tin người dùng.
160
+ * Không render khi `text` rỗng.
161
+ */
162
+ role?: SdLayoutUserRole;
124
163
  }
125
164
  declare const DEFAULT_LAYOUT_MOBILE_BREAKPOINT = 1024;
126
165
  interface SidebarConfigurationBase {
@@ -306,6 +345,7 @@ interface SdLayoutMenuTreeNode {
306
345
  isGroup: boolean;
307
346
  isActive: boolean;
308
347
  isPinned: boolean;
348
+ isPinVisible: boolean;
309
349
  }
310
350
  declare class SdLayoutMenuTreeComponent {
311
351
  #private;
@@ -314,13 +354,17 @@ declare class SdLayoutMenuTreeComponent {
314
354
  activePath: _angular_core.InputSignal<string>;
315
355
  pinnedKeys: _angular_core.InputSignal<string[]>;
316
356
  showPin: _angular_core.InputSignal<boolean>;
357
+ pinVisibility: _angular_core.InputSignal<"hover" | "always">;
317
358
  navigate: _angular_core.OutputEmitterRef<SdLayoutRootMenu>;
318
359
  togglePinned: _angular_core.OutputEmitterRef<SdLayoutMenu>;
319
360
  nodes: _angular_core.Signal<SdLayoutMenuTreeNode[]>;
361
+ constructor();
320
362
  onNavigate(menu: SdLayoutMenu): void;
321
363
  onTogglePinned(event: MouseEvent, menu: SdLayoutMenu): void;
364
+ onPinHoverStart(key: string): void;
365
+ onPinHoverEnd(key: string): void;
322
366
  static ɵfac: _angular_core.ɵɵFactoryDeclaration<SdLayoutMenuTreeComponent, never>;
323
- static ɵcmp: _angular_core.ɵɵComponentDeclaration<SdLayoutMenuTreeComponent, "sd-layout-menu-tree", never, { "menus": { "alias": "menus"; "required": false; "isSignal": true; }; "query": { "alias": "query"; "required": false; "isSignal": true; }; "activePath": { "alias": "activePath"; "required": false; "isSignal": true; }; "pinnedKeys": { "alias": "pinnedKeys"; "required": false; "isSignal": true; }; "showPin": { "alias": "showPin"; "required": false; "isSignal": true; }; }, { "navigate": "navigate"; "togglePinned": "togglePinned"; }, never, never, true, never>;
367
+ static ɵcmp: _angular_core.ɵɵComponentDeclaration<SdLayoutMenuTreeComponent, "sd-layout-menu-tree", never, { "menus": { "alias": "menus"; "required": false; "isSignal": true; }; "query": { "alias": "query"; "required": false; "isSignal": true; }; "activePath": { "alias": "activePath"; "required": false; "isSignal": true; }; "pinnedKeys": { "alias": "pinnedKeys"; "required": false; "isSignal": true; }; "showPin": { "alias": "showPin"; "required": false; "isSignal": true; }; "pinVisibility": { "alias": "pinVisibility"; "required": false; "isSignal": true; }; }, { "navigate": "navigate"; "togglePinned": "togglePinned"; }, never, never, true, never>;
324
368
  }
325
369
 
326
370
  declare class SdLayoutUserMenuComponent {
@@ -328,14 +372,31 @@ declare class SdLayoutUserMenuComponent {
328
372
  private readonly trigger;
329
373
  private readonly menu;
330
374
  userInfo: _angular_core.InputSignal<SdLayoutUserInfo>;
331
- signout: _angular_core.InputSignal<(() => void | Promise<void>) | undefined>;
332
- changePassword: _angular_core.InputSignal<(() => void | Promise<void>) | undefined>;
375
+ signout: _angular_core.InputSignal<SdLayoutAccountAction | undefined>;
376
+ changePassword: _angular_core.InputSignal<SdLayoutAccountAction | undefined>;
377
+ updateProfile: _angular_core.InputSignal<SdLayoutAccountAction | undefined>;
378
+ setting: _angular_core.InputSignal<SdLayoutAccountAction | undefined>;
379
+ notification: _angular_core.InputSignal<SdLayoutNotificationConfiguration | undefined>;
333
380
  compact: _angular_core.InputSignal<boolean>;
381
+ presentation: _angular_core.InputSignal<"disclosure" | "mobile" | "mobile-inline">;
382
+ opened: _angular_core.OutputEmitterRef<void>;
383
+ closed: _angular_core.OutputEmitterRef<void>;
334
384
  isOpen: _angular_core.WritableSignal<boolean>;
335
385
  avatar: _angular_core.Signal<string | undefined>;
336
386
  displayName: _angular_core.Signal<string>;
337
- signoutAction: _angular_core.Signal<(() => void | Promise<void>) | undefined>;
338
- changePasswordAction: _angular_core.Signal<(() => void | Promise<void>) | undefined>;
387
+ role: _angular_core.Signal<{
388
+ text: string;
389
+ icon?: string;
390
+ color?: string;
391
+ } | undefined>;
392
+ signoutAction: _angular_core.Signal<SdLayoutAccountAction | undefined>;
393
+ changePasswordAction: _angular_core.Signal<SdLayoutAccountAction | undefined>;
394
+ updateProfileAction: _angular_core.Signal<SdLayoutAccountAction | undefined>;
395
+ settingAction: _angular_core.Signal<SdLayoutAccountAction | undefined>;
396
+ notificationConfiguration: _angular_core.Signal<SdLayoutNotificationConfiguration | undefined>;
397
+ notificationAction: _angular_core.Signal<SdLayoutAccountAction | undefined>;
398
+ notificationCount: _angular_core.Signal<number>;
399
+ notificationBadge: _angular_core.Signal<string | undefined>;
339
400
  constructor();
340
401
  open(): void;
341
402
  toggle(): void;
@@ -343,8 +404,11 @@ declare class SdLayoutUserMenuComponent {
343
404
  onMenuKeydown(event: KeyboardEvent): void;
344
405
  runChangePassword(): void;
345
406
  runSignout(): void;
407
+ runUpdateProfile(): void;
408
+ runSetting(): void;
409
+ runNotification(): void;
346
410
  static ɵfac: _angular_core.ɵɵFactoryDeclaration<SdLayoutUserMenuComponent, never>;
347
- static ɵcmp: _angular_core.ɵɵComponentDeclaration<SdLayoutUserMenuComponent, "sd-layout-user-menu", never, { "userInfo": { "alias": "userInfo"; "required": true; "isSignal": true; }; "signout": { "alias": "signout"; "required": false; "isSignal": true; }; "changePassword": { "alias": "changePassword"; "required": false; "isSignal": true; }; "compact": { "alias": "compact"; "required": false; "isSignal": true; }; }, {}, never, never, true, never>;
411
+ static ɵcmp: _angular_core.ɵɵComponentDeclaration<SdLayoutUserMenuComponent, "sd-layout-user-menu", never, { "userInfo": { "alias": "userInfo"; "required": true; "isSignal": true; }; "signout": { "alias": "signout"; "required": false; "isSignal": true; }; "changePassword": { "alias": "changePassword"; "required": false; "isSignal": true; }; "updateProfile": { "alias": "updateProfile"; "required": false; "isSignal": true; }; "setting": { "alias": "setting"; "required": false; "isSignal": true; }; "notification": { "alias": "notification"; "required": false; "isSignal": true; }; "compact": { "alias": "compact"; "required": false; "isSignal": true; }; "presentation": { "alias": "presentation"; "required": false; "isSignal": true; }; }, { "opened": "opened"; "closed": "closed"; }, never, never, true, never>;
348
412
  }
349
413
 
350
414
  interface SidebarV2RailItem {
@@ -458,6 +522,15 @@ declare class SidebarMobileV3Component {
458
522
  static ɵcmp: _angular_core.ɵɵComponentDeclaration<SidebarMobileV3Component, "sidebar-mobile-v3", never, { "menus": { "alias": "menus"; "required": false; "isSignal": true; }; "userInfo": { "alias": "userInfo"; "required": true; "isSignal": true; }; "sidebar": { "alias": "sidebar"; "required": true; "isSignal": true; }; }, {}, never, ["*"], true, never>;
459
523
  }
460
524
 
525
+ /**
526
+ * Resolve a translated tab name for `@SdTabComponent`.
527
+ *
528
+ * WHY not I18nService: the decorator runs at module-evaluation time, before
529
+ * Angular's DI exists, so the service cannot be injected. We read the language
530
+ * the app persisted and look the key up in the static catalog instead.
531
+ */
532
+ declare function resolveTabName(key: string): string;
533
+
461
534
  declare class MenuPipe implements PipeTransform {
462
535
  #private;
463
536
  private permissionService;
@@ -492,5 +565,5 @@ declare class SdLayoutModule {
492
565
  static ɵinj: _angular_core.ɵɵInjectorDeclaration<SdLayoutModule>;
493
566
  }
494
567
 
495
- export { DEFAULT_LAYOUT_MOBILE_BREAKPOINT, ForbiddenModule, HighlightSearchPipe, HomeModule, MenuFocusPipe, MenuPipe, NotFoundModule, SD_LAYOUT_CONFIGURATION, SD_LAYOUT_VIEWPORT, SdLayoutComponent, SdLayoutMenuTreeComponent, SdLayoutModule, SdLayoutNavigationStateService, SdLayoutResponsiveService, SdLayoutService, SdLayoutStorageService, SdLayoutUserMenuComponent, SdPageComponent, SidebarMobileOverlayComponent, SidebarMobileV1Component, SidebarMobileV2Component, SidebarMobileV3Component, SidebarV2Component, SidebarV3Component, flattenMenuLeaves, getMenuStableKey, normalizeLayoutMobileBreakpoint, normalizeSidebarConfiguration, resolveMenuKeys, resolveSidebarV2Interaction, resolveSidebarV3Recent, searchMenuLeaves, selectPrimaryMenuGroups };
496
- export type { ISdLayoutConfiguration, ISdSidebarConfiguration, Menus, ResolvedSidebarRecentConfiguration, SdLayoutChildrenMenu, SdLayoutMenu, SdLayoutRootMenu, SdLayoutUserInfo, SdLayoutVersionState, SdLayoutViewport, SidebarConfigurationBase, SidebarConfigurationV1, SidebarConfigurationV2, SidebarConfigurationV3 };
568
+ export { DEFAULT_LAYOUT_MOBILE_BREAKPOINT, ForbiddenModule, HighlightSearchPipe, HomeModule, MenuFocusPipe, MenuPipe, NotFoundModule, SD_LAYOUT_CONFIGURATION, SD_LAYOUT_VIEWPORT, SdLayoutComponent, SdLayoutMenuTreeComponent, SdLayoutModule, SdLayoutNavigationStateService, SdLayoutResponsiveService, SdLayoutService, SdLayoutStorageService, SdLayoutUserMenuComponent, SdPageComponent, SidebarMobileOverlayComponent, SidebarMobileV1Component, SidebarMobileV2Component, SidebarMobileV3Component, SidebarV2Component, SidebarV3Component, flattenMenuLeaves, getMenuStableKey, normalizeLayoutMobileBreakpoint, normalizeSidebarConfiguration, resolveMenuKeys, resolveSidebarV2Interaction, resolveSidebarV3Recent, resolveTabName, searchMenuLeaves, selectPrimaryMenuGroups };
569
+ export type { ISdLayoutConfiguration, ISdSidebarConfiguration, Menus, ResolvedSidebarRecentConfiguration, SdLayoutAccountAction, SdLayoutChildrenMenu, SdLayoutMenu, SdLayoutNotificationConfiguration, SdLayoutRootMenu, SdLayoutUserInfo, SdLayoutUserRole, SdLayoutVersionState, SdLayoutViewport, SidebarConfigurationBase, SidebarConfigurationV1, SidebarConfigurationV2, SidebarConfigurationV3 };
package/package.json CHANGED
@@ -1,7 +1,15 @@
1
1
  {
2
2
  "name": "@sdcorejs/angular",
3
- "version": "20.1.4",
3
+ "version": "20.1.6",
4
4
  "license": "MIT",
5
+ "repository": {
6
+ "type": "git",
7
+ "url": "git+https://github.com/sdcorejs/sdcorejs-angular.git"
8
+ },
9
+ "homepage": "https://sdcorejs.github.io/sdcorejs-angular/",
10
+ "bugs": {
11
+ "url": "https://github.com/sdcorejs/sdcorejs-angular/issues"
12
+ },
5
13
  "peerDependencies": {
6
14
  "@angular/common": "^19.0.0 || ^20.0.0 || ^21.0.0",
7
15
  "@angular/core": "^19.0.0 || ^20.0.0 || ^21.0.0",