@sd-angular/core 19.0.14 → 19.0.16

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.
@@ -0,0 +1,18 @@
1
+ export declare const DATE_DISPLAY_FORMAT = "dd/MM/yyyy";
2
+ export declare const DATE_DISPLAY_PATTERN: RegExp;
3
+ export declare const DATE_INPUT_MAX_DIGITS = 8;
4
+ /** Chèn `/` vào chuỗi số người dùng đang gõ: `22081991` → `22/08/1991`. */
5
+ export declare function formatDateInput(value: string, addTrailingSeparator: boolean): string;
6
+ /** Chuỗi còn dở dang (đang gõ) — chưa đủ `dd/MM/yyyy` nhưng vẫn đúng khuôn. */
7
+ export declare function isPartialDateInput(value: string): boolean;
8
+ /**
9
+ * Chỉ nhận đúng `dd/MM/yyyy` ĐẦY ĐỦ và có thật trên lịch.
10
+ *
11
+ * WHY chặt tay như vậy: `date-fns.parse(value, 'dd/MM/yyyy')` rất dễ dãi — nó
12
+ * nhận cả năm thiếu chữ số, nên `11/12/2` ra năm 0002 còn `11/12/20` ra năm
13
+ * 0020. Nếu để lọt, người dùng mới gõ nửa chừng đã bị coi là nhập xong.
14
+ */
15
+ export declare function parseDateInput(value: string): Date | null;
16
+ /** Giữ con trỏ đứng đúng chỗ sau khi chuỗi được chèn thêm `/`. */
17
+ export declare function getCaretPosition(value: string, selectionStart: number, formattedValue: string, addTrailingSeparator: boolean): number;
18
+ export declare function dateControlsEqual(left: Date | null, right: Date | null): boolean;
@@ -5,3 +5,4 @@ export * from './src/sd-selection-data.model';
5
5
  export * from './src/sd-search.model';
6
6
  export * from './src/form-control-state';
7
7
  export * from './src/sd-viewed';
8
+ export * from './src/sd-strict-date-adapter';
@@ -0,0 +1,26 @@
1
+ import { Provider } from '@angular/core';
2
+ import { DateFnsAdapter } from '@angular/material-date-fns-adapter';
3
+ import { MatDateFormats } from '@angular/material/core';
4
+ import * as i0 from "@angular/core";
5
+ /**
6
+ * DateAdapter từ chối mọi chuỗi người dùng chưa gõ xong.
7
+ *
8
+ * WHY cần đến mức này: `<input matInput [matDatepicker]>` khiến Material tự
9
+ * `parse()` lại ô nhập SAU MỖI PHÍM GÕ rồi ghi thẳng kết quả vào form control.
10
+ * Adapter mặc định quá dễ dãi trên hai đường:
11
+ *
12
+ * 1. `date-fns.parse` nhận năm thiếu chữ số → `11/12/2` thành năm 0002,
13
+ * `11/12/20` thành năm 0020. Ô nhập vừa gõ dở đã bị coi là hợp lệ (cờ lỗi
14
+ * bị xoá) và control ôm một ngày rác.
15
+ * 2. `parseISO` coi chuỗi 2 chữ số là thế kỷ → xoá lùi còn `11` ra năm 1100.
16
+ *
17
+ * Cả hai đường đều bị chặn ở đây: control chỉ nhận giá trị khi người dùng thực
18
+ * sự gõ xong.
19
+ */
20
+ export declare class SdStrictDateFnsAdapter extends DateFnsAdapter {
21
+ parse(value: unknown, parseFormat: string | string[]): Date | null;
22
+ static ɵfac: i0.ɵɵFactoryDeclaration<SdStrictDateFnsAdapter, never>;
23
+ static ɵprov: i0.ɵɵInjectableDeclaration<SdStrictDateFnsAdapter>;
24
+ }
25
+ /** `provideDateFnsAdapter` + ép dùng adapter parse chặt ở trên. */
26
+ export declare function provideSdStrictDateFnsAdapter(formats: MatDateFormats): Provider[];
@@ -49,8 +49,8 @@ export declare class SdSelect<T extends object | string | number = Record<string
49
49
  label: import("@angular/core").InputSignal<string | undefined>;
50
50
  helperText: import("@angular/core").InputSignal<string | undefined>;
51
51
  placeholder: import("@angular/core").InputSignal<string | undefined>;
52
- valueField: import("@angular/core").InputSignal<T extends object ? { [Key in keyof T & string]: T[Key] extends string | number | boolean | Function | Date | null | undefined ? Key : T[Key] extends any[] ? Key : T[Key] extends object ? Key | `${Key}.${T[Key] extends infer T_1 ? T_1 extends T[Key] ? T_1 extends object ? { [Key_1 in keyof T_1 & string]: T_1[Key_1] extends string | number | boolean | Function | Date | null | undefined ? Key_1 : T_1[Key_1] extends any[] ? Key_1 : T_1[Key_1] extends object ? Key_1 | `${Key_1}.${T_1[Key_1] extends infer T_2 ? T_2 extends T_1[Key_1] ? T_2 extends object ? { [Key_2 in keyof T_2 & string]: T_2[Key_2] extends string | number | boolean | Function | Date | null | undefined ? Key_2 : T_2[Key_2] extends any[] ? Key_2 : T_2[Key_2] extends object ? Key_2 | `${Key_2}.${T_2[Key_2] extends infer T_3 ? T_3 extends T_2[Key_2] ? T_3 extends object ? { [Key_3 in keyof T_3 & string]: T_3[Key_3] extends string | number | boolean | Function | Date | null | undefined ? Key_3 : T_3[Key_3] extends any[] ? Key_3 : T_3[Key_3] extends object ? Key_3 : Key_3; }[keyof T_3 & string] : string : never : never}` : Key_2; }[keyof T_2 & string] : string : never : never}` : Key_1; }[keyof T_1 & string] : string : never : never}` : Key; }[keyof T & string] : string>;
53
- displayField: import("@angular/core").InputSignal<T extends object ? { [Key in keyof T & string]: T[Key] extends string | number | boolean | Function | Date | null | undefined ? Key : T[Key] extends any[] ? Key : T[Key] extends object ? Key | `${Key}.${T[Key] extends infer T_1 ? T_1 extends T[Key] ? T_1 extends object ? { [Key_1 in keyof T_1 & string]: T_1[Key_1] extends string | number | boolean | Function | Date | null | undefined ? Key_1 : T_1[Key_1] extends any[] ? Key_1 : T_1[Key_1] extends object ? Key_1 | `${Key_1}.${T_1[Key_1] extends infer T_2 ? T_2 extends T_1[Key_1] ? T_2 extends object ? { [Key_2 in keyof T_2 & string]: T_2[Key_2] extends string | number | boolean | Function | Date | null | undefined ? Key_2 : T_2[Key_2] extends any[] ? Key_2 : T_2[Key_2] extends object ? Key_2 | `${Key_2}.${T_2[Key_2] extends infer T_3 ? T_3 extends T_2[Key_2] ? T_3 extends object ? { [Key_3 in keyof T_3 & string]: T_3[Key_3] extends string | number | boolean | Function | Date | null | undefined ? Key_3 : T_3[Key_3] extends any[] ? Key_3 : T_3[Key_3] extends object ? Key_3 : Key_3; }[keyof T_3 & string] : string : never : never}` : Key_2; }[keyof T_2 & string] : string : never : never}` : Key_1; }[keyof T_1 & string] : string : never : never}` : Key; }[keyof T & string] : string>;
52
+ valueField: import("@angular/core").InputSignal<"" | (T extends object ? { [Key in keyof T & string]: T[Key] extends string | number | boolean | Function | Date | null | undefined ? Key : T[Key] extends any[] ? Key : T[Key] extends object ? Key | `${Key}.${T[Key] extends infer T_1 ? T_1 extends T[Key] ? T_1 extends object ? { [Key_1 in keyof T_1 & string]: T_1[Key_1] extends string | number | boolean | Function | Date | null | undefined ? Key_1 : T_1[Key_1] extends any[] ? Key_1 : T_1[Key_1] extends object ? Key_1 | `${Key_1}.${T_1[Key_1] extends infer T_2 ? T_2 extends T_1[Key_1] ? T_2 extends object ? { [Key_2 in keyof T_2 & string]: T_2[Key_2] extends string | number | boolean | Function | Date | null | undefined ? Key_2 : T_2[Key_2] extends any[] ? Key_2 : T_2[Key_2] extends object ? Key_2 | `${Key_2}.${T_2[Key_2] extends infer T_3 ? T_3 extends T_2[Key_2] ? T_3 extends object ? { [Key_3 in keyof T_3 & string]: T_3[Key_3] extends string | number | boolean | Function | Date | null | undefined ? Key_3 : T_3[Key_3] extends any[] ? Key_3 : T_3[Key_3] extends object ? Key_3 : Key_3; }[keyof T_3 & string] : string : never : never}` : Key_2; }[keyof T_2 & string] : string : never : never}` : Key_1; }[keyof T_1 & string] : string : never : never}` : Key; }[keyof T & string] : string)>;
53
+ displayField: import("@angular/core").InputSignal<"" | (T extends object ? { [Key in keyof T & string]: T[Key] extends string | number | boolean | Function | Date | null | undefined ? Key : T[Key] extends any[] ? Key : T[Key] extends object ? Key | `${Key}.${T[Key] extends infer T_1 ? T_1 extends T[Key] ? T_1 extends object ? { [Key_1 in keyof T_1 & string]: T_1[Key_1] extends string | number | boolean | Function | Date | null | undefined ? Key_1 : T_1[Key_1] extends any[] ? Key_1 : T_1[Key_1] extends object ? Key_1 | `${Key_1}.${T_1[Key_1] extends infer T_2 ? T_2 extends T_1[Key_1] ? T_2 extends object ? { [Key_2 in keyof T_2 & string]: T_2[Key_2] extends string | number | boolean | Function | Date | null | undefined ? Key_2 : T_2[Key_2] extends any[] ? Key_2 : T_2[Key_2] extends object ? Key_2 | `${Key_2}.${T_2[Key_2] extends infer T_3 ? T_3 extends T_2[Key_2] ? T_3 extends object ? { [Key_3 in keyof T_3 & string]: T_3[Key_3] extends string | number | boolean | Function | Date | null | undefined ? Key_3 : T_3[Key_3] extends any[] ? Key_3 : T_3[Key_3] extends object ? Key_3 : Key_3; }[keyof T_3 & string] : string : never : never}` : Key_2; }[keyof T_2 & string] : string : never : never}` : Key_1; }[keyof T_1 & string] : string : never : never}` : Key; }[keyof T & string] : string)>;
54
54
  disabledField: import("@angular/core").InputSignal<"" | (T extends object ? { [Key in keyof T & string]: T[Key] extends string | number | boolean | Function | Date | null | undefined ? Key : T[Key] extends any[] ? Key : T[Key] extends object ? Key | `${Key}.${T[Key] extends infer T_1 ? T_1 extends T[Key] ? T_1 extends object ? { [Key_1 in keyof T_1 & string]: T_1[Key_1] extends string | number | boolean | Function | Date | null | undefined ? Key_1 : T_1[Key_1] extends any[] ? Key_1 : T_1[Key_1] extends object ? Key_1 | `${Key_1}.${T_1[Key_1] extends infer T_2 ? T_2 extends T_1[Key_1] ? T_2 extends object ? { [Key_2 in keyof T_2 & string]: T_2[Key_2] extends string | number | boolean | Function | Date | null | undefined ? Key_2 : T_2[Key_2] extends any[] ? Key_2 : T_2[Key_2] extends object ? Key_2 | `${Key_2}.${T_2[Key_2] extends infer T_3 ? T_3 extends T_2[Key_2] ? T_3 extends object ? { [Key_3 in keyof T_3 & string]: T_3[Key_3] extends string | number | boolean | Function | Date | null | undefined ? Key_3 : T_3[Key_3] extends any[] ? Key_3 : T_3[Key_3] extends object ? Key_3 : Key_3; }[keyof T_3 & string] : string : never : never}` : Key_2; }[keyof T_2 & string] : string : never : never}` : Key_1; }[keyof T_1 & string] : string : never : never}` : Key; }[keyof T & string] : string)>;
55
55
  cacheChecksum: import("@angular/core").InputSignal<any>;
56
56
  limit: import("@angular/core").InputSignal<number>;
@@ -62,6 +62,11 @@ export declare class SdSelect<T extends object | string | number = Record<string
62
62
  /** Display mode: `false` edit · `true` static view · `'inline'` view + click-to-edit (bare editor). */
63
63
  viewed: import("@angular/core").InputSignalWithTransform<SdViewed, SdViewedInput>;
64
64
  multiple: import("@angular/core").InputSignalWithTransform<boolean, unknown>;
65
+ /**
66
+ * Hiện option "Chọn tất cả" đầu panel (chỉ multiple + items là mảng tĩnh/Signal — ẩn với
67
+ * SdSearch lazy vì dataset không xác định). Opt-in, default `false`.
68
+ */
69
+ showSelectAll: import("@angular/core").InputSignalWithTransform<boolean, unknown>;
65
70
  /**
66
71
  * Whether the `viewed='inline'` text face shows a hover clear-× to empty the value.
67
72
  * Default `true`. Set `false` where the HOST owns removal (e.g. `<sd-query-bar>` chips,
@@ -107,6 +112,16 @@ export declare class SdSelect<T extends object | string | number = Record<string
107
112
  normalizedValue: Signal<string | number | boolean | (string | number | boolean)[] | null | undefined>;
108
113
  filtered: Signal<boolean>;
109
114
  delayTime: Signal<0 | 500>;
115
+ /**
116
+ * Scope của "Chọn tất cả": item enabled khớp search text hiện tại, tính trên MẢNG NGUỒN
117
+ * `actualItems()`.
118
+ */
119
+ readonly selectAllScope: Signal<T[]>;
120
+ /** Row "Chọn tất cả" chỉ render khi opt-in + multiple + items tĩnh + scope có item để thao tác. */
121
+ readonly selectAllVisible: Signal<boolean>;
122
+ /** Trạng thái checkbox "Chọn tất cả", tính trên items ENABLED trong scope (item disabled bỏ qua). */
123
+ readonly selectAllState: Signal<"checked" | "indeterminate" | "unchecked">;
124
+ readonly selectAllLabel: Signal<string>;
110
125
  itemValue: (item: T) => unknown;
111
126
  itemDisplay: (item: T) => string;
112
127
  itemDisabled: (item: T) => boolean;
@@ -117,6 +132,12 @@ export declare class SdSelect<T extends object | string | number = Record<string
117
132
  constructor();
118
133
  ngOnInit(): void;
119
134
  onSelectionChange: (change: MatSelectChange) => void;
135
+ /**
136
+ * Toggle "Chọn tất cả" theo scope hiện tại (items enabled khớp search):
137
+ * - Đang `checked` → BỎ chọn các value trong scope (giữ value ngoài scope, kể cả item disabled đã chọn).
138
+ * - Ngược lại → CHỌN THÊM toàn bộ scope, union với selection hiện có (additive khi đang search).
139
+ */
140
+ toggleSelectAll: () => void;
120
141
  reValidate: () => void;
121
142
  clear: ($event?: any) => void;
122
143
  onClick: () => void;
@@ -127,5 +148,5 @@ export declare class SdSelect<T extends object | string | number = Record<string
127
148
  open: () => void;
128
149
  onOpenedChange: (isOpened: boolean) => void;
129
150
  static ɵfac: i0.ɵɵFactoryDeclaration<SdSelect<any>, never>;
130
- static ɵcmp: i0.ɵɵComponentDeclaration<SdSelect<any>, "sd-select", never, { "autoIdInput": { "alias": "autoId"; "required": false; "isSignal": true; }; "name": { "alias": "name"; "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; }; "helperText": { "alias": "helperText"; "required": false; "isSignal": true; }; "placeholder": { "alias": "placeholder"; "required": false; "isSignal": true; }; "valueField": { "alias": "valueField"; "required": true; "isSignal": true; }; "displayField": { "alias": "displayField"; "required": true; "isSignal": true; }; "disabledField": { "alias": "disabledField"; "required": false; "isSignal": true; }; "cacheChecksum": { "alias": "cacheChecksum"; "required": false; "isSignal": true; }; "limit": { "alias": "limit"; "required": false; "isSignal": true; }; "hyperlink": { "alias": "hyperlink"; "required": false; "isSignal": true; }; "minWidthPanel": { "alias": "minWidthPanel"; "required": false; "isSignal": true; }; "hideInlineError": { "alias": "hideInlineError"; "required": false; "isSignal": true; }; "required": { "alias": "required"; "required": false; "isSignal": true; }; "disabled": { "alias": "disabled"; "required": false; "isSignal": true; }; "viewed": { "alias": "viewed"; "required": false; "isSignal": true; }; "multiple": { "alias": "multiple"; "required": false; "isSignal": true; }; "clearable": { "alias": "clearable"; "required": false; "isSignal": true; }; "validator": { "alias": "validator"; "required": false; "isSignal": true; }; "inlineError": { "alias": "inlineError"; "required": false; "isSignal": true; }; "appearanceInput": { "alias": "appearance"; "required": false; "isSignal": true; }; "floatLabel": { "alias": "floatLabel"; "required": false; "isSignal": true; }; "items": { "alias": "items"; "required": false; "isSignal": true; }; "valueModel": { "alias": "model"; "required": false; "isSignal": true; }; }, { "valueModel": "modelChange"; "sdChange": "sdChange"; "sdSelection": "sdSelection"; }, ["sdLabelTemplate", "sdValueTemplate", "sdSelectedTemplate", "itemDef", "sdViewDef", "footerActions"], ["[sdLabel]"], true, never>;
151
+ static ɵcmp: i0.ɵɵComponentDeclaration<SdSelect<any>, "sd-select", never, { "autoIdInput": { "alias": "autoId"; "required": false; "isSignal": true; }; "name": { "alias": "name"; "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; }; "helperText": { "alias": "helperText"; "required": false; "isSignal": true; }; "placeholder": { "alias": "placeholder"; "required": false; "isSignal": true; }; "valueField": { "alias": "valueField"; "required": false; "isSignal": true; }; "displayField": { "alias": "displayField"; "required": false; "isSignal": true; }; "disabledField": { "alias": "disabledField"; "required": false; "isSignal": true; }; "cacheChecksum": { "alias": "cacheChecksum"; "required": false; "isSignal": true; }; "limit": { "alias": "limit"; "required": false; "isSignal": true; }; "hyperlink": { "alias": "hyperlink"; "required": false; "isSignal": true; }; "minWidthPanel": { "alias": "minWidthPanel"; "required": false; "isSignal": true; }; "hideInlineError": { "alias": "hideInlineError"; "required": false; "isSignal": true; }; "required": { "alias": "required"; "required": false; "isSignal": true; }; "disabled": { "alias": "disabled"; "required": false; "isSignal": true; }; "viewed": { "alias": "viewed"; "required": false; "isSignal": true; }; "multiple": { "alias": "multiple"; "required": false; "isSignal": true; }; "showSelectAll": { "alias": "showSelectAll"; "required": false; "isSignal": true; }; "clearable": { "alias": "clearable"; "required": false; "isSignal": true; }; "validator": { "alias": "validator"; "required": false; "isSignal": true; }; "inlineError": { "alias": "inlineError"; "required": false; "isSignal": true; }; "appearanceInput": { "alias": "appearance"; "required": false; "isSignal": true; }; "floatLabel": { "alias": "floatLabel"; "required": false; "isSignal": true; }; "items": { "alias": "items"; "required": false; "isSignal": true; }; "valueModel": { "alias": "model"; "required": false; "isSignal": true; }; }, { "valueModel": "modelChange"; "sdChange": "sdChange"; "sdSelection": "sdSelection"; }, ["sdLabelTemplate", "sdValueTemplate", "sdSelectedTemplate", "itemDef", "sdViewDef", "footerActions"], ["[sdLabel]"], true, never>;
131
152
  }
package/i18n/src/en.d.ts CHANGED
@@ -138,6 +138,7 @@ export declare const EN_MESSAGES: {
138
138
  readonly 'core.form.checkbox.checked': "Yes";
139
139
  readonly 'core.form.checkbox.unchecked': "No";
140
140
  readonly 'core.form.select.required': "Please enter information";
141
+ readonly 'core.form.select.selectAll': "Select all";
141
142
  readonly 'core.form.textarea.required': "Please enter information";
142
143
  readonly 'core.form.textarea.maxlength': "Maximum characters: {max}";
143
144
  readonly 'core.form.textarea.invalid-pattern': "Invalid format";
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@sd-angular/core",
3
- "version": "19.0.14",
3
+ "version": "19.0.16",
4
4
  "peerDependencies": {
5
5
  "@angular/common": "^19.0.0 || ^20.0.0 || ^21.0.0",
6
6
  "@angular/core": "^19.0.0 || ^20.0.0 || ^21.0.0",
@@ -260,14 +260,14 @@
260
260
  "types": "./forms/input-color/index.d.ts",
261
261
  "default": "./fesm2022/sd-angular-core-forms-input-color.mjs"
262
262
  },
263
- "./forms/label": {
264
- "types": "./forms/label/index.d.ts",
265
- "default": "./fesm2022/sd-angular-core-forms-label.mjs"
266
- },
267
263
  "./forms/input-number": {
268
264
  "types": "./forms/input-number/index.d.ts",
269
265
  "default": "./fesm2022/sd-angular-core-forms-input-number.mjs"
270
266
  },
267
+ "./forms/label": {
268
+ "types": "./forms/label/index.d.ts",
269
+ "default": "./fesm2022/sd-angular-core-forms-label.mjs"
270
+ },
271
271
  "./forms/models": {
272
272
  "types": "./forms/models/index.d.ts",
273
273
  "default": "./fesm2022/sd-angular-core-forms-models.mjs"