@sd-angular/core 19.0.0-beta.70 → 19.0.0-beta.72

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.
Files changed (57) hide show
  1. package/assets/scss/ckeditor5.scss +1 -2
  2. package/components/modal/index.d.ts +1 -1
  3. package/components/modal/src/modal.component.d.ts +24 -0
  4. package/components/upload-file/src/configurations/upload-file.configuration.d.ts +33 -0
  5. package/components/upload-file/src/upload-file.component.d.ts +5 -2
  6. package/fesm2022/sd-angular-core-components-document-builder.mjs +1 -1
  7. package/fesm2022/sd-angular-core-components-document-builder.mjs.map +1 -1
  8. package/fesm2022/sd-angular-core-components-import-excel.mjs +1 -1
  9. package/fesm2022/sd-angular-core-components-import-excel.mjs.map +1 -1
  10. package/fesm2022/sd-angular-core-components-modal.mjs +57 -91
  11. package/fesm2022/sd-angular-core-components-modal.mjs.map +1 -1
  12. package/fesm2022/sd-angular-core-components-preview.mjs +1 -1
  13. package/fesm2022/sd-angular-core-components-preview.mjs.map +1 -1
  14. package/fesm2022/sd-angular-core-components-side-drawer.mjs +2 -2
  15. package/fesm2022/sd-angular-core-components-side-drawer.mjs.map +1 -1
  16. package/fesm2022/sd-angular-core-components-table.mjs +9 -7
  17. package/fesm2022/sd-angular-core-components-table.mjs.map +1 -1
  18. package/fesm2022/sd-angular-core-components-upload-file.mjs +62 -10
  19. package/fesm2022/sd-angular-core-components-upload-file.mjs.map +1 -1
  20. package/fesm2022/sd-angular-core-components-workflow.mjs +13 -13
  21. package/fesm2022/sd-angular-core-components-workflow.mjs.map +1 -1
  22. package/fesm2022/sd-angular-core-forms-chip-calendar.mjs +158 -197
  23. package/fesm2022/sd-angular-core-forms-chip-calendar.mjs.map +1 -1
  24. package/fesm2022/sd-angular-core-forms-chip.mjs +173 -203
  25. package/fesm2022/sd-angular-core-forms-chip.mjs.map +1 -1
  26. package/fesm2022/sd-angular-core-modules-layout.mjs +2 -3
  27. package/fesm2022/sd-angular-core-modules-layout.mjs.map +1 -1
  28. package/fesm2022/sd-angular-core-modules-permission.mjs +160 -74
  29. package/fesm2022/sd-angular-core-modules-permission.mjs.map +1 -1
  30. package/fesm2022/sd-angular-core.mjs +0 -1
  31. package/fesm2022/sd-angular-core.mjs.map +1 -1
  32. package/forms/chip/src/chip.component.d.ts +35 -44
  33. package/forms/chip-calendar/src/chip-calendar.component.d.ts +35 -42
  34. package/modules/layout/services/menu/menu.model.d.ts +1 -0
  35. package/modules/permission/src/configurations/permission.configuration.d.ts +56 -2
  36. package/modules/permission/src/directives/permission.directive.d.ts +5 -8
  37. package/modules/permission/src/guards/permission.guard.d.ts +2 -1
  38. package/modules/permission/src/services/permission.service.d.ts +6 -9
  39. package/package.json +44 -52
  40. package/public-api.d.ts +0 -1
  41. package/sd-angular-core-19.0.0-beta.72.tgz +0 -0
  42. package/components/modal/src/modal/modal.component.d.ts +0 -31
  43. package/fesm2022/sd-angular-core-guards-permission.mjs +0 -155
  44. package/fesm2022/sd-angular-core-guards-permission.mjs.map +0 -1
  45. package/fesm2022/sd-angular-core-guards.mjs +0 -6
  46. package/fesm2022/sd-angular-core-guards.mjs.map +0 -1
  47. package/guards/index.d.ts +0 -1
  48. package/guards/permission/index.d.ts +0 -4
  49. package/guards/permission/src/configurations/index.d.ts +0 -1
  50. package/guards/permission/src/configurations/permission.configuration.d.ts +0 -8
  51. package/guards/permission/src/directives/index.d.ts +0 -1
  52. package/guards/permission/src/directives/permission.directive.d.ts +0 -12
  53. package/guards/permission/src/guards/index.d.ts +0 -1
  54. package/guards/permission/src/guards/permission.guard.d.ts +0 -13
  55. package/guards/permission/src/services/index.d.ts +0 -1
  56. package/guards/permission/src/services/permission.service.d.ts +0 -15
  57. package/sd-angular-core-19.0.0-beta.70.tgz +0 -0
@@ -1,67 +1,144 @@
1
1
  import * as i0 from '@angular/core';
2
- import { InjectionToken, Inject, Injectable, Input, Directive } from '@angular/core';
2
+ import { InjectionToken, inject, Injectable, TemplateRef, ViewContainerRef, input, effect, Directive, Inject } from '@angular/core';
3
+ import { SdCacheService } from '@sd-angular/core/services/cache';
3
4
  import { ArrayUtilities } from '@sd-angular/core/utilities/extensions';
4
5
  import { SdResolveMaybeAsync } from '@sd-angular/core/utilities';
5
- import * as i1 from '@sd-angular/core/services/cache';
6
6
 
7
+ /**
8
+ * InjectionToken cho cấu hình permission.
9
+ *
10
+ * Ví dụ provider:
11
+ * {
12
+ * provide: SD_PERMISSION_CONFIGURATION,
13
+ * useValue: {
14
+ * disabled: false,
15
+ * loadPermissions: () => ['SAMPLE_C_EMPLOYEE_VIEW'],
16
+ * onForbiden: () => router.navigateByUrl('/layout/forbidden')
17
+ * }
18
+ * }
19
+ */
7
20
  const SD_PERMISSION_CONFIGURATION = new InjectionToken('sd-permission.configuration');
8
21
 
9
22
  class SdPermissionService {
10
- configuration;
11
- cacheService;
12
- #permission = {};
13
- #permissions;
14
- #loaded = false;
15
- constructor(configuration, cacheService) {
16
- this.configuration = configuration;
17
- this.cacheService = cacheService;
18
- this.#permissions = this.cacheService.create('212a51fa-38d5-43b2-bd46-922d85950ba3', {
19
- type: 'session',
20
- default: [],
21
- });
23
+ #permissionMapByKey = {};
24
+ #configuration = inject(SD_PERMISSION_CONFIGURATION);
25
+ #cacheService = inject(SdCacheService);
26
+ #permissionsByKey = this.#cacheService.create('212a51fa-38d5-43b2-bd46-922d85950ba3', {
27
+ type: 'session',
28
+ default: {},
29
+ });
30
+ #loadedKeys = new Set();
31
+ constructor() {
32
+ this.#validateDuplicateConfigKeys();
22
33
  }
23
- loadPermissions = async () => {
24
- if (!this.#loaded) {
25
- try {
26
- // Trả về Promise<string[]> nhưng chấp nhận mọi kiểu MaybeAsync
27
- const permissions = await SdResolveMaybeAsync(this.configuration.loadPermissions());
28
- const distinctPermissions = ArrayUtilities.distinct(permissions);
29
- this.#permissions.set(ArrayUtilities.distinct(permissions));
30
- // Chuyển sang dạng map để kiểm tra nhanh hơn
31
- this.#permission = {};
32
- distinctPermissions.forEach(p => (this.#permission[p] = true));
33
- this.#loaded = true;
34
- }
35
- catch (err) {
36
- console.error(err);
37
- this.#permissions.set([]);
38
- this.#permission = {};
39
- this.#loaded = true;
34
+ #getConfigurations = () => {
35
+ const config = this.#configuration;
36
+ if (!config) {
37
+ return [];
38
+ }
39
+ return Array.isArray(config) ? config : [config];
40
+ };
41
+ #normalizeKey = (key) => {
42
+ return key === undefined ? '__undefined__' : key;
43
+ };
44
+ #validateDuplicateConfigKeys = () => {
45
+ const seen = new Set();
46
+ for (const config of this.#getConfigurations()) {
47
+ const normalizedKey = this.#normalizeKey(config.key);
48
+ if (seen.has(normalizedKey)) {
49
+ const keyLabel = config.key === undefined ? 'undefined' : config.key;
50
+ throw new Error(`[Permission] Duplicate permission configuration key: ${keyLabel}`);
40
51
  }
52
+ seen.add(normalizedKey);
41
53
  }
42
54
  };
43
- hasPermission = (permission) => {
55
+ #getConfigurationByKey = (key) => {
56
+ return this.#getConfigurations().find(config => config.key === key);
57
+ };
58
+ #getEffectivePermissionKey = (key) => {
59
+ if (this.#getConfigurationByKey(key)) {
60
+ return key;
61
+ }
62
+ // Portal-level config uses key = undefined and acts as default fallback
63
+ if (key !== undefined && this.#getConfigurationByKey(undefined)) {
64
+ return undefined;
65
+ }
66
+ return key;
67
+ };
68
+ #setPermissionsForKey = (normalizedKey, permissions) => {
69
+ const distinctPermissions = ArrayUtilities.distinct(permissions || []);
70
+ const current = this.#permissionsByKey.get() || {};
71
+ this.#permissionsByKey.set({
72
+ ...current,
73
+ [normalizedKey]: distinctPermissions,
74
+ });
75
+ const permissionMap = {};
76
+ distinctPermissions.forEach(permission => {
77
+ permissionMap[permission] = true;
78
+ });
79
+ this.#permissionMapByKey[normalizedKey] = permissionMap;
80
+ };
81
+ loadPermissions = async (key) => {
82
+ const effectiveKey = this.#getEffectivePermissionKey(key);
83
+ const normalizedKey = this.#normalizeKey(effectiveKey);
84
+ if (this.#loadedKeys.has(normalizedKey)) {
85
+ return this.#permissionsByKey.get()?.[normalizedKey] || [];
86
+ }
87
+ const configuration = this.#getConfigurationByKey(effectiveKey);
88
+ if (!configuration) {
89
+ this.#setPermissionsForKey(normalizedKey, []);
90
+ this.#loadedKeys.add(normalizedKey);
91
+ return [];
92
+ }
93
+ try {
94
+ const permissions = await SdResolveMaybeAsync(configuration.loadPermissions());
95
+ this.#setPermissionsForKey(normalizedKey, permissions || []);
96
+ }
97
+ catch (err) {
98
+ console.error(err);
99
+ this.#setPermissionsForKey(normalizedKey, []);
100
+ }
101
+ finally {
102
+ this.#loadedKeys.add(normalizedKey);
103
+ }
104
+ return this.#permissionsByKey.get()?.[normalizedKey] || [];
105
+ };
106
+ loadAllPermissions = async () => {
107
+ const configurations = this.#getConfigurations();
108
+ if (!configurations.length) {
109
+ await this.loadPermissions(undefined);
110
+ return;
111
+ }
112
+ await Promise.all(configurations.map(config => this.loadPermissions(config.key)));
113
+ };
114
+ hasPermission = (permission, key) => {
44
115
  if (!permission?.toString()) {
45
116
  return true;
46
117
  }
47
- if (this.configuration.disabled) {
118
+ const effectiveKey = this.#getEffectivePermissionKey(key);
119
+ const configuration = this.#getConfigurationByKey(effectiveKey);
120
+ if (configuration?.disabled) {
48
121
  return true;
49
122
  }
123
+ const normalizedKey = this.#normalizeKey(effectiveKey);
124
+ const permissionMap = this.#permissionMapByKey[normalizedKey] || {};
50
125
  const permissions = Array.isArray(permission) ? permission : [permission];
51
- return permissions.some(permission => this.#permission[permission]);
126
+ return permissions.some(val => permissionMap[val]);
52
127
  };
53
- getToken = async () => {
54
- if (!this.configuration.getToken) {
128
+ getToken = async (key) => {
129
+ const effectiveKey = this.#getEffectivePermissionKey(key);
130
+ const getToken = this.#getConfigurationByKey(effectiveKey)?.getToken;
131
+ if (!getToken) {
55
132
  throw new Error('[Permission] Method getToken');
56
133
  }
57
- const token = this.configuration.getToken();
58
- if (token instanceof Promise) {
59
- return await token;
134
+ const token = await SdResolveMaybeAsync(getToken());
135
+ if (token === '') {
136
+ return undefined;
60
137
  }
61
138
  return token;
62
139
  };
63
- decodeToken = async () => {
64
- const token = await this.getToken();
140
+ decodeToken = async (key) => {
141
+ const token = await this.getToken(key);
65
142
  if (!token) {
66
143
  return null;
67
144
  }
@@ -79,49 +156,46 @@ class SdPermissionService {
79
156
  return null;
80
157
  }
81
158
  };
82
- static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "19.2.17", ngImport: i0, type: SdPermissionService, deps: [{ token: SD_PERMISSION_CONFIGURATION }, { token: i1.SdCacheService }], target: i0.ɵɵFactoryTarget.Injectable });
159
+ static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "19.2.17", ngImport: i0, type: SdPermissionService, deps: [], target: i0.ɵɵFactoryTarget.Injectable });
83
160
  static ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "19.2.17", ngImport: i0, type: SdPermissionService, providedIn: 'root' });
84
161
  }
85
162
  i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.2.17", ngImport: i0, type: SdPermissionService, decorators: [{
86
163
  type: Injectable,
87
164
  args: [{ providedIn: 'root' }]
88
- }], ctorParameters: () => [{ type: undefined, decorators: [{
89
- type: Inject,
90
- args: [SD_PERMISSION_CONFIGURATION]
91
- }] }, { type: i1.SdCacheService }] });
165
+ }], ctorParameters: () => [] });
92
166
 
93
167
  class SdPermissionDirective {
94
- templateRef;
95
- viewContainerRef;
96
- permissionService;
168
+ #templateRef = inject(TemplateRef);
169
+ #viewContainerRef = inject(ViewContainerRef);
170
+ #permissionService = inject(SdPermissionService);
97
171
  // Nếu là mảng thì chỉ cần có 1 permission trong mảng đó xem như có quyền
98
- set sdPermission(permission) {
99
- // Nếu không gắn permisison thì render
100
- if (!permission?.toString()) {
101
- this.viewContainerRef.createEmbeddedView(this.templateRef);
102
- return;
103
- }
104
- // Kiểm tra permisison
105
- if (this.permissionService.hasPermission(permission)) {
106
- this.viewContainerRef.createEmbeddedView(this.templateRef);
107
- }
108
- }
109
- constructor(templateRef, viewContainerRef, permissionService) {
110
- this.templateRef = templateRef;
111
- this.viewContainerRef = viewContainerRef;
112
- this.permissionService = permissionService;
172
+ sdPermission = input(undefined);
173
+ sdPermissionKey = input(undefined);
174
+ constructor() {
175
+ effect(() => {
176
+ const permission = this.sdPermission();
177
+ const permissionKey = this.sdPermissionKey();
178
+ this.#viewContainerRef.clear();
179
+ // Nếu không gắn permission thì render
180
+ if (!permission?.toString()) {
181
+ this.#viewContainerRef.createEmbeddedView(this.#templateRef);
182
+ return;
183
+ }
184
+ // Kiểm tra permission theo key (nếu có)
185
+ if (this.#permissionService.hasPermission(permission, permissionKey)) {
186
+ this.#viewContainerRef.createEmbeddedView(this.#templateRef);
187
+ }
188
+ });
113
189
  }
114
- static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "19.2.17", ngImport: i0, type: SdPermissionDirective, deps: [{ token: i0.TemplateRef }, { token: i0.ViewContainerRef }, { token: SdPermissionService }], target: i0.ɵɵFactoryTarget.Directive });
115
- static ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "14.0.0", version: "19.2.17", type: SdPermissionDirective, isStandalone: true, selector: "[sdPermission]", inputs: { sdPermission: "sdPermission" }, ngImport: i0 });
190
+ static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "19.2.17", ngImport: i0, type: SdPermissionDirective, deps: [], target: i0.ɵɵFactoryTarget.Directive });
191
+ static ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "17.1.0", version: "19.2.17", type: SdPermissionDirective, isStandalone: true, selector: "[sdPermission]", inputs: { sdPermission: { classPropertyName: "sdPermission", publicName: "sdPermission", isSignal: true, isRequired: false, transformFunction: null }, sdPermissionKey: { classPropertyName: "sdPermissionKey", publicName: "sdPermissionKey", isSignal: true, isRequired: false, transformFunction: null } }, ngImport: i0 });
116
192
  }
117
193
  i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.2.17", ngImport: i0, type: SdPermissionDirective, decorators: [{
118
194
  type: Directive,
119
195
  args: [{
120
196
  selector: '[sdPermission]',
121
197
  }]
122
- }], ctorParameters: () => [{ type: i0.TemplateRef }, { type: i0.ViewContainerRef }, { type: SdPermissionService }], propDecorators: { sdPermission: [{
123
- type: Input
124
- }] } });
198
+ }], ctorParameters: () => [] });
125
199
 
126
200
  class SdPermissionGuard {
127
201
  configuration;
@@ -130,18 +204,30 @@ class SdPermissionGuard {
130
204
  this.configuration = configuration;
131
205
  this.permissionService = permissionService;
132
206
  }
207
+ #getConfigurations = () => {
208
+ const config = this.configuration;
209
+ if (!config) {
210
+ return [];
211
+ }
212
+ return Array.isArray(config) ? config : [config];
213
+ };
133
214
  canActivate = async (next, state) => {
134
- // Đảm bảo permission đã được loaded
135
- await this.permissionService.loadPermissions().catch(console.error);
215
+ // Guard layer portal: preload toàn bộ permission theo tất cả key đã cấu hình
216
+ await this.permissionService.loadAllPermissions().catch(console.error);
136
217
  return true;
137
218
  };
138
219
  canActivateChild = async (activatedRoute, state) => {
139
220
  const permission = activatedRoute.data['permission'];
140
- if (this.permissionService.hasPermission(permission)) {
221
+ const permissionKey = activatedRoute.data?.['permissionKey'];
222
+ if (this.permissionService.hasPermission(permission, permissionKey)) {
141
223
  return true;
142
224
  }
143
- //
144
- this.configuration?.onForbiden?.();
225
+ const configurations = this.#getConfigurations();
226
+ const onForbiden = configurations
227
+ .filter(config => config.key === permissionKey || (permissionKey !== undefined && config.key === undefined))
228
+ .map(config => config.onForbiden)
229
+ .find(val => !!val);
230
+ onForbiden?.();
145
231
  return false;
146
232
  };
147
233
  static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "19.2.17", ngImport: i0, type: SdPermissionGuard, deps: [{ token: SD_PERMISSION_CONFIGURATION }, { token: SdPermissionService }], target: i0.ɵɵFactoryTarget.Injectable });
@@ -1 +1 @@
1
- {"version":3,"file":"sd-angular-core-modules-permission.mjs","sources":["../../../projects/sd-angular/modules/permission/src/configurations/permission.configuration.ts","../../../projects/sd-angular/modules/permission/src/services/permission.service.ts","../../../projects/sd-angular/modules/permission/src/directives/permission.directive.ts","../../../projects/sd-angular/modules/permission/src/guards/permission.guard.ts","../../../projects/sd-angular/modules/permission/sd-angular-core-modules-permission.ts"],"sourcesContent":["import { InjectionToken } from '@angular/core';\r\nimport { SdMaybeAsync } from '@sd-angular/core/utilities';\r\n\r\nexport interface ISdPermissionConfiguration {\r\n disabled?: boolean; // Vô hiệu việc kiểm tra permission, mục đích để test chức năng khi chưa có permisison\r\n loadPermissions: () => SdMaybeAsync<string[]>;\r\n onForbiden?: () => void; // Xử lý khi không có quyền truy cập vào URL\r\n getToken?: () => Promise<string | undefined | null> | string | undefined | null; // Lấy thông tin token\r\n}\r\n\r\nexport const SD_PERMISSION_CONFIGURATION = new InjectionToken<ISdPermissionConfiguration>('sd-permission.configuration');\r\n","import { Inject, Injectable } from '@angular/core';\r\nimport { SdCache, SdCacheService } from '@sd-angular/core/services/cache';\r\nimport { ArrayUtilities } from '@sd-angular/core/utilities/extensions';\r\nimport { ISdPermissionConfiguration, SD_PERMISSION_CONFIGURATION } from '../configurations';\r\nimport { SdResolveMaybeAsync } from '@sd-angular/core/utilities';\r\n\r\n@Injectable({ providedIn: 'root' })\r\nexport class SdPermissionService {\r\n #permission: Record<string, boolean> = {};\r\n #permissions: SdCache<string[]>;\r\n #loaded = false;\r\n constructor(\r\n @Inject(SD_PERMISSION_CONFIGURATION) private configuration: ISdPermissionConfiguration,\r\n private cacheService: SdCacheService\r\n ) {\r\n this.#permissions = this.cacheService.create<string[]>('212a51fa-38d5-43b2-bd46-922d85950ba3', {\r\n type: 'session',\r\n default: [],\r\n });\r\n }\r\n\r\n loadPermissions = async () => {\r\n if (!this.#loaded) {\r\n try {\r\n // Trả về Promise<string[]> nhưng chấp nhận mọi kiểu MaybeAsync\r\n const permissions: string[] = await SdResolveMaybeAsync(this.configuration.loadPermissions());\r\n const distinctPermissions = ArrayUtilities.distinct(permissions);\r\n this.#permissions.set(ArrayUtilities.distinct(permissions));\r\n // Chuyển sang dạng map để kiểm tra nhanh hơn\r\n this.#permission = {};\r\n distinctPermissions.forEach(p => (this.#permission[p] = true));\r\n this.#loaded = true;\r\n } catch (err) {\r\n console.error(err);\r\n this.#permissions.set([]);\r\n this.#permission = {};\r\n this.#loaded = true;\r\n }\r\n }\r\n };\r\n\r\n hasPermission = (permission: string | string[]) => {\r\n if (!permission?.toString()) {\r\n return true;\r\n }\r\n if (this.configuration.disabled) {\r\n return true;\r\n }\r\n const permissions = Array.isArray(permission) ? permission : [permission];\r\n return permissions.some(permission => this.#permission[permission]);\r\n };\r\n\r\n getToken = async () => {\r\n if (!this.configuration.getToken) {\r\n throw new Error('[Permission] Method getToken');\r\n }\r\n const token = this.configuration.getToken();\r\n if (token instanceof Promise) {\r\n return await token;\r\n }\r\n return token;\r\n };\r\n\r\n decodeToken = async <T>(): Promise<T | null> => {\r\n const token = await this.getToken();\r\n if (!token) {\r\n return null;\r\n }\r\n try {\r\n const payload = token.split('.')[1];\r\n const base64 = payload.replace(/-/g, '+').replace(/_/g, '/');\r\n const jsonPayload = decodeURIComponent(\r\n atob(base64)\r\n .split('')\r\n .map(c => '%' + ('00' + c.charCodeAt(0).toString(16)).slice(-2))\r\n .join('')\r\n );\r\n return JSON.parse(jsonPayload);\r\n } catch (error) {\r\n console.error('Invalid token', error);\r\n return null;\r\n }\r\n };\r\n}\r\n","import { Directive, Input, TemplateRef, ViewContainerRef } from '@angular/core';\r\nimport { SdPermissionService } from '../services';\r\n\r\n@Directive({\r\n selector: '[sdPermission]',\r\n})\r\nexport class SdPermissionDirective {\r\n // Nếu là mảng thì chỉ cần có 1 permission trong mảng đó xem như có quyền\r\n @Input() set sdPermission(permission: string | string[] | undefined | null) {\r\n // Nếu không gắn permisison thì render\r\n if (!permission?.toString()) {\r\n this.viewContainerRef.createEmbeddedView(this.templateRef);\r\n return;\r\n }\r\n // Kiểm tra permisison\r\n if (this.permissionService.hasPermission(permission)) {\r\n this.viewContainerRef.createEmbeddedView(this.templateRef);\r\n }\r\n }\r\n\r\n constructor(\r\n private templateRef: TemplateRef<any>,\r\n private viewContainerRef: ViewContainerRef,\r\n private permissionService: SdPermissionService\r\n ) {}\r\n}\r\n","import { Inject, Injectable } from '@angular/core';\r\nimport { ActivatedRouteSnapshot, CanActivate, CanActivateChild, RouterStateSnapshot } from '@angular/router';\r\nimport { ISdPermissionConfiguration, SD_PERMISSION_CONFIGURATION } from '../configurations';\r\nimport { SdPermissionService } from '../services';\r\n\r\n@Injectable({ providedIn: 'root' })\r\nexport class SdPermissionGuard implements CanActivate, CanActivateChild {\r\n constructor(\r\n @Inject(SD_PERMISSION_CONFIGURATION)\r\n private configuration: ISdPermissionConfiguration,\r\n private permissionService: SdPermissionService\r\n ) {}\r\n\r\n canActivate = async (next: ActivatedRouteSnapshot, state: RouterStateSnapshot) => {\r\n // Đảm bảo permission đã được loaded\r\n await this.permissionService.loadPermissions().catch(console.error);\r\n return true;\r\n };\r\n\r\n canActivateChild = async (activatedRoute: ActivatedRouteSnapshot, state: RouterStateSnapshot) => {\r\n const permission = activatedRoute.data['permission'];\r\n if (this.permissionService.hasPermission(permission)) {\r\n return true;\r\n }\r\n //\r\n this.configuration?.onForbiden?.();\r\n return false;\r\n };\r\n}\r\n","/**\n * Generated bundle index. Do not edit.\n */\n\nexport * from './index';\n"],"names":["i1.SdPermissionService"],"mappings":"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"}
1
+ {"version":3,"file":"sd-angular-core-modules-permission.mjs","sources":["../../../projects/sd-angular/modules/permission/src/configurations/permission.configuration.ts","../../../projects/sd-angular/modules/permission/src/services/permission.service.ts","../../../projects/sd-angular/modules/permission/src/directives/permission.directive.ts","../../../projects/sd-angular/modules/permission/src/guards/permission.guard.ts","../../../projects/sd-angular/modules/permission/sd-angular-core-modules-permission.ts"],"sourcesContent":["import { InjectionToken } from '@angular/core';\r\nimport { SdMaybeAsync } from '@sd-angular/core/utilities';\r\n\r\n/**\r\n * Cấu hình trung tâm cho module permission.\r\n *\r\n * Luồng hoạt động chính:\r\n * 1. `loadPermissions(key?)` ở service được gọi để lấy danh sách mã quyền theo từng `key` cấu hình.\r\n * 2. Guard/service đối chiếu mã quyền theo route metadata.\r\n * 3. Khi không đủ quyền, callback `onForbiden()` sẽ được gọi (nếu có).\r\n *\r\n * Lưu ý:\r\n * - `SD_PERMISSION_CONFIGURATION` hỗ trợ cả cấu hình đơn và mảng cấu hình (`multi: true`).\r\n * - Nếu cần tạm bỏ qua kiểm tra quyền (POC/UAT cục bộ), đặt `disabled = true`.\r\n */\r\nexport interface ISdPermissionConfiguration {\r\n /**\r\n * Khóa định danh cấu hình.\r\n * Dùng để phân biệt khi hệ thống mở rộng theo nhiều profile permission.\r\n *\r\n * Lưu ý: `undefined` cũng được xem là một key hợp lệ (cấu hình mặc định).\r\n */\r\n key?: string;\r\n\r\n /**\r\n * Bật/tắt kiểm tra permission toàn cục.\r\n * - `true`: bỏ qua kiểm tra quyền.\r\n * - `false | undefined`: kiểm tra quyền theo cấu hình route.\r\n */\r\n disabled?: boolean;\r\n\r\n /**\r\n * Trả về danh sách mã quyền của user hiện tại.\r\n * Có thể đồng bộ hoặc bất đồng bộ.\r\n *\r\n * Ví dụ giá trị trả về:\r\n * - `['PRODUCT_C_EMPLOYEE_VIEW', 'PRODUCT_C_EMPLOYEE_UPDATE']`\r\n */\r\n loadPermissions: () => SdMaybeAsync<string[]>;\r\n\r\n /**\r\n * Callback xử lý khi user không có quyền truy cập URL hiện tại.\r\n * Thường dùng để điều hướng sang trang forbidden hoặc hiển thị thông báo.\r\n *\r\n * Giữ nguyên tên `onForbiden` để tương thích API hiện tại.\r\n */\r\n onForbiden?: () => void;\r\n\r\n /**\r\n * Cung cấp access token hiện tại cho các tác vụ liên quan permission.\r\n * Hỗ trợ trả về đồng bộ, Promise hoặc Observable.\r\n */\r\n getToken?: () => SdMaybeAsync<string | undefined | null>;\r\n}\r\n\r\n/**\r\n * InjectionToken cho cấu hình permission.\r\n *\r\n * Ví dụ provider:\r\n * {\r\n * provide: SD_PERMISSION_CONFIGURATION,\r\n * useValue: {\r\n * disabled: false,\r\n * loadPermissions: () => ['SAMPLE_C_EMPLOYEE_VIEW'],\r\n * onForbiden: () => router.navigateByUrl('/layout/forbidden')\r\n * }\r\n * }\r\n */\r\nexport const SD_PERMISSION_CONFIGURATION =\r\n new InjectionToken<ISdPermissionConfiguration | ISdPermissionConfiguration[]>('sd-permission.configuration');\r\n","import { inject, Injectable } from '@angular/core';\r\nimport { SdCache, SdCacheService } from '@sd-angular/core/services/cache';\r\nimport { ArrayUtilities } from '@sd-angular/core/utilities/extensions';\r\nimport { ISdPermissionConfiguration, SD_PERMISSION_CONFIGURATION } from '../configurations';\r\nimport { SdMaybeAsync, SdResolveMaybeAsync } from '@sd-angular/core/utilities';\r\n\r\n@Injectable({ providedIn: 'root' })\r\nexport class SdPermissionService {\r\n #permissionMapByKey: Record<string, Record<string, boolean>> = {};\r\n readonly #configuration = inject<ISdPermissionConfiguration | ISdPermissionConfiguration[]>(SD_PERMISSION_CONFIGURATION);\r\n readonly #cacheService = inject(SdCacheService);\r\n #permissionsByKey: SdCache<Record<string, string[]>> = this.#cacheService.create<Record<string, string[]>>('212a51fa-38d5-43b2-bd46-922d85950ba3', {\r\n type: 'session',\r\n default: {},\r\n });\r\n readonly #loadedKeys = new Set<string>();\r\n\r\n constructor() {\r\n this.#validateDuplicateConfigKeys();\r\n }\r\n\r\n #getConfigurations = (): ISdPermissionConfiguration[] => {\r\n const config = this.#configuration;\r\n if (!config) {\r\n return [];\r\n }\r\n return Array.isArray(config) ? config : [config];\r\n };\r\n\r\n #normalizeKey = (key?: string): string => {\r\n return key === undefined ? '__undefined__' : key;\r\n };\r\n\r\n #validateDuplicateConfigKeys = (): void => {\r\n const seen = new Set<string>();\r\n for (const config of this.#getConfigurations()) {\r\n const normalizedKey = this.#normalizeKey(config.key);\r\n if (seen.has(normalizedKey)) {\r\n const keyLabel = config.key === undefined ? 'undefined' : config.key;\r\n throw new Error(`[Permission] Duplicate permission configuration key: ${keyLabel}`);\r\n }\r\n seen.add(normalizedKey);\r\n }\r\n };\r\n\r\n #getConfigurationByKey = (key?: string): ISdPermissionConfiguration | undefined => {\r\n return this.#getConfigurations().find(config => config.key === key);\r\n };\r\n\r\n #getEffectivePermissionKey = (key?: string): string | undefined => {\r\n if (this.#getConfigurationByKey(key)) {\r\n return key;\r\n }\r\n\r\n // Portal-level config uses key = undefined and acts as default fallback\r\n if (key !== undefined && this.#getConfigurationByKey(undefined)) {\r\n return undefined;\r\n }\r\n\r\n return key;\r\n };\r\n\r\n #setPermissionsForKey = (normalizedKey: string, permissions: string[]): void => {\r\n const distinctPermissions = ArrayUtilities.distinct(permissions || []);\r\n const current = this.#permissionsByKey.get() || {};\r\n this.#permissionsByKey.set({\r\n ...current,\r\n [normalizedKey]: distinctPermissions,\r\n });\r\n\r\n const permissionMap: Record<string, boolean> = {};\r\n distinctPermissions.forEach(permission => {\r\n permissionMap[permission] = true;\r\n });\r\n this.#permissionMapByKey[normalizedKey] = permissionMap;\r\n };\r\n\r\n loadPermissions = async (key?: string): Promise<string[]> => {\r\n const effectiveKey = this.#getEffectivePermissionKey(key);\r\n const normalizedKey = this.#normalizeKey(effectiveKey);\r\n if (this.#loadedKeys.has(normalizedKey)) {\r\n return this.#permissionsByKey.get()?.[normalizedKey] || [];\r\n }\r\n\r\n const configuration = this.#getConfigurationByKey(effectiveKey);\r\n if (!configuration) {\r\n this.#setPermissionsForKey(normalizedKey, []);\r\n this.#loadedKeys.add(normalizedKey);\r\n return [];\r\n }\r\n\r\n try {\r\n const permissions: string[] = await SdResolveMaybeAsync(configuration.loadPermissions());\r\n this.#setPermissionsForKey(normalizedKey, permissions || []);\r\n } catch (err) {\r\n console.error(err);\r\n this.#setPermissionsForKey(normalizedKey, []);\r\n } finally {\r\n this.#loadedKeys.add(normalizedKey);\r\n }\r\n\r\n return this.#permissionsByKey.get()?.[normalizedKey] || [];\r\n };\r\n\r\n loadAllPermissions = async (): Promise<void> => {\r\n const configurations = this.#getConfigurations();\r\n if (!configurations.length) {\r\n await this.loadPermissions(undefined);\r\n return;\r\n }\r\n\r\n await Promise.all(configurations.map(config => this.loadPermissions(config.key)));\r\n };\r\n\r\n hasPermission = (permission: string | string[], key?: string) => {\r\n if (!permission?.toString()) {\r\n return true;\r\n }\r\n\r\n const effectiveKey = this.#getEffectivePermissionKey(key);\r\n const configuration = this.#getConfigurationByKey(effectiveKey);\r\n if (configuration?.disabled) {\r\n return true;\r\n }\r\n\r\n const normalizedKey = this.#normalizeKey(effectiveKey);\r\n const permissionMap = this.#permissionMapByKey[normalizedKey] || {};\r\n const permissions = Array.isArray(permission) ? permission : [permission];\r\n return permissions.some(val => permissionMap[val]);\r\n };\r\n\r\n getToken = async (key?: string) => {\r\n const effectiveKey = this.#getEffectivePermissionKey(key);\r\n const getToken = this.#getConfigurationByKey(effectiveKey)?.getToken as (() => SdMaybeAsync<string | undefined | null>) | undefined;\r\n if (!getToken) {\r\n throw new Error('[Permission] Method getToken');\r\n }\r\n\r\n const token = await SdResolveMaybeAsync(getToken());\r\n if (token === '') {\r\n return undefined;\r\n }\r\n return token;\r\n };\r\n\r\n decodeToken = async <T>(key?: string): Promise<T | null> => {\r\n const token = await this.getToken(key);\r\n if (!token) {\r\n return null;\r\n }\r\n try {\r\n const payload = token.split('.')[1];\r\n const base64 = payload.replace(/-/g, '+').replace(/_/g, '/');\r\n const jsonPayload = decodeURIComponent(\r\n atob(base64)\r\n .split('')\r\n .map(c => '%' + ('00' + c.charCodeAt(0).toString(16)).slice(-2))\r\n .join('')\r\n );\r\n return JSON.parse(jsonPayload);\r\n } catch (error) {\r\n console.error('Invalid token', error);\r\n return null;\r\n }\r\n };\r\n}\r\n","import { Directive, effect, inject, input, TemplateRef, ViewContainerRef } from '@angular/core';\r\nimport { SdPermissionService } from '../services';\r\n\r\n@Directive({\r\n selector: '[sdPermission]',\r\n})\r\nexport class SdPermissionDirective {\r\n readonly #templateRef = inject<TemplateRef<any>>(TemplateRef);\r\n readonly #viewContainerRef = inject(ViewContainerRef);\r\n readonly #permissionService = inject(SdPermissionService);\r\n\r\n // Nếu là mảng thì chỉ cần có 1 permission trong mảng đó xem như có quyền\r\n readonly sdPermission = input<string | string[] | undefined | null>(undefined);\r\n readonly sdPermissionKey = input<string | undefined>(undefined);\r\n\r\n constructor() {\r\n effect(() => {\r\n const permission = this.sdPermission();\r\n const permissionKey = this.sdPermissionKey();\r\n\r\n this.#viewContainerRef.clear();\r\n\r\n // Nếu không gắn permission thì render\r\n if (!permission?.toString()) {\r\n this.#viewContainerRef.createEmbeddedView(this.#templateRef);\r\n return;\r\n }\r\n\r\n // Kiểm tra permission theo key (nếu có)\r\n if (this.#permissionService.hasPermission(permission, permissionKey)) {\r\n this.#viewContainerRef.createEmbeddedView(this.#templateRef);\r\n }\r\n });\r\n }\r\n}\r\n","import { Inject, Injectable } from '@angular/core';\r\nimport { ActivatedRouteSnapshot, CanActivate, CanActivateChild, RouterStateSnapshot } from '@angular/router';\r\nimport { ISdPermissionConfiguration, SD_PERMISSION_CONFIGURATION } from '../configurations';\r\nimport { SdPermissionService } from '../services';\r\n\r\n@Injectable({ providedIn: 'root' })\r\nexport class SdPermissionGuard implements CanActivate, CanActivateChild {\r\n constructor(\r\n @Inject(SD_PERMISSION_CONFIGURATION)\r\n private configuration: ISdPermissionConfiguration | ISdPermissionConfiguration[],\r\n private permissionService: SdPermissionService\r\n ) {}\r\n\r\n #getConfigurations = (): ISdPermissionConfiguration[] => {\r\n const config = this.configuration;\r\n if (!config) {\r\n return [];\r\n }\r\n return Array.isArray(config) ? config : [config];\r\n };\r\n\r\n canActivate = async (next: ActivatedRouteSnapshot, state: RouterStateSnapshot) => {\r\n // Guard ở layer portal: preload toàn bộ permission theo tất cả key đã cấu hình\r\n await this.permissionService.loadAllPermissions().catch(console.error);\r\n return true;\r\n };\r\n\r\n canActivateChild = async (activatedRoute: ActivatedRouteSnapshot, state: RouterStateSnapshot) => {\r\n const permission = activatedRoute.data['permission'];\r\n const permissionKey = activatedRoute.data?.['permissionKey'] as string | undefined;\r\n if (this.permissionService.hasPermission(permission, permissionKey)) {\r\n return true;\r\n }\r\n\r\n const configurations = this.#getConfigurations();\r\n const onForbiden = configurations\r\n .filter(config => config.key === permissionKey || (permissionKey !== undefined && config.key === undefined))\r\n .map(config => config.onForbiden)\r\n .find(val => !!val);\r\n onForbiden?.();\r\n return false;\r\n };\r\n}\r\n","/**\n * Generated bundle index. Do not edit.\n */\n\nexport * from './index';\n"],"names":["i1.SdPermissionService"],"mappings":"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"}
@@ -2,7 +2,6 @@ import '@sd-angular/core/configurations';
2
2
  import '@sd-angular/core/utilities';
3
3
  import '@sd-angular/core/pipes';
4
4
  import '@sd-angular/core/directives';
5
- import '@sd-angular/core/guards';
6
5
  import '@sd-angular/core/services';
7
6
  import '@sd-angular/core/interceptors';
8
7
  import '@sd-angular/core/handlers';
@@ -1 +1 @@
1
- {"version":3,"file":"sd-angular-core.mjs","sources":["../../../projects/sd-angular/src/public-api.ts","../../../projects/sd-angular/src/sd-angular-core.ts"],"sourcesContent":["/*\n * Public API Surface of sd-angular\n */\nimport '@sd-angular/core/configurations';\nimport '@sd-angular/core/utilities';\nimport '@sd-angular/core/pipes';\nimport '@sd-angular/core/directives';\nimport '@sd-angular/core/guards';\nimport '@sd-angular/core/services';\nimport '@sd-angular/core/interceptors';\nimport '@sd-angular/core/handlers';\nimport '@sd-angular/core/components';\nimport '@sd-angular/core/forms';\nimport '@sd-angular/core/modules';","/**\n * Generated bundle index. Do not edit.\n */\n\nexport * from './public-api';\n"],"names":[],"mappings":";;;;;;;;;;;;AAAA;;AAEG;;ACFH;;AAEG"}
1
+ {"version":3,"file":"sd-angular-core.mjs","sources":["../../../projects/sd-angular/src/public-api.ts","../../../projects/sd-angular/src/sd-angular-core.ts"],"sourcesContent":["/*\n * Public API Surface of sd-angular\n */\nimport '@sd-angular/core/configurations';\nimport '@sd-angular/core/utilities';\nimport '@sd-angular/core/pipes';\nimport '@sd-angular/core/directives';\nimport '@sd-angular/core/services';\nimport '@sd-angular/core/interceptors';\nimport '@sd-angular/core/handlers';\nimport '@sd-angular/core/components';\nimport '@sd-angular/core/forms';\nimport '@sd-angular/core/modules';","/**\n * Generated bundle index. Do not edit.\n */\n\nexport * from './public-api';\n"],"names":[],"mappings":";;;;;;;;;;;AAAA;;AAEG;;ACFH;;AAEG"}
@@ -1,4 +1,4 @@
1
- import { AfterViewInit, ChangeDetectorRef, ElementRef, EventEmitter, OnDestroy } from '@angular/core';
1
+ import { AfterViewInit, ElementRef, TemplateRef } from '@angular/core';
2
2
  import { FormControl, FormGroup, FormGroupDirective, NgForm } from '@angular/forms';
3
3
  import { MatAutocompleteSelectedEvent } from '@angular/material/autocomplete';
4
4
  import { MatChipInputEvent } from '@angular/material/chips';
@@ -8,59 +8,50 @@ import { SdLabelDefDirective, SdViewDefDirective } from '@sd-angular/core/forms/
8
8
  import { SdFormControl } from '@sd-angular/core/forms/models';
9
9
  import { SdSize } from '@sd-angular/core/utilities';
10
10
  import * as i0 from "@angular/core";
11
- declare class SdChipErrotStateMatcher implements ErrorStateMatcher {
11
+ declare class SdChipErrorStateMatcher implements ErrorStateMatcher {
12
12
  private formControl;
13
13
  constructor(formControl: FormControl);
14
14
  isErrorState(control: FormControl | null, form: FormGroupDirective | NgForm | null): boolean;
15
15
  }
16
- export declare class SdChip implements OnDestroy, AfterViewInit {
16
+ export declare class SdChip implements AfterViewInit {
17
17
  #private;
18
- private ref;
19
- autoId?: string;
20
- set _autoId(val: string | undefined | null);
21
- set _name(val: string | undefined);
22
- appearance: MatFormFieldAppearance;
23
- floatLabel: FloatLabelType;
24
- separatorKeysCodes: number[];
25
- selectable: boolean;
26
- size: SdSize;
27
- set form(val: NgForm | FormGroup);
28
- addable: boolean;
29
- set _addable(val: boolean | '' | undefined | null);
30
- label: string;
31
- placeholder?: string;
32
- removable: boolean | ((item: any) => boolean);
33
- set _removable(val: '' | boolean | ((item: any) => boolean));
34
- hideInlineError: boolean;
35
- set _hideInlineError(val: boolean | '' | undefined | null);
36
- set model(values: undefined | (string | number)[]);
37
- required: boolean;
38
- set _required(val: boolean | '' | undefined | null);
39
- min: number;
40
- set pMin(val: number | string);
41
- max: number;
42
- set pMax(val: number | string);
43
- modelChange: EventEmitter<any>;
44
- set disabled(val: boolean | '' | undefined | null);
45
- sdChange: EventEmitter<any[]>;
18
+ autoId: import("@angular/core").InputSignal<string | undefined>;
19
+ name: import("@angular/core").InputSignal<string | undefined>;
20
+ appearance: import("@angular/core").InputSignal<MatFormFieldAppearance>;
21
+ floatLabel: import("@angular/core").InputSignal<FloatLabelType>;
22
+ size: import("@angular/core").InputSignal<SdSize>;
23
+ form: import("@angular/core").InputSignal<NgForm | FormGroup<any> | undefined>;
24
+ label: import("@angular/core").InputSignal<string>;
25
+ placeholder: import("@angular/core").InputSignal<string | undefined>;
26
+ removable: import("@angular/core").InputSignal<boolean | ((item: any) => boolean)>;
27
+ hideInlineError: import("@angular/core").InputSignalWithTransform<boolean, unknown>;
28
+ model: import("@angular/core").InputSignal<(string | number)[] | undefined>;
29
+ required: import("@angular/core").InputSignalWithTransform<boolean, unknown>;
30
+ min: import("@angular/core").InputSignal<number>;
31
+ max: import("@angular/core").InputSignal<number>;
32
+ addable: import("@angular/core").InputSignalWithTransform<boolean, unknown>;
33
+ disabled: import("@angular/core").InputSignalWithTransform<boolean, unknown>;
34
+ viewed: import("@angular/core").InputSignalWithTransform<boolean, unknown>;
35
+ hyperlink: import("@angular/core").InputSignal<string | null | undefined>;
36
+ modelChange: import("@angular/core").OutputEmitterRef<any[]>;
37
+ sdChange: import("@angular/core").OutputEmitterRef<any[]>;
46
38
  input: ElementRef<HTMLInputElement>;
47
- sdView?: SdViewDefDirective;
48
- sdLabelDef?: SdLabelDefDirective;
49
- isBlurring: boolean;
39
+ sdViewDef: import("@angular/core").Signal<SdViewDefDirective | undefined>;
40
+ sdLabelDef: import("@angular/core").Signal<SdLabelDefDirective | undefined>;
41
+ sdLabelTemplate: import("@angular/core").Signal<TemplateRef<any> | undefined>;
42
+ sdValueTemplate: import("@angular/core").Signal<TemplateRef<any> | undefined>;
50
43
  isFocused: boolean;
51
- inputControl: FormControl<any>;
52
- formControl: SdFormControl;
53
- matcher: SdChipErrotStateMatcher;
54
- /**
55
- * Tổng hợp error message để hiển thị trong tooltip khi hideInlineError = true.
56
- * Dùng getter (không phải computed) vì đây là component cũ dùng @Input decorator.
57
- */
44
+ readonly separatorKeysCodes: number[];
45
+ readonly selectable = true;
46
+ constructor();
47
+ get formControl(): SdFormControl;
48
+ get inputControl(): FormControl<any>;
58
49
  get errorTooltipMessage(): string | undefined;
59
- constructor(ref: ChangeDetectorRef);
50
+ get matcher(): SdChipErrorStateMatcher;
60
51
  ngAfterViewInit(): void;
61
52
  ngOnDestroy(): void;
62
53
  onAdd: (event: MatChipInputEvent) => void;
63
- onClickChip: ($event: Event, item: any) => void;
54
+ onClickChip: (event: Event, item: any) => void;
64
55
  onRemove: (item: any) => void;
65
56
  onSelect: (event: MatAutocompleteSelectedEvent) => void;
66
57
  onFocus: () => void;
@@ -69,6 +60,6 @@ export declare class SdChip implements OnDestroy, AfterViewInit {
69
60
  focus: () => void;
70
61
  onClear: ($event?: any) => void;
71
62
  static ɵfac: i0.ɵɵFactoryDeclaration<SdChip, never>;
72
- static ɵcmp: i0.ɵɵComponentDeclaration<SdChip, "sd-chip", never, { "_autoId": { "alias": "autoId"; "required": false; }; "_name": { "alias": "name"; "required": false; }; "appearance": { "alias": "appearance"; "required": false; }; "floatLabel": { "alias": "floatLabel"; "required": false; }; "size": { "alias": "size"; "required": false; }; "form": { "alias": "form"; "required": false; }; "_addable": { "alias": "addable"; "required": false; }; "label": { "alias": "label"; "required": false; }; "placeholder": { "alias": "placeholder"; "required": false; }; "_removable": { "alias": "removable"; "required": false; }; "_hideInlineError": { "alias": "hideInlineError"; "required": false; }; "model": { "alias": "model"; "required": false; }; "_required": { "alias": "required"; "required": false; }; "pMin": { "alias": "min"; "required": false; }; "pMax": { "alias": "max"; "required": false; }; "disabled": { "alias": "disabled"; "required": false; }; }, { "modelChange": "modelChange"; "sdChange": "sdChange"; }, ["sdView", "sdLabelDef"], never, true, never>;
63
+ static ɵcmp: i0.ɵɵComponentDeclaration<SdChip, "sd-chip", never, { "autoId": { "alias": "autoId"; "required": false; "isSignal": true; }; "name": { "alias": "name"; "required": false; "isSignal": true; }; "appearance": { "alias": "appearance"; "required": false; "isSignal": true; }; "floatLabel": { "alias": "floatLabel"; "required": false; "isSignal": true; }; "size": { "alias": "size"; "required": false; "isSignal": true; }; "form": { "alias": "form"; "required": false; "isSignal": true; }; "label": { "alias": "label"; "required": false; "isSignal": true; }; "placeholder": { "alias": "placeholder"; "required": false; "isSignal": true; }; "removable": { "alias": "removable"; "required": false; "isSignal": true; }; "hideInlineError": { "alias": "hideInlineError"; "required": false; "isSignal": true; }; "model": { "alias": "model"; "required": false; "isSignal": true; }; "required": { "alias": "required"; "required": false; "isSignal": true; }; "min": { "alias": "min"; "required": false; "isSignal": true; }; "max": { "alias": "max"; "required": false; "isSignal": true; }; "addable": { "alias": "addable"; "required": false; "isSignal": true; }; "disabled": { "alias": "disabled"; "required": false; "isSignal": true; }; "viewed": { "alias": "viewed"; "required": false; "isSignal": true; }; "hyperlink": { "alias": "hyperlink"; "required": false; "isSignal": true; }; }, { "modelChange": "modelChange"; "sdChange": "sdChange"; }, ["sdViewDef", "sdLabelDef", "sdLabelTemplate", "sdValueTemplate"], never, true, never>;
73
64
  }
74
65
  export {};
@@ -1,4 +1,4 @@
1
- import { AfterViewInit, ChangeDetectorRef, ElementRef, EventEmitter, OnDestroy } from '@angular/core';
1
+ import { AfterViewInit, ElementRef, TemplateRef } from '@angular/core';
2
2
  import { FormControl, FormGroup, FormGroupDirective, NgForm } from '@angular/forms';
3
3
  import { MatAutocompleteSelectedEvent } from '@angular/material/autocomplete';
4
4
  import { ErrorStateMatcher } from '@angular/material/core';
@@ -9,64 +9,57 @@ import { SdLabelDefDirective, SdViewDefDirective } from '@sd-angular/core/forms/
9
9
  import { SdFormControl } from '@sd-angular/core/forms/models';
10
10
  import { SdSize } from '@sd-angular/core/utilities';
11
11
  import * as i0 from "@angular/core";
12
- declare class SdChipErrotStateMatcher implements ErrorStateMatcher {
12
+ declare class SdChipCalendarErrorStateMatcher implements ErrorStateMatcher {
13
13
  private formControl;
14
14
  constructor(formControl: FormControl);
15
15
  isErrorState(control: FormControl | null, form: FormGroupDirective | NgForm | null): boolean;
16
16
  }
17
- export declare class SdChipCalendar implements OnDestroy, AfterViewInit {
17
+ export declare class SdChipCalendar implements AfterViewInit {
18
18
  #private;
19
- private ref;
20
19
  menuTrigger: MatMenuTrigger;
21
20
  calendar: MatCalendar<Date>;
22
- autoId?: string;
23
- set _autoId(val: string | undefined | null);
24
- set _name(val: string | undefined);
25
- appearance: MatFormFieldAppearance;
26
- floatLabel: FloatLabelType;
27
- size: SdSize;
28
- set form(val: NgForm | FormGroup);
29
- label: string;
30
- placeholder?: string;
31
- removable: boolean | ((item: any) => boolean);
32
- set _removable(val: '' | boolean | ((item: any) => boolean));
33
- hideInlineError: boolean;
34
- set _hideInlineError(val: boolean | '' | undefined | null);
35
- set model(values: undefined | (string | number)[]);
36
- required: boolean;
37
- set _required(val: boolean | '' | undefined | null);
38
- min: number;
39
- set pMin(val: number | string);
40
- max: number;
41
- set pMax(val: number | string);
42
- modelChange: EventEmitter<any>;
43
- set disabled(val: boolean | '' | undefined | null);
44
- sdChange: EventEmitter<any[]>;
21
+ autoId: import("@angular/core").InputSignal<string | undefined>;
22
+ name: import("@angular/core").InputSignal<string | undefined>;
23
+ appearance: import("@angular/core").InputSignal<MatFormFieldAppearance>;
24
+ floatLabel: import("@angular/core").InputSignal<FloatLabelType>;
25
+ size: import("@angular/core").InputSignal<SdSize>;
26
+ form: import("@angular/core").InputSignal<NgForm | FormGroup<any> | undefined>;
27
+ label: import("@angular/core").InputSignal<string>;
28
+ placeholder: import("@angular/core").InputSignal<string | undefined>;
29
+ removable: import("@angular/core").InputSignal<boolean | ((item: any) => boolean)>;
30
+ hideInlineError: import("@angular/core").InputSignalWithTransform<boolean, unknown>;
31
+ model: import("@angular/core").InputSignal<(string | number)[] | undefined>;
32
+ required: import("@angular/core").InputSignalWithTransform<boolean, unknown>;
33
+ min: import("@angular/core").InputSignal<number>;
34
+ max: import("@angular/core").InputSignal<number>;
35
+ disabled: import("@angular/core").InputSignalWithTransform<boolean, unknown>;
36
+ viewed: import("@angular/core").InputSignalWithTransform<boolean, unknown>;
37
+ hyperlink: import("@angular/core").InputSignal<string | null | undefined>;
38
+ modelChange: import("@angular/core").OutputEmitterRef<any[]>;
39
+ sdChange: import("@angular/core").OutputEmitterRef<any[]>;
45
40
  input: ElementRef<HTMLInputElement>;
46
- sdView?: SdViewDefDirective;
47
- sdLabelDef?: SdLabelDefDirective;
48
- isBlurring: boolean;
41
+ sdViewDef: import("@angular/core").Signal<SdViewDefDirective | undefined>;
42
+ sdLabelDef: import("@angular/core").Signal<SdLabelDefDirective | undefined>;
43
+ sdLabelTemplate: import("@angular/core").Signal<TemplateRef<any> | undefined>;
44
+ sdValueTemplate: import("@angular/core").Signal<TemplateRef<any> | undefined>;
49
45
  isFocused: boolean;
50
- inputControl: FormControl<any>;
51
- formControl: SdFormControl;
52
- matcher: SdChipErrotStateMatcher;
53
- /**
54
- * Tổng hợp error message để hiển thị trong tooltip khi hideInlineError = true.
55
- * Dùng getter (không phải computed) vì đây là component cũ dùng @Input decorator.
56
- */
46
+ readonly separatorKeysCodes: number[];
47
+ constructor();
48
+ get formControl(): SdFormControl;
49
+ get inputControl(): FormControl<any>;
57
50
  get errorTooltipMessage(): string | undefined;
58
- constructor(ref: ChangeDetectorRef);
51
+ get matcher(): SdChipCalendarErrorStateMatcher;
59
52
  ngAfterViewInit(): void;
60
53
  ngOnDestroy(): void;
61
- onClickChip: ($event: Event, item: any) => void;
54
+ onClickChip: (event: Event, item: any) => void;
62
55
  onRemove: (item: string) => void;
63
56
  onSelect: (event: MatAutocompleteSelectedEvent) => void;
64
57
  onClick: () => void;
65
- onClear: ($event?: any) => void;
58
+ onClear: (evt?: any) => void;
66
59
  onSelectDate: (date: Date | null) => void;
67
- onCloseCalendar(): void;
60
+ onCloseCalendar: () => void;
68
61
  dateClass: (cellDate: Date) => "" | "sd-chip-calendar-selected-date";
69
62
  static ɵfac: i0.ɵɵFactoryDeclaration<SdChipCalendar, never>;
70
- static ɵcmp: i0.ɵɵComponentDeclaration<SdChipCalendar, "sd-chip-calendar", never, { "_autoId": { "alias": "autoId"; "required": false; }; "_name": { "alias": "name"; "required": false; }; "appearance": { "alias": "appearance"; "required": false; }; "floatLabel": { "alias": "floatLabel"; "required": false; }; "size": { "alias": "size"; "required": false; }; "form": { "alias": "form"; "required": false; }; "label": { "alias": "label"; "required": false; }; "placeholder": { "alias": "placeholder"; "required": false; }; "_removable": { "alias": "removable"; "required": false; }; "_hideInlineError": { "alias": "hideInlineError"; "required": false; }; "model": { "alias": "model"; "required": false; }; "_required": { "alias": "required"; "required": false; }; "pMin": { "alias": "min"; "required": false; }; "pMax": { "alias": "max"; "required": false; }; "disabled": { "alias": "disabled"; "required": false; }; }, { "modelChange": "modelChange"; "sdChange": "sdChange"; }, ["sdView", "sdLabelDef"], never, true, never>;
63
+ static ɵcmp: i0.ɵɵComponentDeclaration<SdChipCalendar, "sd-chip-calendar", never, { "autoId": { "alias": "autoId"; "required": false; "isSignal": true; }; "name": { "alias": "name"; "required": false; "isSignal": true; }; "appearance": { "alias": "appearance"; "required": false; "isSignal": true; }; "floatLabel": { "alias": "floatLabel"; "required": false; "isSignal": true; }; "size": { "alias": "size"; "required": false; "isSignal": true; }; "form": { "alias": "form"; "required": false; "isSignal": true; }; "label": { "alias": "label"; "required": false; "isSignal": true; }; "placeholder": { "alias": "placeholder"; "required": false; "isSignal": true; }; "removable": { "alias": "removable"; "required": false; "isSignal": true; }; "hideInlineError": { "alias": "hideInlineError"; "required": false; "isSignal": true; }; "model": { "alias": "model"; "required": false; "isSignal": true; }; "required": { "alias": "required"; "required": false; "isSignal": true; }; "min": { "alias": "min"; "required": false; "isSignal": true; }; "max": { "alias": "max"; "required": false; "isSignal": true; }; "disabled": { "alias": "disabled"; "required": false; "isSignal": true; }; "viewed": { "alias": "viewed"; "required": false; "isSignal": true; }; "hyperlink": { "alias": "hyperlink"; "required": false; "isSignal": true; }; }, { "modelChange": "modelChange"; "sdChange": "sdChange"; }, ["sdViewDef", "sdLabelDef", "sdLabelTemplate", "sdValueTemplate"], never, true, never>;
71
64
  }
72
65
  export {};