@edmicro/olkit 1.1.5 → 1.1.7
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.
- package/fesm2022/edmicro-olkit.mjs +4403 -780
- package/fesm2022/edmicro-olkit.mjs.map +1 -1
- package/olkit.css +1 -1
- package/package.json +1 -1
- package/types/edmicro-olkit.d.ts +1787 -218
- package/types/edmicro-olkit.d.ts.map +1 -1
- package/version.txt +2 -2
- package/LICENSES/LICENSES/FLOWBITE-MIT.txt +0 -21
- package/LICENSES/LICENSES/MYNAUI-MIT.txt +0 -21
- package/LICENSES/LICENSES/SOLAR-CC-BY-4.0.txt +0 -49
package/types/edmicro-olkit.d.ts
CHANGED
|
@@ -131,6 +131,17 @@ declare class OlAlert {
|
|
|
131
131
|
static ɵcmp: _angular_core.ɵɵComponentDeclaration<OlAlert, "ol-alert", never, { "type": { "alias": "type"; "required": false; "isSignal": true; }; "headingLevel": { "alias": "headingLevel"; "required": false; "isSignal": true; }; "layout": { "alias": "layout"; "required": false; "isSignal": true; }; "variant": { "alias": "variant"; "required": false; "isSignal": true; }; "title": { "alias": "title"; "required": false; "isSignal": true; }; "icon": { "alias": "icon"; "required": false; "isSignal": true; }; "dismissible": { "alias": "dismissible"; "required": false; "isSignal": true; }; "rounded": { "alias": "rounded"; "required": false; "isSignal": true; }; "badge": { "alias": "badge"; "required": false; "isSignal": true; }; }, { "onDismiss": "onDismiss"; }, never, ["[badge]", "*", "[alertActions]"], true, never>;
|
|
132
132
|
}
|
|
133
133
|
|
|
134
|
+
/**
|
|
135
|
+
* Bỏ dấu tiếng Việt để gõ không dấu vẫn tìm ra.
|
|
136
|
+
*
|
|
137
|
+
* Phải xử lý `đ`/`Đ` riêng: chúng KHÔNG phải `d` cộng dấu phụ nên `NFD` không
|
|
138
|
+
* tách ra được, `đăng nhập` sẽ không khớp `dang nhap` nếu bỏ bước này.
|
|
139
|
+
*
|
|
140
|
+
* Dùng chung cho mọi ô có tìm kiếm (`ol-command`, `ol-select`); `ol-command`
|
|
141
|
+
* export lại để giữ API công khai từ 1.1.1.
|
|
142
|
+
*/
|
|
143
|
+
declare function stripDiacritics(text: string): string;
|
|
144
|
+
|
|
134
145
|
/** Một lệnh trong bảng. `keywords` để tìm được bằng từ khác với chữ hiển thị. */
|
|
135
146
|
interface CommandItem {
|
|
136
147
|
id: string;
|
|
@@ -145,13 +156,7 @@ interface CommandGroup {
|
|
|
145
156
|
label: string;
|
|
146
157
|
items: CommandItem[];
|
|
147
158
|
}
|
|
148
|
-
|
|
149
|
-
* Bỏ dấu tiếng Việt để gõ không dấu vẫn tìm ra.
|
|
150
|
-
*
|
|
151
|
-
* Phải xử lý `đ`/`Đ` riêng: chúng KHÔNG phải `d` cộng dấu phụ nên `NFD` không
|
|
152
|
-
* tách ra được, `đăng nhập` sẽ không khớp `dang nhap` nếu bỏ bước này.
|
|
153
|
-
*/
|
|
154
|
-
declare function stripDiacritics(text: string): string;
|
|
159
|
+
|
|
155
160
|
/**
|
|
156
161
|
* @deprecated Dùng `stripDiacritics`. Giữ lại vì hàm này ĐÃ publish trong
|
|
157
162
|
* `@edmicro/olkit@1.1.1` (kiểm bằng `npm pack` rồi đọc `types/*.d.ts` — có
|
|
@@ -246,6 +251,106 @@ declare class OlScrollArea {
|
|
|
246
251
|
static ɵcmp: _angular_core.ɵɵComponentDeclaration<OlScrollArea, "ol-scroll-area", never, { "scrollbar": { "alias": "scrollbar"; "required": false; "isSignal": true; }; "axis": { "alias": "axis"; "required": false; "isSignal": true; }; "smooth": { "alias": "smooth"; "required": false; "isSignal": true; }; "innerClass": { "alias": "innerClass"; "required": false; "isSignal": true; }; }, {}, never, ["*"], true, never>;
|
|
247
252
|
}
|
|
248
253
|
|
|
254
|
+
/** Một mục trong mục lục. */
|
|
255
|
+
interface OlScrollspyItem {
|
|
256
|
+
/** `id` của phần tử trên trang mà mục này trỏ tới. */
|
|
257
|
+
id: string;
|
|
258
|
+
label: string;
|
|
259
|
+
/** Cấp thụt lề: 1 là mục chính, 2 là mục con. */
|
|
260
|
+
level?: 1 | 2;
|
|
261
|
+
}
|
|
262
|
+
type OlScrollspyOrientation = 'vertical' | 'horizontal';
|
|
263
|
+
/**
|
|
264
|
+
* Mục lục tự đánh dấu phần đang xem.
|
|
265
|
+
*
|
|
266
|
+
* Chưa có node Figma — dựng theo design system, mục đang xem dùng
|
|
267
|
+
* `text-fg-brand` và một vạch `bg-brand` bên trái (dọc) hoặc dưới (ngang).
|
|
268
|
+
*
|
|
269
|
+
* ## Vì sao `IntersectionObserver` chứ không nghe sự kiện `scroll`
|
|
270
|
+
*
|
|
271
|
+
* Nghe `scroll` thì mỗi lần cuộn là một lần chạy tay tính `getBoundingClientRect()`
|
|
272
|
+
* cho MỌI phần — trang 63 mục như docs olkit là 63 phép đo mỗi khung hình.
|
|
273
|
+
* `IntersectionObserver` để trình duyệt tự báo, và chỉ báo phần nào đổi trạng
|
|
274
|
+
* thái.
|
|
275
|
+
*
|
|
276
|
+
* ## `rootMargin` quyết định "đang xem" nghĩa là gì
|
|
277
|
+
*
|
|
278
|
+
* Mặc định `-20% 0px -70% 0px` thu vùng quan sát thành một dải ngang mỏng ở
|
|
279
|
+
* khoảng 1/4 trên màn hình. Không thu thì phần nào chạm mép dưới màn hình cũng
|
|
280
|
+
* tính là đang xem, và cuộn một nhịp có thể sáng ba mục cùng lúc.
|
|
281
|
+
*
|
|
282
|
+
* Dải mỏng cũng xử lý được phần NGẮN hơn màn hình: nếu đợi phần chiếm trọn
|
|
283
|
+
* viewport mới tính, mục ngắn không bao giờ được đánh dấu.
|
|
284
|
+
*
|
|
285
|
+
* ## Phần cuối trang không bao giờ chạm dải
|
|
286
|
+
*
|
|
287
|
+
* Cuộn hết cỡ mà phần cuối vẫn nằm dưới dải quan sát thì nó không sáng. Nên
|
|
288
|
+
* khi chạm đáy trang, component đánh dấu thẳng mục cuối — `atBottom()`.
|
|
289
|
+
*
|
|
290
|
+
* ## Lưu ý khi viết test
|
|
291
|
+
*
|
|
292
|
+
* jsdom KHÔNG có `IntersectionObserver` (đo 2026-09-26: `typeof` trả
|
|
293
|
+
* `'undefined'`). Component tự bảo vệ bằng cách kiểm trước khi dùng, nên spec
|
|
294
|
+
* dựng được và khoá được phần hiển thị; còn việc đánh dấu theo cuộn phải
|
|
295
|
+
* nghiệm thu trên trình duyệt. Đừng giả lập `IntersectionObserver` rồi tưởng
|
|
296
|
+
* đã kiểm hành vi thật.
|
|
297
|
+
*/
|
|
298
|
+
declare class OlScrollspy {
|
|
299
|
+
private readonly elementRef;
|
|
300
|
+
private readonly destroyRef;
|
|
301
|
+
readonly items: _angular_core.InputSignal<OlScrollspyItem[]>;
|
|
302
|
+
readonly orientation: _angular_core.InputSignal<OlScrollspyOrientation>;
|
|
303
|
+
readonly ariaLabel: _angular_core.InputSignal<string>;
|
|
304
|
+
/**
|
|
305
|
+
* Vùng quan sát, theo cú pháp `rootMargin` của `IntersectionObserver`.
|
|
306
|
+
*
|
|
307
|
+
* Đổi giá trị này khi trang có thanh trên cố định: `-80px 0px -70% 0px` đẩy
|
|
308
|
+
* mép trên xuống dưới thanh đó.
|
|
309
|
+
*/
|
|
310
|
+
readonly rootMargin: _angular_core.InputSignal<string>;
|
|
311
|
+
/** Cuộn mượt khi bấm mục. Tắt nếu trang tự lo việc cuộn. */
|
|
312
|
+
readonly smoothScroll: _angular_core.InputSignal<boolean>;
|
|
313
|
+
/**
|
|
314
|
+
* Khung cuộn chứa nội dung. `null` (mặc định) nghĩa là cả trang.
|
|
315
|
+
*
|
|
316
|
+
* BẮT BUỘC truyền khi nội dung nằm trong một khung `overflow-y-auto` riêng:
|
|
317
|
+
* `IntersectionObserver` mặc định quan sát theo VIEWPORT, nên phần nào cũng
|
|
318
|
+
* "đang hiện" khi khung con nằm trong tầm mắt — đo được: cuộn khung con từ
|
|
319
|
+
* đầu tới đáy mà không mục nào sáng.
|
|
320
|
+
*/
|
|
321
|
+
readonly scrollRoot: _angular_core.InputSignal<HTMLElement | null>;
|
|
322
|
+
private readonly currentId;
|
|
323
|
+
/** `id` của phần đang xem. Rỗng khi chưa phần nào vào vùng quan sát. */
|
|
324
|
+
readonly activeId: _angular_core.Signal<string>;
|
|
325
|
+
readonly activeChange: _angular_core.OutputEmitterRef<string>;
|
|
326
|
+
private observer;
|
|
327
|
+
constructor();
|
|
328
|
+
private startObserving;
|
|
329
|
+
/** Khung (hoặc trang) đã cuộn tới sát đáy chưa — sai số 4px cho tròn số lẻ. */
|
|
330
|
+
private atBottom;
|
|
331
|
+
private stopObserving;
|
|
332
|
+
private setActive;
|
|
333
|
+
/**
|
|
334
|
+
* Bấm mục thì cuộn tới phần tương ứng và đánh dấu NGAY.
|
|
335
|
+
*
|
|
336
|
+
* Không đợi `IntersectionObserver` báo: cuộn mượt mất vài trăm mili giây, và
|
|
337
|
+
* trong quãng đó mục vừa bấm chưa sáng — người dùng tưởng bấm hụt.
|
|
338
|
+
*/
|
|
339
|
+
protected onClick(event: MouseEvent, item: OlScrollspyItem): void;
|
|
340
|
+
protected readonly navClasses: _angular_core.Signal<"block" | "block w-full overflow-x-auto">;
|
|
341
|
+
protected readonly listClasses: _angular_core.Signal<"flex flex-col gap-0.5 border-s border-default ps-0" | "flex items-center gap-1 border-b border-default">;
|
|
342
|
+
/**
|
|
343
|
+
* Class của một mục.
|
|
344
|
+
*
|
|
345
|
+
* Gom vào MỘT chuỗi qua ba-ngôi thay vì nhiều `[class.x]` rời: hai class
|
|
346
|
+
* cùng thuộc tính thì trình duyệt chọn theo thứ tự luật trong file CSS chứ
|
|
347
|
+
* không theo thứ tự viết, kết quả đổi theo bản build.
|
|
348
|
+
*/
|
|
349
|
+
protected linkClasses(item: OlScrollspyItem): string;
|
|
350
|
+
static ɵfac: _angular_core.ɵɵFactoryDeclaration<OlScrollspy, never>;
|
|
351
|
+
static ɵcmp: _angular_core.ɵɵComponentDeclaration<OlScrollspy, "ol-scrollspy", never, { "items": { "alias": "items"; "required": false; "isSignal": true; }; "orientation": { "alias": "orientation"; "required": false; "isSignal": true; }; "ariaLabel": { "alias": "ariaLabel"; "required": false; "isSignal": true; }; "rootMargin": { "alias": "rootMargin"; "required": false; "isSignal": true; }; "smoothScroll": { "alias": "smoothScroll"; "required": false; "isSignal": true; }; "scrollRoot": { "alias": "scrollRoot"; "required": false; "isSignal": true; }; }, { "activeChange": "activeChange"; }, never, never, true, never>;
|
|
352
|
+
}
|
|
353
|
+
|
|
249
354
|
type ButtonColor = 'default' | 'brand' | 'primary' | 'alternative' | 'secondary' | 'tertiary' | 'ghost' | 'success' | 'green' | 'danger' | 'red' | 'warning' | 'yellow' | 'dark' | 'light';
|
|
250
355
|
type ButtonSize = 'xs' | 'sm' | 'base' | 'l' | 'xl';
|
|
251
356
|
type OlButtonType = 'button' | 'submit' | 'reset';
|
|
@@ -952,6 +1057,178 @@ interface DatepickerPreset {
|
|
|
952
1057
|
range: () => [Date, Date];
|
|
953
1058
|
}
|
|
954
1059
|
|
|
1060
|
+
/**
|
|
1061
|
+
* Bảng chuẩn kích thước và trạng thái cho MỌI ô nhập của thư viện.
|
|
1062
|
+
*
|
|
1063
|
+
* ## Vì sao cần
|
|
1064
|
+
*
|
|
1065
|
+
* Chín component họ form từng tự khai kích thước riêng, và chúng trôi khỏi
|
|
1066
|
+
* nhau. Đo ngày 2026-09-23 trên chín component:
|
|
1067
|
+
*
|
|
1068
|
+
* thiếu cỡ `xl` 3 component (select · autocomplete · input-counter)
|
|
1069
|
+
* nền sai 3 component (autocomplete · timepicker · datepicker)
|
|
1070
|
+
* viền sai 5 component
|
|
1071
|
+
* đệm ngang lệch 2px ở cả ba cỡ đầu (datepicker so với input)
|
|
1072
|
+
* cỡ chữ `sm` lệch 2px (14px vs 12px)
|
|
1073
|
+
*
|
|
1074
|
+
* Nền và viền lệch **chỉ lộ ở chế độ tối**: sáng thì `--bg-secondary` và
|
|
1075
|
+
* `--bg-secondary-medium` cùng ra `#f9fafb`, tối thì `gray-950` vs `gray-800`.
|
|
1076
|
+
* Nên lỗi sống rất lâu — người dựng nhìn chế độ sáng, thấy giống hệt nhau.
|
|
1077
|
+
*
|
|
1078
|
+
* Đọc từ đây thì thêm ô nhập mới cũng tự khớp, và đổi thang chỉ sửa một chỗ.
|
|
1079
|
+
*
|
|
1080
|
+
* ## Không gộp chiều cao với đệm ngang
|
|
1081
|
+
*
|
|
1082
|
+
* Hai thứ tách riêng vì component có icon cần `ps-*` thay `px-*`. Gộp lại thì
|
|
1083
|
+
* mỗi component phải cắt chuỗi ra để bỏ phần đệm — dễ sai hơn là ghép vào.
|
|
1084
|
+
*/
|
|
1085
|
+
/** Bốn cỡ của họ form. Trùng `InputSize`, `SelectSize`, `DatepickerSize`. */
|
|
1086
|
+
type FieldSize = 'sm' | 'base' | 'lg' | 'xl';
|
|
1087
|
+
/** Ba trạng thái hiển thị. */
|
|
1088
|
+
type FieldState = 'default' | 'error' | 'success';
|
|
1089
|
+
/**
|
|
1090
|
+
* Chiều cao theo cỡ — **cố định bằng `h-*`**, không suy từ `py-*`.
|
|
1091
|
+
*
|
|
1092
|
+
* Suy từ đệm dọc thì chiều cao phụ thuộc `line-height` của cỡ chữ và không
|
|
1093
|
+
* bao giờ khớp thang chung. Đo trước khi chuẩn hoá: datepicker ra 34/42/54
|
|
1094
|
+
* trong khi input ra 36/40/48 — đặt cạnh nhau là so le ngay, nặng nhất ở `lg`.
|
|
1095
|
+
*
|
|
1096
|
+
* `xl` (52px) là cỡ mới nhất; ba component còn thiếu nó sẽ so le 12px khi đặt
|
|
1097
|
+
* cạnh một `ol-input size="xl"`.
|
|
1098
|
+
*/
|
|
1099
|
+
declare const FIELD_HEIGHT: Record<FieldSize, string>;
|
|
1100
|
+
/**
|
|
1101
|
+
* Chiều cao TỐI THIỂU — cho component cao theo nội dung.
|
|
1102
|
+
*
|
|
1103
|
+
* `ol-select` nhiều lựa chọn, `ol-tag-input` nhiều thẻ: chúng phải giãn ra khi
|
|
1104
|
+
* nội dung xuống dòng, nên `h-*` cố định sẽ cắt mất. Giá trị bằng đúng
|
|
1105
|
+
* `FIELD_HEIGHT` để một dòng vẫn cao bằng các ô khác.
|
|
1106
|
+
*/
|
|
1107
|
+
declare const FIELD_MIN_HEIGHT: Record<FieldSize, string>;
|
|
1108
|
+
/**
|
|
1109
|
+
* Đệm ngang theo Figma `ol-input`: sm 10px · base 12px · lg 14px · xl 16px.
|
|
1110
|
+
*
|
|
1111
|
+
* KHÔNG dùng `[class.px-2.5]` trên template: Angular cắt phần sau dấu chấm
|
|
1112
|
+
* nên nó render ra `px-2`, lệch 2px so với thiết kế. Phải gom vào một chuỗi.
|
|
1113
|
+
*/
|
|
1114
|
+
declare const FIELD_PADDING_X: Record<FieldSize, string>;
|
|
1115
|
+
/**
|
|
1116
|
+
* `FIELD_PADDING_X` tách hai đầu — cho ô có icon: phần tử ĐẦU TIÊN trong khung
|
|
1117
|
+
* (icon hoặc ô gõ) nhận lề đầu, phần tử CUỐI nhận lề cuối, ở giữa chỉ còn
|
|
1118
|
+
* `FIELD_ICON_GAP`.
|
|
1119
|
+
*/
|
|
1120
|
+
declare const FIELD_PADDING_START: Record<FieldSize, string>;
|
|
1121
|
+
declare const FIELD_PADDING_END: Record<FieldSize, string>;
|
|
1122
|
+
/**
|
|
1123
|
+
* Icon ↔ chữ trong khung: 8px, mọi cỡ — Figma `ol-input` (1149:46826) và
|
|
1124
|
+
* `ol-timepicker` (1149:52243) đều `itemSpacing: 8`.
|
|
1125
|
+
*
|
|
1126
|
+
* Chỉ một nguồn tạo khoảng này. Bản cũ của `ol-input` có cả `gap-2` ở khung
|
|
1127
|
+
* lẫn `ps-2.5`/`pe-2.5` ở ô gõ → icon cách chữ 18px (đo 2026-09-29).
|
|
1128
|
+
*/
|
|
1129
|
+
declare const FIELD_ICON_GAP = "gap-2";
|
|
1130
|
+
/**
|
|
1131
|
+
* Đệm dọc của khung CHỌN NHIỀU (chip cao 24px). Nhãn nổi Bordered nằm vắt
|
|
1132
|
+
* qua viền trên, nửa dưới lấn vào khung ~10px — đệm 4px thường lệ để chip
|
|
1133
|
+
* nằm dưới chữ nhãn (đo 2026-09-29: đè 3px, 32/96 ô). Chừa 10px thì một
|
|
1134
|
+
* dòng chip vẫn cao đúng 40px: 1 + 10 + 24 + 4 + 1.
|
|
1135
|
+
*/
|
|
1136
|
+
declare function multiValuePadY(floatingOutlined: boolean): string;
|
|
1137
|
+
/**
|
|
1138
|
+
* Chỗ dành cho icon 16px nằm `absolute` ở đầu/cuối khung: lề cỡ + 16px +
|
|
1139
|
+
* `FIELD_ICON_GAP` 8px. Dùng khi icon ra khỏi luồng (select, autocomplete
|
|
1140
|
+
* chọn nhiều) nên khung phải tự chừa chỗ.
|
|
1141
|
+
*/
|
|
1142
|
+
declare const FIELD_ICON_RESERVE_START: Record<FieldSize, string>;
|
|
1143
|
+
declare const FIELD_ICON_RESERVE_END: Record<FieldSize, string>;
|
|
1144
|
+
/** Chỗ cho nút xoá 14px (`close` cỡ xs) nằm `absolute` cuối ô: lề cỡ + 14 + 8. */
|
|
1145
|
+
declare const FIELD_CLEAR_RESERVE_END: Record<FieldSize, string>;
|
|
1146
|
+
/**
|
|
1147
|
+
* Như `FIELD_ICON_RESERVE_START` nhưng cho icon lịch của datepicker, vốn to
|
|
1148
|
+
* theo cỡ ô (14 / 16 / 20 / 20px): lề cỡ + icon + 8px = 32 / 36 / 42 / 44.
|
|
1149
|
+
*/
|
|
1150
|
+
declare const PICKER_ICON_RESERVE_START: Record<FieldSize, string>;
|
|
1151
|
+
/**
|
|
1152
|
+
* Cỡ chữ theo cỡ ô.
|
|
1153
|
+
*
|
|
1154
|
+
* `sm` là **14px** (`text-sm`), không phải 12px. Datepicker từng dùng
|
|
1155
|
+
* `text-xs` nên chữ trong ô nhỏ hơn hẳn các ô cùng hàng.
|
|
1156
|
+
*/
|
|
1157
|
+
declare const FIELD_TEXT: Record<FieldSize, string>;
|
|
1158
|
+
/**
|
|
1159
|
+
* Nền · viền · vòng focus theo trạng thái.
|
|
1160
|
+
*
|
|
1161
|
+
* Dùng `-medium` cho cả nền lẫn viền ở trạng thái thường. Hai tên gần giống
|
|
1162
|
+
* nhau (`bg-neutral-secondary` vs `bg-neutral-secondary-medium`) nhưng **khác
|
|
1163
|
+
* hẳn ở chế độ tối**, nên nhầm một chữ là ô đó lệch màu mà chế độ sáng không
|
|
1164
|
+
* lộ ra.
|
|
1165
|
+
*
|
|
1166
|
+
* Dùng `focus-within:` chứ không `focus:`: viền nằm trên thẻ bọc, còn focus
|
|
1167
|
+
* rơi vào `<input>` bên trong. `focus:` trên thẻ bọc không bao giờ khớp.
|
|
1168
|
+
*/
|
|
1169
|
+
declare const FIELD_STATE: Record<FieldState, string>;
|
|
1170
|
+
/** Nền và con trỏ khi ô bị khoá. Áp đè lên `FIELD_STATE`. */
|
|
1171
|
+
declare const FIELD_DISABLED = "bg-disabled opacity-60 cursor-not-allowed";
|
|
1172
|
+
/** Bo góc — 12px cho mọi cỡ, theo Figma `bieu-mau.md`. */
|
|
1173
|
+
declare const FIELD_RADIUS = "rounded-md";
|
|
1174
|
+
/**
|
|
1175
|
+
* Lớp của nhãn phía trên ô.
|
|
1176
|
+
*
|
|
1177
|
+
* `text-heading` chứ không `text-body`: nhãn là thứ người dùng đọc đầu tiên để
|
|
1178
|
+
* biết ô này hỏi gì, nó phải đậm hơn chữ phụ.
|
|
1179
|
+
*/
|
|
1180
|
+
declare const FIELD_LABEL = "inline-flex items-center gap-1 text-sm font-medium text-heading";
|
|
1181
|
+
/** Khoảng cách nhãn → ô. */
|
|
1182
|
+
declare const FIELD_LABEL_GAP = "mb-1.5";
|
|
1183
|
+
/**
|
|
1184
|
+
* Vị trí nhãn so với ô: `top` (mặc định, nhãn trên ô) hoặc `left` (nhãn cùng
|
|
1185
|
+
* hàng, bên trái — form dạng bảng: cài đặt, hồ sơ). Nhãn nổi thắng cả hai.
|
|
1186
|
+
*/
|
|
1187
|
+
type LabelPosition = 'top' | 'left';
|
|
1188
|
+
/**
|
|
1189
|
+
* Khung ngoài của host khi nhãn `left`: lưới 2 cột. Cột 1 = nhãn, rộng theo
|
|
1190
|
+
* `--ol-label-w` (input `labelWidth`, mặc định 8rem). Cột 2 = mọi thứ còn lại
|
|
1191
|
+
* — khung nhập, dòng gợi ý/lỗi — nên chữ lỗi thẳng mép ô, không chui xuống
|
|
1192
|
+
* dưới nhãn. `[&>ol-field-label]` cụ thể hơn `[&>*]` nên nhãn thắng cột.
|
|
1193
|
+
*/
|
|
1194
|
+
declare const FIELD_LABEL_BESIDE = "grid grid-cols-[var(--ol-label-w,8rem)_minmax(0,1fr)] items-start gap-x-3 [&>*]:col-start-2 [&>ol-field-label]:col-start-1 [&>ol-field-label]:row-start-1";
|
|
1195
|
+
/** Lớp khung ngoài theo vị trí nhãn — rỗng khi nhãn trên hoặc nhãn nổi. */
|
|
1196
|
+
declare function fieldLabelLayout(position: LabelPosition, floating: boolean): string;
|
|
1197
|
+
/** Dấu sao bắt buộc. */
|
|
1198
|
+
declare const FIELD_ASTERISK = "text-fg-danger font-bold";
|
|
1199
|
+
/**
|
|
1200
|
+
* Chữ trợ giúp dưới ô, đổi màu theo trạng thái.
|
|
1201
|
+
*
|
|
1202
|
+
* Trạng thái lỗi mà chữ vẫn màu phụ thì người dùng không biết dòng đó là lời
|
|
1203
|
+
* giải thích lỗi hay chú thích thường.
|
|
1204
|
+
*/
|
|
1205
|
+
declare const FIELD_HELPER: Record<FieldState, string>;
|
|
1206
|
+
/** Khoảng cách ô → chữ trợ giúp. */
|
|
1207
|
+
declare const FIELD_HELPER_GAP = "mt-1.5";
|
|
1208
|
+
/**
|
|
1209
|
+
* Gộp chiều cao · đệm ngang · cỡ chữ · bo góc cho một cỡ.
|
|
1210
|
+
*
|
|
1211
|
+
* Tiện cho component không có icon. Component có icon tự ghép từ các bảng
|
|
1212
|
+
* riêng để thay `px-*` bằng `ps-*`.
|
|
1213
|
+
*/
|
|
1214
|
+
declare function fieldSizeClasses(size: FieldSize): string;
|
|
1215
|
+
/**
|
|
1216
|
+
* Ba kiểu nhãn nổi — Figma `ol-floating-label` (#1149:50454) trục `Type`:
|
|
1217
|
+
*
|
|
1218
|
+
* - `outlined` — **Bordered**: viền đủ, nhãn nổi nằm ĐÈ lên viền trên.
|
|
1219
|
+
* - `filled` — **With background**: nền xám + gạch chân 2px, nhãn nổi thành
|
|
1220
|
+
* một hàng 20px ở trên, nằm trong nền.
|
|
1221
|
+
* - `standard` — **Default**: chỉ gạch chân 2px, nhãn nổi thành hàng 20px ở trên.
|
|
1222
|
+
*/
|
|
1223
|
+
type FloatingVariant = 'outlined' | 'filled' | 'standard';
|
|
1224
|
+
/**
|
|
1225
|
+
* Vị trí ngang của nhãn KHI NỔI (px) = đệm ngang của ô (`FIELD_PADDING_X`) —
|
|
1226
|
+
* Figma đặt nhãn nổi thẳng mép chữ, kể cả khi có icon đầu (nhãn nổi lên trên
|
|
1227
|
+
* cột icon). Phải là SỐ vì nhãn đặt bằng `style.left`, cùng hệ với vị trí nằm
|
|
1228
|
+
* yên (đo lúc chạy).
|
|
1229
|
+
*/
|
|
1230
|
+
declare const FLOAT_LABEL_START: Record<FieldSize, number>;
|
|
1231
|
+
|
|
955
1232
|
declare class OlDatepickerStateService {
|
|
956
1233
|
readonly viewMode: _angular_core.WritableSignal<DatepickerViewMode>;
|
|
957
1234
|
readonly viewDate: _angular_core.WritableSignal<Date>;
|
|
@@ -999,7 +1276,11 @@ declare class OlDatepickerStateService {
|
|
|
999
1276
|
}
|
|
1000
1277
|
|
|
1001
1278
|
declare class OlDatepicker implements ControlValueAccessor {
|
|
1002
|
-
|
|
1279
|
+
/**
|
|
1280
|
+
* Trạng thái lịch (ngày đang xem, khoảng đã chọn…). Tên cũ `state` nhường
|
|
1281
|
+
* cho input `state` (lỗi / thành công) — cùng tên với mọi ô nhập khác.
|
|
1282
|
+
*/
|
|
1283
|
+
readonly pickerState: OlDatepickerStateService;
|
|
1003
1284
|
private readonly hostEl;
|
|
1004
1285
|
/** Id do nơi gọi truyền; trống thì dùng id tự sinh bên dưới. */
|
|
1005
1286
|
readonly id: _angular_core.InputSignal<string>;
|
|
@@ -1013,6 +1294,33 @@ declare class OlDatepicker implements ControlValueAccessor {
|
|
|
1013
1294
|
readonly value: _angular_core.ModelSignal<Date | null>;
|
|
1014
1295
|
readonly placeholder: _angular_core.InputSignal<string>;
|
|
1015
1296
|
readonly label: _angular_core.InputSignal<string>;
|
|
1297
|
+
/**
|
|
1298
|
+
* Trạng thái hiển thị — lỗi / thành công, cùng thang `FIELD_STATE` với mọi ô
|
|
1299
|
+
* nhập khác. Trước đây datepicker không có (tên `state` bị service chiếm).
|
|
1300
|
+
*/
|
|
1301
|
+
readonly state: _angular_core.InputSignal<FieldState>;
|
|
1302
|
+
/**
|
|
1303
|
+
* Nhãn nổi: `label` nằm TRONG khung (sau icon lịch), nổi lên khi focus, mở
|
|
1304
|
+
* lịch hoặc đã có ngày (kể cả chữ đang gõ dở).
|
|
1305
|
+
*/
|
|
1306
|
+
readonly floatingLabel: _angular_core.InputSignal<boolean>;
|
|
1307
|
+
/**
|
|
1308
|
+
* Nhãn `top` (trên ô, mặc định) hay `left` (cùng hàng, bên trái). Nhãn nổi
|
|
1309
|
+
* (`floatingLabel`) thắng — bật nó thì bỏ qua input này.
|
|
1310
|
+
*/
|
|
1311
|
+
readonly labelPosition: _angular_core.InputSignal<LabelPosition>;
|
|
1312
|
+
/**
|
|
1313
|
+
* Độ rộng cột nhãn khi `labelPosition="left"` — độ dài CSS bất kỳ: `140px`,
|
|
1314
|
+
* `10rem`, `30%`. Bỏ trống = 8rem. Các ô trong cùng form đặt cùng một số thì
|
|
1315
|
+
* mép ô thẳng hàng.
|
|
1316
|
+
*/
|
|
1317
|
+
readonly labelWidth: _angular_core.InputSignal<string>;
|
|
1318
|
+
protected readonly labelLayout: _angular_core.Signal<string>;
|
|
1319
|
+
protected readonly labelBeside: _angular_core.Signal<boolean>;
|
|
1320
|
+
/** Khung nhãn + ô: cột dọc (nhãn trên) hoặc lưới 2 cột (nhãn trái). */
|
|
1321
|
+
protected readonly stackClasses: _angular_core.Signal<string>;
|
|
1322
|
+
/** Kiểu nhãn nổi — Figma Bordered / With background / Default. */
|
|
1323
|
+
readonly floatingVariant: _angular_core.InputSignal<FloatingVariant>;
|
|
1016
1324
|
readonly helperText: _angular_core.InputSignal<string>;
|
|
1017
1325
|
readonly required: _angular_core.InputSignal<boolean>;
|
|
1018
1326
|
/**
|
|
@@ -1103,6 +1411,16 @@ declare class OlDatepicker implements ControlValueAccessor {
|
|
|
1103
1411
|
* ngang và `ps-*` cho chỗ icon lịch.
|
|
1104
1412
|
*/
|
|
1105
1413
|
readonly inputSizeClasses: _angular_core.Signal<string>;
|
|
1414
|
+
private readonly sizeClasses;
|
|
1415
|
+
protected readonly showClear: _angular_core.Signal<boolean>;
|
|
1416
|
+
/**
|
|
1417
|
+
* `ms-px`/`me-px`: div bọc icon tính từ mép NGOÀI viền 1px của ô, còn đệm
|
|
1418
|
+
* ô tính từ mép trong. Nhãn nổi `filled`/`standard` không có viền hai bên
|
|
1419
|
+
* (chỉ gạch dưới) thì không bù.
|
|
1420
|
+
*/
|
|
1421
|
+
private readonly sideBorder;
|
|
1422
|
+
protected readonly leadPadClass: _angular_core.Signal<string>;
|
|
1423
|
+
protected readonly trailPadClass: _angular_core.Signal<string>;
|
|
1106
1424
|
/**
|
|
1107
1425
|
* Cỡ icon lịch theo `size` của ô nhập.
|
|
1108
1426
|
*
|
|
@@ -1157,17 +1475,57 @@ declare class OlDatepicker implements ControlValueAccessor {
|
|
|
1157
1475
|
*/
|
|
1158
1476
|
ngOnDestroy(): void;
|
|
1159
1477
|
static ɵfac: _angular_core.ɵɵFactoryDeclaration<OlDatepicker, never>;
|
|
1160
|
-
static ɵcmp: _angular_core.ɵɵComponentDeclaration<OlDatepicker, "ol-datepicker", never, { "id": { "alias": "id"; "required": false; "isSignal": true; }; "value": { "alias": "value"; "required": false; "isSignal": true; }; "placeholder": { "alias": "placeholder"; "required": false; "isSignal": true; }; "label": { "alias": "label"; "required": false; "isSignal": true; }; "helperText": { "alias": "helperText"; "required": false; "isSignal": true; }; "required": { "alias": "required"; "required": false; "isSignal": true; }; "disabled": { "alias": "disabled"; "required": false; "isSignal": true; }; "format": { "alias": "format"; "required": false; "isSignal": true; }; "minDate": { "alias": "minDate"; "required": false; "isSignal": true; }; "maxDate": { "alias": "maxDate"; "required": false; "isSignal": true; }; "daysDisabled": { "alias": "daysDisabled"; "required": false; "isSignal": true; }; "datesDisabled": { "alias": "datesDisabled"; "required": false; "isSignal": true; }; "datesEnabled": { "alias": "datesEnabled"; "required": false; "isSignal": true; }; "appendTo": { "alias": "appendTo"; "required": false; "isSignal": true; }; "showFooter": { "alias": "showFooter"; "required": false; "isSignal": true; }; "inline": { "alias": "inline"; "required": false; "isSignal": true; }; "size": { "alias": "size"; "required": false; "isSignal": true; }; "clearable": { "alias": "clearable"; "required": false; "isSignal": true; }; }, { "value": "valueChange"; "disabled": "disabledChange"; "dateChange": "dateChange"; "timestampChange": "timestampChange"; "isoChange": "isoChange"; "formattedChange": "formattedChange"; }, never, never, true, never>;
|
|
1478
|
+
static ɵcmp: _angular_core.ɵɵComponentDeclaration<OlDatepicker, "ol-datepicker", never, { "id": { "alias": "id"; "required": false; "isSignal": true; }; "value": { "alias": "value"; "required": false; "isSignal": true; }; "placeholder": { "alias": "placeholder"; "required": false; "isSignal": true; }; "label": { "alias": "label"; "required": false; "isSignal": true; }; "state": { "alias": "state"; "required": false; "isSignal": true; }; "floatingLabel": { "alias": "floatingLabel"; "required": false; "isSignal": true; }; "labelPosition": { "alias": "labelPosition"; "required": false; "isSignal": true; }; "labelWidth": { "alias": "labelWidth"; "required": false; "isSignal": true; }; "floatingVariant": { "alias": "floatingVariant"; "required": false; "isSignal": true; }; "helperText": { "alias": "helperText"; "required": false; "isSignal": true; }; "required": { "alias": "required"; "required": false; "isSignal": true; }; "disabled": { "alias": "disabled"; "required": false; "isSignal": true; }; "format": { "alias": "format"; "required": false; "isSignal": true; }; "minDate": { "alias": "minDate"; "required": false; "isSignal": true; }; "maxDate": { "alias": "maxDate"; "required": false; "isSignal": true; }; "daysDisabled": { "alias": "daysDisabled"; "required": false; "isSignal": true; }; "datesDisabled": { "alias": "datesDisabled"; "required": false; "isSignal": true; }; "datesEnabled": { "alias": "datesEnabled"; "required": false; "isSignal": true; }; "appendTo": { "alias": "appendTo"; "required": false; "isSignal": true; }; "showFooter": { "alias": "showFooter"; "required": false; "isSignal": true; }; "inline": { "alias": "inline"; "required": false; "isSignal": true; }; "size": { "alias": "size"; "required": false; "isSignal": true; }; "clearable": { "alias": "clearable"; "required": false; "isSignal": true; }; }, { "value": "valueChange"; "disabled": "disabledChange"; "dateChange": "dateChange"; "timestampChange": "timestampChange"; "isoChange": "isoChange"; "formattedChange": "formattedChange"; }, never, never, true, never>;
|
|
1161
1479
|
}
|
|
1162
1480
|
|
|
1163
1481
|
type OlDateRangePickerVariant = 'dual-inputs' | 'joined';
|
|
1164
1482
|
declare class OlDateRangePicker implements ControlValueAccessor {
|
|
1165
|
-
|
|
1483
|
+
/**
|
|
1484
|
+
* Trạng thái lịch (ngày đang xem, khoảng đã chọn…). Tên cũ `state` nhường
|
|
1485
|
+
* cho input `state` (lỗi / thành công) — cùng tên với mọi ô nhập khác.
|
|
1486
|
+
*/
|
|
1487
|
+
readonly pickerState: OlDatepickerStateService;
|
|
1166
1488
|
private readonly hostEl;
|
|
1167
1489
|
readonly value: _angular_core.ModelSignal<DateRange | null>;
|
|
1168
1490
|
readonly startPlaceholder: _angular_core.InputSignal<string>;
|
|
1169
1491
|
readonly endPlaceholder: _angular_core.InputSignal<string>;
|
|
1170
1492
|
readonly label: _angular_core.InputSignal<string>;
|
|
1493
|
+
/** Lỗi / thành công — cùng thang `FIELD_STATE` với mọi ô nhập khác. */
|
|
1494
|
+
readonly state: _angular_core.InputSignal<FieldState>;
|
|
1495
|
+
/**
|
|
1496
|
+
* Nhãn nổi. `joined`: một nhãn (`label`) cho cả khung. `dual-inputs`: mỗi ô
|
|
1497
|
+
* một nhãn (`fromLabel` / `toLabel`), nổi riêng theo ô đó có ngày hay không.
|
|
1498
|
+
*/
|
|
1499
|
+
readonly floatingLabel: _angular_core.InputSignal<boolean>;
|
|
1500
|
+
/**
|
|
1501
|
+
* Nhãn `top` (trên ô, mặc định) hay `left` (cùng hàng, bên trái). Nhãn nổi
|
|
1502
|
+
* (`floatingLabel`) thắng — bật nó thì bỏ qua input này.
|
|
1503
|
+
*/
|
|
1504
|
+
readonly labelPosition: _angular_core.InputSignal<LabelPosition>;
|
|
1505
|
+
/**
|
|
1506
|
+
* Độ rộng cột nhãn khi `labelPosition="left"` — độ dài CSS bất kỳ: `140px`,
|
|
1507
|
+
* `10rem`, `30%`. Bỏ trống = 8rem. Các ô trong cùng form đặt cùng một số thì
|
|
1508
|
+
* mép ô thẳng hàng.
|
|
1509
|
+
*/
|
|
1510
|
+
readonly labelWidth: _angular_core.InputSignal<string>;
|
|
1511
|
+
protected readonly labelLayout: _angular_core.Signal<string>;
|
|
1512
|
+
protected readonly labelBeside: _angular_core.Signal<boolean>;
|
|
1513
|
+
/**
|
|
1514
|
+
* `joined`: một nhãn cho cả khung → khung ngoài thành lưới. `dual-inputs`:
|
|
1515
|
+
* mỗi ô một nhãn ("Từ" / "Đến") → khung ngoài giữ cột dọc, từng CỘT thành lưới.
|
|
1516
|
+
*/
|
|
1517
|
+
protected readonly stackClasses: _angular_core.Signal<string>;
|
|
1518
|
+
protected readonly columnClasses: _angular_core.Signal<string>;
|
|
1519
|
+
/** Kiểu nhãn nổi — Figma Bordered / With background / Default. */
|
|
1520
|
+
readonly floatingVariant: _angular_core.InputSignal<FloatingVariant>;
|
|
1521
|
+
/**
|
|
1522
|
+
* Id hai ô `dual-inputs` — để `<label for>` nối được. Bản cũ hai nhãn
|
|
1523
|
+
* "Từ"/"Đến" KHÔNG có `for`, ô không có id: bấm nhãn không focus, trình đọc
|
|
1524
|
+
* màn hình đọc hai ô không tên.
|
|
1525
|
+
*/
|
|
1526
|
+
private readonly uid;
|
|
1527
|
+
readonly startInputId: string;
|
|
1528
|
+
readonly endInputId: string;
|
|
1171
1529
|
readonly fromLabel: _angular_core.InputSignal<string>;
|
|
1172
1530
|
readonly toLabel: _angular_core.InputSignal<string>;
|
|
1173
1531
|
readonly showInfoIcon: _angular_core.InputSignal<boolean>;
|
|
@@ -1241,7 +1599,27 @@ declare class OlDateRangePicker implements ControlValueAccessor {
|
|
|
1241
1599
|
* dùng y hệt `py-2 / py-2.5 / py-3.5` nên lệch cùng một kiểu; sửa một nửa là
|
|
1242
1600
|
* để lại đúng lỗi đó ở chỗ khác.
|
|
1243
1601
|
*/
|
|
1602
|
+
/**
|
|
1603
|
+
* Hai ô của dạng `dual-inputs`: icon lịch ở lề theo cỡ, chữ cách icon 8px.
|
|
1604
|
+
* Ô "Đến" mang nút xoá `absolute` nên lề phải chừa chỗ cho nó.
|
|
1605
|
+
*/
|
|
1244
1606
|
readonly inputSizeClasses: _angular_core.Signal<string>;
|
|
1607
|
+
readonly endInputClasses: _angular_core.Signal<string>;
|
|
1608
|
+
private inputClasses;
|
|
1609
|
+
protected readonly showClear: _angular_core.Signal<boolean>;
|
|
1610
|
+
/**
|
|
1611
|
+
* `ms-px`/`me-px`: div bọc icon tính từ mép NGOÀI viền 1px của ô, còn đệm
|
|
1612
|
+
* ô tính từ mép trong. Nhãn nổi `filled`/`standard` không có viền hai bên
|
|
1613
|
+
* (chỉ gạch dưới) thì không bù.
|
|
1614
|
+
*/
|
|
1615
|
+
private readonly sideBorder;
|
|
1616
|
+
protected readonly leadPadClass: _angular_core.Signal<string>;
|
|
1617
|
+
protected readonly trailPadClass: _angular_core.Signal<string>;
|
|
1618
|
+
/**
|
|
1619
|
+
* Dạng `joined`: khung có `p-1` (4px), nên icon lùi thêm lề cỡ − 4px để
|
|
1620
|
+
* mép icon cách viền đúng lề cỡ như mọi ô; chữ cách icon 8px.
|
|
1621
|
+
*/
|
|
1622
|
+
protected readonly joinedIconPadClass: _angular_core.Signal<string>;
|
|
1245
1623
|
/**
|
|
1246
1624
|
* Cỡ cho biến thể `joined` — khung bọc mang viền, hai input bên trong trong
|
|
1247
1625
|
* suốt. Phải tách khỏi `inputSizeClasses()`: ở đây chiều cao thuộc về KHUNG,
|
|
@@ -1256,9 +1634,10 @@ declare class OlDateRangePicker implements ControlValueAccessor {
|
|
|
1256
1634
|
* Khung có `p-1` = 4px mỗi cạnh, nên input con lùi 8px để TỔNG chiều cao
|
|
1257
1635
|
* khớp thang: h-9 → h-7, h-10 → h-8, h-12 → h-10, h-13 → h-11.
|
|
1258
1636
|
*/
|
|
1259
|
-
readonly joinedWrapperClasses: _angular_core.Signal<
|
|
1637
|
+
readonly joinedWrapperClasses: _angular_core.Signal<string>;
|
|
1638
|
+
private readonly joinedHeight;
|
|
1260
1639
|
/** Input bên trong khung `joined` — trừ đi `p-1` của khung. */
|
|
1261
|
-
readonly joinedInputClasses: _angular_core.Signal<
|
|
1640
|
+
readonly joinedInputClasses: _angular_core.Signal<string>;
|
|
1262
1641
|
writeValue(val: DateRange | null): void;
|
|
1263
1642
|
registerOnChange(fn: (val: DateRange | null) => void): void;
|
|
1264
1643
|
registerOnTouched(fn: () => void): void;
|
|
@@ -1294,7 +1673,7 @@ declare class OlDateRangePicker implements ControlValueAccessor {
|
|
|
1294
1673
|
*/
|
|
1295
1674
|
ngOnDestroy(): void;
|
|
1296
1675
|
static ɵfac: _angular_core.ɵɵFactoryDeclaration<OlDateRangePicker, never>;
|
|
1297
|
-
static ɵcmp: _angular_core.ɵɵComponentDeclaration<OlDateRangePicker, "ol-date-range-picker", never, { "value": { "alias": "value"; "required": false; "isSignal": true; }; "startPlaceholder": { "alias": "startPlaceholder"; "required": false; "isSignal": true; }; "endPlaceholder": { "alias": "endPlaceholder"; "required": false; "isSignal": true; }; "label": { "alias": "label"; "required": false; "isSignal": true; }; "fromLabel": { "alias": "fromLabel"; "required": false; "isSignal": true; }; "toLabel": { "alias": "toLabel"; "required": false; "isSignal": true; }; "showInfoIcon": { "alias": "showInfoIcon"; "required": false; "isSignal": true; }; "variant": { "alias": "variant"; "required": false; "isSignal": true; }; "dualMonth": { "alias": "dualMonth"; "required": false; "isSignal": true; }; "helperText": { "alias": "helperText"; "required": false; "isSignal": true; }; "required": { "alias": "required"; "required": false; "isSignal": true; }; "disabled": { "alias": "disabled"; "required": false; "isSignal": true; }; "format": { "alias": "format"; "required": false; "isSignal": true; }; "minDate": { "alias": "minDate"; "required": false; "isSignal": true; }; "maxDate": { "alias": "maxDate"; "required": false; "isSignal": true; }; "daysDisabled": { "alias": "daysDisabled"; "required": false; "isSignal": true; }; "datesDisabled": { "alias": "datesDisabled"; "required": false; "isSignal": true; }; "datesEnabled": { "alias": "datesEnabled"; "required": false; "isSignal": true; }; "appendTo": { "alias": "appendTo"; "required": false; "isSignal": true; }; "showFooter": { "alias": "showFooter"; "required": false; "isSignal": true; }; "presets": { "alias": "presets"; "required": false; "isSignal": true; }; "inline": { "alias": "inline"; "required": false; "isSignal": true; }; "size": { "alias": "size"; "required": false; "isSignal": true; }; "clearable": { "alias": "clearable"; "required": false; "isSignal": true; }; }, { "value": "valueChange"; "disabled": "disabledChange"; "rangeChange": "rangeChange"; }, never, never, true, never>;
|
|
1676
|
+
static ɵcmp: _angular_core.ɵɵComponentDeclaration<OlDateRangePicker, "ol-date-range-picker", never, { "value": { "alias": "value"; "required": false; "isSignal": true; }; "startPlaceholder": { "alias": "startPlaceholder"; "required": false; "isSignal": true; }; "endPlaceholder": { "alias": "endPlaceholder"; "required": false; "isSignal": true; }; "label": { "alias": "label"; "required": false; "isSignal": true; }; "state": { "alias": "state"; "required": false; "isSignal": true; }; "floatingLabel": { "alias": "floatingLabel"; "required": false; "isSignal": true; }; "labelPosition": { "alias": "labelPosition"; "required": false; "isSignal": true; }; "labelWidth": { "alias": "labelWidth"; "required": false; "isSignal": true; }; "floatingVariant": { "alias": "floatingVariant"; "required": false; "isSignal": true; }; "fromLabel": { "alias": "fromLabel"; "required": false; "isSignal": true; }; "toLabel": { "alias": "toLabel"; "required": false; "isSignal": true; }; "showInfoIcon": { "alias": "showInfoIcon"; "required": false; "isSignal": true; }; "variant": { "alias": "variant"; "required": false; "isSignal": true; }; "dualMonth": { "alias": "dualMonth"; "required": false; "isSignal": true; }; "helperText": { "alias": "helperText"; "required": false; "isSignal": true; }; "required": { "alias": "required"; "required": false; "isSignal": true; }; "disabled": { "alias": "disabled"; "required": false; "isSignal": true; }; "format": { "alias": "format"; "required": false; "isSignal": true; }; "minDate": { "alias": "minDate"; "required": false; "isSignal": true; }; "maxDate": { "alias": "maxDate"; "required": false; "isSignal": true; }; "daysDisabled": { "alias": "daysDisabled"; "required": false; "isSignal": true; }; "datesDisabled": { "alias": "datesDisabled"; "required": false; "isSignal": true; }; "datesEnabled": { "alias": "datesEnabled"; "required": false; "isSignal": true; }; "appendTo": { "alias": "appendTo"; "required": false; "isSignal": true; }; "showFooter": { "alias": "showFooter"; "required": false; "isSignal": true; }; "presets": { "alias": "presets"; "required": false; "isSignal": true; }; "inline": { "alias": "inline"; "required": false; "isSignal": true; }; "size": { "alias": "size"; "required": false; "isSignal": true; }; "clearable": { "alias": "clearable"; "required": false; "isSignal": true; }; }, { "value": "valueChange"; "disabled": "disabledChange"; "rangeChange": "rangeChange"; }, never, never, true, never>;
|
|
1298
1677
|
}
|
|
1299
1678
|
|
|
1300
1679
|
declare class OlDatepickerDirective implements OnDestroy {
|
|
@@ -1629,6 +2008,8 @@ declare class OlDropdown {
|
|
|
1629
2008
|
private detachMenu;
|
|
1630
2009
|
/** Hàm gỡ khỏi ngăn xếp Escape. `null` khi đang đóng. */
|
|
1631
2010
|
private releaseEscape;
|
|
2011
|
+
/** Hàm gỡ listener Tab trên panel. `null` khi đang đóng. */
|
|
2012
|
+
private releaseMenuKeydown;
|
|
1632
2013
|
readonly label: _angular_core.InputSignal<string | null>;
|
|
1633
2014
|
readonly isOpen: _angular_core.ModelSignal<boolean>;
|
|
1634
2015
|
/**
|
|
@@ -1679,6 +2060,75 @@ declare class OlDropdown {
|
|
|
1679
2060
|
onTriggerClick(): void;
|
|
1680
2061
|
onMouseEnter(): void;
|
|
1681
2062
|
onMouseLeave(): void;
|
|
2063
|
+
/**
|
|
2064
|
+
* Danh sách phần tử nhận được tiêu điểm, theo thứ tự nhìn thấy.
|
|
2065
|
+
*
|
|
2066
|
+
* `tabindex="-1"` bị loại: đó là dấu hiệu tác giả cố ý đưa phần tử ra khỏi
|
|
2067
|
+
* đường Tab. `:disabled` cũng loại — trình duyệt không cho nó nhận tiêu điểm.
|
|
2068
|
+
*
|
|
2069
|
+
* Lọc phần ẩn bằng `[hidden]`/`[aria-hidden]` chứ KHÔNG `offsetParent`:
|
|
2070
|
+
* `offsetParent` là `null` với mọi phần tử trong `position: fixed`, và luôn
|
|
2071
|
+
* `null` trong jsdom — dùng nó thì danh sách rỗng, hàm thoát sớm, và toàn bộ
|
|
2072
|
+
* xử lý Tab lặng lẽ không chạy. Đã mắc: spec đỏ 3 ca trong khi trình duyệt
|
|
2073
|
+
* thật vẫn đúng, vì hai môi trường cho `offsetParent` khác nhau.
|
|
2074
|
+
*/
|
|
2075
|
+
private focusableItems;
|
|
2076
|
+
/**
|
|
2077
|
+
* Nút mở panel, kể cả khi nơi dùng tự khai qua slot `[trigger]`.
|
|
2078
|
+
*
|
|
2079
|
+
* `triggerButtonRef` CHỈ có giá trị với nút mặc định của component — hai
|
|
2080
|
+
* nhánh `@if` trong template vẽ ra nó. Nơi dùng truyền nút riêng qua
|
|
2081
|
+
* `<ng-content select="[trigger]">` thì cả hai nhánh đều không chạy và ref
|
|
2082
|
+
* là `undefined`. Đo 2026-09-25: header onluyenv4 (streak, chuông) đều dùng
|
|
2083
|
+
* nút slot, nên mọi xử lý bám vào ref đó lặng lẽ không chạy — gồm cả việc
|
|
2084
|
+
* trả tiêu điểm về nút sau khi Escape, vốn có từ trước.
|
|
2085
|
+
*
|
|
2086
|
+
* Nên tìm nút thật trong cây DOM của host khi không có ref.
|
|
2087
|
+
*/
|
|
2088
|
+
private triggerElement;
|
|
2089
|
+
/**
|
|
2090
|
+
* Phần tử nhận tiêu điểm đứng ngay sau `element` trong thứ tự Tab của trang.
|
|
2091
|
+
*
|
|
2092
|
+
* Quét từ `<body>` và loại chính panel ra: panel treo cuối `<body>` nên nếu
|
|
2093
|
+
* tính cả nó thì "phần tử sau nút trigger" lại rơi vào panel vừa đóng.
|
|
2094
|
+
*/
|
|
2095
|
+
private nextFocusableAfter;
|
|
2096
|
+
/**
|
|
2097
|
+
* Tab từ nút trigger khi panel đang mở → nhảy VÀO mục đầu panel.
|
|
2098
|
+
*
|
|
2099
|
+
* Vì sao cần: `appendTo="body"` treo panel ra cuối `<body>`, nên trong thứ
|
|
2100
|
+
* tự DOM nó nằm SAU toàn bộ nội dung trang. Bàn phím đi theo thứ tự DOM chứ
|
|
2101
|
+
* không theo vị trí nhìn thấy, nên Tab từ nút trigger nhảy sang phần tử kế
|
|
2102
|
+
* tiếp trong header rồi xuống thân trang — panel mở ngay trước mắt mà không
|
|
2103
|
+
* bao giờ tới được. Đo 2026-09-25: 8 lượt Tab, không lượt nào vào panel.
|
|
2104
|
+
*
|
|
2105
|
+
* KHÔNG cuốn tiêu điểm lúc mở: người dùng chuột không cần, và nhảy tiêu điểm
|
|
2106
|
+
* khi họ chưa yêu cầu là cướp quyền điều khiển. Chỉ khi họ chủ động nhấn Tab
|
|
2107
|
+
* mới dẫn vào — đúng lúc họ đang tìm đường đi tiếp.
|
|
2108
|
+
*
|
|
2109
|
+
* Shift+Tab bỏ qua: người dùng đang muốn lùi RA, giữ họ lại là bẫy.
|
|
2110
|
+
*/
|
|
2111
|
+
onTriggerKeydown(event: KeyboardEvent): void;
|
|
2112
|
+
/**
|
|
2113
|
+
* Tab BÊN TRONG panel — giữ đường đi liền mạch với chỗ panel đang hiện.
|
|
2114
|
+
*
|
|
2115
|
+
* Panel nằm cuối `<body>` nên nếu để trình duyệt tự xử, Tab ở mục cuối sẽ
|
|
2116
|
+
* rơi xuống phần tử sau panel trong DOM (thường là hết trang), còn Shift+Tab
|
|
2117
|
+
* ở mục đầu nhảy ngược lên thân trang — cả hai đều bỏ qua nút trigger, tức
|
|
2118
|
+
* người dùng mất mốc quay về.
|
|
2119
|
+
*
|
|
2120
|
+
* KHÔNG bẫy vòng tròn như hộp thoại: chuẩn WAI-ARIA cho menu quy định Tab
|
|
2121
|
+
* phải THOÁT được ra trang. Nên:
|
|
2122
|
+
*
|
|
2123
|
+
* - Tab ở mục CUỐI → đóng panel, trả tiêu điểm về nút trigger rồi để trình
|
|
2124
|
+
* duyệt đi tiếp bình thường (phần tử sau nút trong header)
|
|
2125
|
+
* - Shift+Tab ở mục ĐẦU → về thẳng nút trigger, panel vẫn mở để người dùng
|
|
2126
|
+
* còn thấy mình vừa rời khỏi đâu
|
|
2127
|
+
*
|
|
2128
|
+
* Giữa các mục thì không can thiệp — panel là một khối liền trong DOM nên
|
|
2129
|
+
* trình duyệt tự đi đúng.
|
|
2130
|
+
*/
|
|
2131
|
+
onMenuKeydown(event: KeyboardEvent): void;
|
|
1682
2132
|
show(): void;
|
|
1683
2133
|
hide(): void;
|
|
1684
2134
|
toggle(): void;
|
|
@@ -1702,6 +2152,19 @@ declare class OlDropdownItem {
|
|
|
1702
2152
|
readonly itemClick: _angular_core.OutputEmitterRef<MouseEvent>;
|
|
1703
2153
|
private readonly parentDropdown;
|
|
1704
2154
|
readonly isItemActive: _angular_core.Signal<boolean>;
|
|
2155
|
+
/**
|
|
2156
|
+
* Hình học theo Figma `ol-dropdown-item` (node 1149:39652, đo 2026-09-28):
|
|
2157
|
+
* lề 8px bốn cạnh (`px-2 py-2`, cao 36px), icon 16px cách chữ 6px, bo 8px
|
|
2158
|
+
* (`rounded` = `--radius: 8px`), chữ 14px medium. Bản trước `px-3` (12px),
|
|
2159
|
+
* icon cách chữ 10px, bo 6px.
|
|
2160
|
+
*
|
|
2161
|
+
* Độ đậm nằm TRONG từng nhánh, không gắn vô điều kiện — hai class cùng thuộc
|
|
2162
|
+
* tính thì thắng thua theo thứ tự luật CSS, không theo thứ tự trong chuỗi.
|
|
2163
|
+
*
|
|
2164
|
+
* Trạng thái đang chọn: Figma KHÔNG vẽ (chỉ có Initial / Hover / Disabled).
|
|
2165
|
+
* Bản trước tự đặt `bg-brand-softer` (#F5F8FF trên nền trắng — gần như không
|
|
2166
|
+
* thấy, báo 2026-09-28). Nay `bg-brand-soft` (#E3EAFF) + chữ brand đậm.
|
|
2167
|
+
*/
|
|
1705
2168
|
readonly itemClasses: _angular_core.Signal<string>;
|
|
1706
2169
|
handleClick(event: MouseEvent): void;
|
|
1707
2170
|
static ɵfac: _angular_core.ɵɵFactoryDeclaration<OlDropdownItem, never>;
|
|
@@ -1722,122 +2185,129 @@ declare class OlDropdownHeader {
|
|
|
1722
2185
|
static ɵcmp: _angular_core.ɵɵComponentDeclaration<OlDropdownHeader, "ol-dropdown-header", never, { "heading": { "alias": "heading"; "required": false; "isSignal": true; }; "helperText": { "alias": "helperText"; "required": false; "isSignal": true; }; }, {}, never, ["*"], true, never>;
|
|
1723
2186
|
}
|
|
1724
2187
|
|
|
1725
|
-
|
|
2188
|
+
/**
|
|
2189
|
+
* Ô tìm ở đầu menu — Figma `ol-dropdown-header` Type=Form (1149:39893): một
|
|
2190
|
+
* `ol-input` cỡ sm có icon tìm, đặt trên danh sách (`ol-dropdown` Type=Users,
|
|
2191
|
+
* Type=With scroll).
|
|
2192
|
+
*
|
|
2193
|
+
* Component KHÔNG tự lọc: mục trong menu do nơi dùng chiếu vào, có thể lấy từ
|
|
2194
|
+
* máy chủ, nên nơi dùng lọc theo `query` rồi hiện `ol-dropdown-state` khi rỗng
|
|
2195
|
+
* hoặc đang tải.
|
|
2196
|
+
*
|
|
2197
|
+
* Bàn phím: ↓ xuống mục đầu, Enter chọn mục đầu còn bấm được. Esc do
|
|
2198
|
+
* `ol-dropdown` lo (đóng + trả tiêu điểm về nút mở).
|
|
2199
|
+
*
|
|
2200
|
+
* `sticky`: menu dài có `menuClass="max-h-… overflow-y-auto"` thì ô tìm đứng
|
|
2201
|
+
* yên trên đỉnh khi cuộn danh sách. `-top-2 -mt-2 pt-2` phủ luôn đệm 8px của
|
|
2202
|
+
* menu, để mục cuộn qua không lộ ra phía trên ô tìm.
|
|
2203
|
+
*/
|
|
2204
|
+
declare class OlDropdownSearch {
|
|
2205
|
+
readonly query: _angular_core.ModelSignal<string>;
|
|
2206
|
+
readonly placeholder: _angular_core.InputSignal<string>;
|
|
2207
|
+
readonly ariaLabel: _angular_core.InputSignal<string>;
|
|
2208
|
+
/** Mở menu thì đưa tiêu điểm vào ô tìm — người mở menu có ô tìm là để gõ. */
|
|
2209
|
+
readonly autofocus: _angular_core.InputSignal<boolean>;
|
|
2210
|
+
/** Đóng menu thì xoá từ khoá, lần mở sau thấy lại đủ danh sách. */
|
|
2211
|
+
readonly clearOnClose: _angular_core.InputSignal<boolean>;
|
|
2212
|
+
private readonly host;
|
|
2213
|
+
private readonly dropdown;
|
|
2214
|
+
constructor();
|
|
2215
|
+
protected onKeydown(event: KeyboardEvent): void;
|
|
2216
|
+
private field;
|
|
1726
2217
|
/**
|
|
1727
|
-
*
|
|
1728
|
-
*
|
|
2218
|
+
* Mục đầu còn bấm được trong CÙNG menu — bỏ qua mục khoá. Tính cả
|
|
2219
|
+
* `menuitemcheckbox`/`menuitemradio` (menu chọn nhiều, chọn một).
|
|
1729
2220
|
*/
|
|
1730
|
-
|
|
1731
|
-
|
|
1732
|
-
static
|
|
1733
|
-
static ɵcmp: _angular_core.ɵɵComponentDeclaration<OlFooter, "ol-footer", never, { "container": { "alias": "container"; "required": false; "isSignal": true; }; }, {}, never, ["*"], true, never>;
|
|
2221
|
+
private firstItem;
|
|
2222
|
+
static ɵfac: _angular_core.ɵɵFactoryDeclaration<OlDropdownSearch, never>;
|
|
2223
|
+
static ɵcmp: _angular_core.ɵɵComponentDeclaration<OlDropdownSearch, "ol-dropdown-search", never, { "query": { "alias": "query"; "required": false; "isSignal": true; }; "placeholder": { "alias": "placeholder"; "required": false; "isSignal": true; }; "ariaLabel": { "alias": "ariaLabel"; "required": false; "isSignal": true; }; "autofocus": { "alias": "autofocus"; "required": false; "isSignal": true; }; "clearOnClose": { "alias": "clearOnClose"; "required": false; "isSignal": true; }; }, { "query": "queryChange"; }, never, never, true, never>;
|
|
1734
2224
|
}
|
|
1735
2225
|
|
|
2226
|
+
type DropdownStateType = 'loading' | 'empty' | 'no-results';
|
|
1736
2227
|
/**
|
|
1737
|
-
*
|
|
2228
|
+
* Trạng thái của menu khi KHÔNG có mục nào để hiện — Figma `ol-dropdown`
|
|
2229
|
+
* Type=Đang tải (5266:29107) · Rỗng (5266:29111) · Không có kết quả (5266:29114).
|
|
1738
2230
|
*
|
|
1739
|
-
*
|
|
2231
|
+
* Figma ghi: "Menu lấy dữ liệu từ máy chủ phải có đủ bốn trạng thái. Thiếu
|
|
2232
|
+
* Đang tải / Rỗng / Không có kết quả là lỗi hay gặp nhất ở ô tìm kiếm gợi ý."
|
|
1740
2233
|
*
|
|
1741
|
-
*
|
|
1742
|
-
*
|
|
2234
|
+
* Đệm 24/16px, căn giữa. Đang tải: ba thanh xương cao 10px (thanh cuối ngắn
|
|
2235
|
+
* ~70%), cách 10px. Hai trạng thái chữ: tiêu đề 14px đậm vừa `text-heading`,
|
|
2236
|
+
* dòng phụ 12px `text-body-subtle`, cách 8px.
|
|
1743
2237
|
*
|
|
1744
|
-
*
|
|
1745
|
-
*
|
|
1746
|
-
* viền sai 5 component
|
|
1747
|
-
* đệm ngang lệch 2px ở cả ba cỡ đầu (datepicker so với input)
|
|
1748
|
-
* cỡ chữ `sm` lệch 2px (14px vs 12px)
|
|
1749
|
-
*
|
|
1750
|
-
* Nền và viền lệch **chỉ lộ ở chế độ tối**: sáng thì `--bg-secondary` và
|
|
1751
|
-
* `--bg-secondary-medium` cùng ra `#f9fafb`, tối thì `gray-950` vs `gray-800`.
|
|
1752
|
-
* Nên lỗi sống rất lâu — người dựng nhìn chế độ sáng, thấy giống hệt nhau.
|
|
1753
|
-
*
|
|
1754
|
-
* Đọc từ đây thì thêm ô nhập mới cũng tự khớp, và đổi thang chỉ sửa một chỗ.
|
|
1755
|
-
*
|
|
1756
|
-
* ## Không gộp chiều cao với đệm ngang
|
|
1757
|
-
*
|
|
1758
|
-
* Hai thứ tách riêng vì component có icon cần `ps-*` thay `px-*`. Gộp lại thì
|
|
1759
|
-
* mỗi component phải cắt chuỗi ra để bỏ phần đệm — dễ sai hơn là ghép vào.
|
|
2238
|
+
* `role="status"`: trình đọc màn hình báo khi danh sách vừa lọc ra rỗng —
|
|
2239
|
+
* người dùng gõ tìm không nhìn thấy menu thì vẫn biết không có kết quả.
|
|
1760
2240
|
*/
|
|
1761
|
-
|
|
1762
|
-
type
|
|
1763
|
-
/**
|
|
1764
|
-
|
|
1765
|
-
/**
|
|
1766
|
-
|
|
1767
|
-
|
|
1768
|
-
|
|
1769
|
-
|
|
1770
|
-
|
|
1771
|
-
|
|
1772
|
-
|
|
1773
|
-
|
|
1774
|
-
|
|
1775
|
-
|
|
2241
|
+
declare class OlDropdownState {
|
|
2242
|
+
readonly type: _angular_core.InputSignal<DropdownStateType>;
|
|
2243
|
+
/** Tiêu đề — bỏ trống thì dùng câu mặc định theo `type`. */
|
|
2244
|
+
readonly heading: _angular_core.InputSignal<string>;
|
|
2245
|
+
/** Dòng phụ — bỏ trống thì dùng câu mặc định theo `type`. */
|
|
2246
|
+
readonly description: _angular_core.InputSignal<string>;
|
|
2247
|
+
/** Từ khoá vừa tìm — chèn vào câu mặc định của `no-results`. */
|
|
2248
|
+
readonly query: _angular_core.InputSignal<string>;
|
|
2249
|
+
protected readonly boxClasses: _angular_core.Signal<"flex flex-col items-center gap-2.5 px-4 py-6" | "flex flex-col items-center gap-2 px-4 py-6 text-center">;
|
|
2250
|
+
protected readonly resolvedHeading: _angular_core.Signal<string>;
|
|
2251
|
+
protected readonly resolvedDescription: _angular_core.Signal<string>;
|
|
2252
|
+
static ɵfac: _angular_core.ɵɵFactoryDeclaration<OlDropdownState, never>;
|
|
2253
|
+
static ɵcmp: _angular_core.ɵɵComponentDeclaration<OlDropdownState, "ol-dropdown-state", never, { "type": { "alias": "type"; "required": false; "isSignal": true; }; "heading": { "alias": "heading"; "required": false; "isSignal": true; }; "description": { "alias": "description"; "required": false; "isSignal": true; }; "query": { "alias": "query"; "required": false; "isSignal": true; }; }, {}, never, never, true, never>;
|
|
2254
|
+
}
|
|
2255
|
+
|
|
2256
|
+
declare class OlFooter {
|
|
2257
|
+
/**
|
|
2258
|
+
* Giới hạn nội dung trong khung rộng tối đa và căn giữa. Tắt đi thì chân
|
|
2259
|
+
* trang trải hết bề ngang — dùng khi trang đã có khung bao ngoài.
|
|
2260
|
+
*/
|
|
2261
|
+
readonly container: _angular_core.InputSignal<boolean>;
|
|
2262
|
+
readonly innerClasses: _angular_core.Signal<string>;
|
|
2263
|
+
static ɵfac: _angular_core.ɵɵFactoryDeclaration<OlFooter, never>;
|
|
2264
|
+
static ɵcmp: _angular_core.ɵɵComponentDeclaration<OlFooter, "ol-footer", never, { "container": { "alias": "container"; "required": false; "isSignal": true; }; }, {}, never, ["*"], true, never>;
|
|
2265
|
+
}
|
|
2266
|
+
|
|
2267
|
+
type OlFrameSpacing = 'xs' | 'sm' | 'base' | 'lg';
|
|
2268
|
+
type OlFrameRounded = 'sm' | 'md' | 'lg' | 'xl';
|
|
2269
|
+
type OlFrameVariant = 'default' | 'ghost';
|
|
1776
2270
|
/**
|
|
1777
|
-
*
|
|
2271
|
+
* Khung bọc nhiều mảng nội dung, khoảng cách đều nhau.
|
|
1778
2272
|
*
|
|
1779
|
-
*
|
|
1780
|
-
* nội dung xuống dòng, nên `h-*` cố định sẽ cắt mất. Giá trị bằng đúng
|
|
1781
|
-
* `FIELD_HEIGHT` để một dòng vẫn cao bằng các ô khác.
|
|
1782
|
-
*/
|
|
1783
|
-
declare const FIELD_MIN_HEIGHT: Record<FieldSize, string>;
|
|
1784
|
-
/**
|
|
1785
|
-
* Đệm ngang theo Figma `ol-input`: sm 10px · base 12px · lg 14px · xl 16px.
|
|
2273
|
+
* Chưa có node Figma — dựng theo design system.
|
|
1786
2274
|
*
|
|
1787
|
-
* KHÔNG dùng `
|
|
1788
|
-
* nên nó render ra `px-2`, lệch 2px so với thiết kế. Phải gom vào một chuỗi.
|
|
1789
|
-
*/
|
|
1790
|
-
declare const FIELD_PADDING_X: Record<FieldSize, string>;
|
|
1791
|
-
/**
|
|
1792
|
-
* Cỡ chữ theo cỡ ô.
|
|
2275
|
+
* ## Vì sao KHÔNG dùng `ol-card` cho việc này
|
|
1793
2276
|
*
|
|
1794
|
-
* `
|
|
1795
|
-
*
|
|
1796
|
-
|
|
1797
|
-
|
|
1798
|
-
|
|
1799
|
-
* Nền · viền · vòng focus theo trạng thái.
|
|
2277
|
+
* `ol-card` là MỘT thẻ nội dung: có ảnh bìa, có `href`, có trạng thái chọn.
|
|
2278
|
+
* Còn đây là cái khung xếp NHIỀU mảng cạnh nhau với khoảng cách đều — như cột
|
|
2279
|
+
* thiết lập, bảng điều khiển, hay danh sách nhóm. Lồng nhiều `ol-card` vào một
|
|
2280
|
+
* `div` rồi tự đặt `space-y-*` cũng ra kết quả, nhưng mỗi nơi dùng lại chọn
|
|
2281
|
+
* một khoảng cách khác và trang trông lộn xộn.
|
|
1800
2282
|
*
|
|
1801
|
-
*
|
|
1802
|
-
* nhau (`bg-neutral-secondary` vs `bg-neutral-secondary-medium`) nhưng **khác
|
|
1803
|
-
* hẳn ở chế độ tối**, nên nhầm một chữ là ô đó lệch màu mà chế độ sáng không
|
|
1804
|
-
* lộ ra.
|
|
2283
|
+
* ## `stacked` bỏ viền giữa, không phải bỏ viền hết
|
|
1805
2284
|
*
|
|
1806
|
-
*
|
|
1807
|
-
*
|
|
1808
|
-
|
|
1809
|
-
declare const FIELD_STATE: Record<FieldState, string>;
|
|
1810
|
-
/** Nền và con trỏ khi ô bị khoá. Áp đè lên `FIELD_STATE`. */
|
|
1811
|
-
declare const FIELD_DISABLED = "bg-disabled opacity-60 cursor-not-allowed";
|
|
1812
|
-
/** Bo góc — 12px cho mọi cỡ, theo Figma `bieu-mau.md`. */
|
|
1813
|
-
declare const FIELD_RADIUS = "rounded-md";
|
|
1814
|
-
/**
|
|
1815
|
-
* Lớp của nhãn phía trên ô.
|
|
2285
|
+
* Xếp chồng thì các mảng dính thành một khối liền, chỉ còn một viền ngoài và
|
|
2286
|
+
* kẻ ngăn mảnh ở giữa — giống `ol-list-group`. Tách rời thì mỗi mảng là một
|
|
2287
|
+
* thẻ riêng có viền đủ bốn cạnh.
|
|
1816
2288
|
*
|
|
1817
|
-
* `
|
|
1818
|
-
*
|
|
1819
|
-
|
|
1820
|
-
|
|
1821
|
-
/** Khoảng cách nhãn → ô. */
|
|
1822
|
-
declare const FIELD_LABEL_GAP = "mb-1.5";
|
|
1823
|
-
/** Dấu sao bắt buộc. */
|
|
1824
|
-
declare const FIELD_ASTERISK = "text-fg-danger font-bold";
|
|
1825
|
-
/**
|
|
1826
|
-
* Chữ trợ giúp dưới ô, đổi màu theo trạng thái.
|
|
2289
|
+
* Làm bằng `divide-y` cộng `overflow-hidden` trên khung, KHÔNG bằng
|
|
2290
|
+
* `[&>*:not(:last-child)]:border-b`: biến thể `:last-child` trong chuỗi class
|
|
2291
|
+
* của component con sẽ khớp MỌI thể hiện của con đó, kể cả khi nó là con duy
|
|
2292
|
+
* nhất ở nơi khác — lỗi đã gặp trong repo này.
|
|
1827
2293
|
*
|
|
1828
|
-
*
|
|
1829
|
-
* giải thích lỗi hay chú thích thường.
|
|
1830
|
-
*/
|
|
1831
|
-
declare const FIELD_HELPER: Record<FieldState, string>;
|
|
1832
|
-
/** Khoảng cách ô → chữ trợ giúp. */
|
|
1833
|
-
declare const FIELD_HELPER_GAP = "mt-1.5";
|
|
1834
|
-
/**
|
|
1835
|
-
* Gộp chiều cao · đệm ngang · cỡ chữ · bo góc cho một cỡ.
|
|
2294
|
+
* ## `ghost` bỏ nền và viền, giữ khoảng cách
|
|
1836
2295
|
*
|
|
1837
|
-
*
|
|
1838
|
-
*
|
|
2296
|
+
* Dùng khi khung nằm trong một thẻ đã có viền rồi — hai lớp viền lồng nhau
|
|
2297
|
+
* trông như lỗi hiển thị.
|
|
1839
2298
|
*/
|
|
1840
|
-
declare
|
|
2299
|
+
declare class OlFrame {
|
|
2300
|
+
readonly spacing: _angular_core.InputSignal<OlFrameSpacing>;
|
|
2301
|
+
readonly rounded: _angular_core.InputSignal<OlFrameRounded>;
|
|
2302
|
+
readonly variant: _angular_core.InputSignal<OlFrameVariant>;
|
|
2303
|
+
/** Dính các mảng thành một khối liền, chỉ còn kẻ ngăn ở giữa. */
|
|
2304
|
+
readonly stacked: _angular_core.InputSignal<boolean>;
|
|
2305
|
+
/** Xếp ngang thay vì dọc. Khoảng cách và kẻ ngăn đổi trục theo. */
|
|
2306
|
+
readonly horizontal: _angular_core.InputSignal<boolean>;
|
|
2307
|
+
protected readonly frameClasses: _angular_core.Signal<string>;
|
|
2308
|
+
static ɵfac: _angular_core.ɵɵFactoryDeclaration<OlFrame, never>;
|
|
2309
|
+
static ɵcmp: _angular_core.ɵɵComponentDeclaration<OlFrame, "ol-frame", never, { "spacing": { "alias": "spacing"; "required": false; "isSignal": true; }; "rounded": { "alias": "rounded"; "required": false; "isSignal": true; }; "variant": { "alias": "variant"; "required": false; "isSignal": true; }; "stacked": { "alias": "stacked"; "required": false; "isSignal": true; }; "horizontal": { "alias": "horizontal"; "required": false; "isSignal": true; }; }, {}, never, ["*"], true, never>;
|
|
2310
|
+
}
|
|
1841
2311
|
|
|
1842
2312
|
/**
|
|
1843
2313
|
* Nhãn cho ô nhập — khớp Figma `ol-label` (#1149:94727), trục
|
|
@@ -2211,6 +2681,28 @@ declare class OlInput implements ControlValueAccessor {
|
|
|
2211
2681
|
readonly cleared: _angular_core.OutputEmitterRef<void>;
|
|
2212
2682
|
readonly rightHelperText: _angular_core.InputSignal<string>;
|
|
2213
2683
|
readonly id: _angular_core.InputSignal<string>;
|
|
2684
|
+
/**
|
|
2685
|
+
* Nhãn nổi: `label` nằm TRONG khung, nổi lên khi focus hoặc có chữ — thay
|
|
2686
|
+
* cho nhãn phía trên ô. Xem `OlFieldFrame`.
|
|
2687
|
+
*/
|
|
2688
|
+
readonly floatingLabel: _angular_core.InputSignal<boolean>;
|
|
2689
|
+
/**
|
|
2690
|
+
* Nhãn `top` (trên ô, mặc định) hay `left` (cùng hàng, bên trái). Nhãn nổi
|
|
2691
|
+
* (`floatingLabel`) thắng — bật nó thì bỏ qua input này.
|
|
2692
|
+
*/
|
|
2693
|
+
readonly labelPosition: _angular_core.InputSignal<LabelPosition>;
|
|
2694
|
+
/**
|
|
2695
|
+
* Độ rộng cột nhãn khi `labelPosition="left"` — độ dài CSS bất kỳ: `140px`,
|
|
2696
|
+
* `10rem`, `30%`. Bỏ trống = 8rem. Các ô trong cùng form đặt cùng một số thì
|
|
2697
|
+
* mép ô thẳng hàng.
|
|
2698
|
+
*/
|
|
2699
|
+
readonly labelWidth: _angular_core.InputSignal<string>;
|
|
2700
|
+
protected readonly labelLayout: _angular_core.Signal<string>;
|
|
2701
|
+
protected readonly labelBeside: _angular_core.Signal<boolean>;
|
|
2702
|
+
/** Kiểu nhãn nổi — Figma Bordered / With background / Default. */
|
|
2703
|
+
readonly floatingVariant: _angular_core.InputSignal<FloatingVariant>;
|
|
2704
|
+
/** Có chữ → nhãn nổi. `0` (input number) là CÓ giá trị. */
|
|
2705
|
+
readonly hasValue: _angular_core.Signal<boolean>;
|
|
2214
2706
|
/** Id thực dùng: ưu tiên id do nơi gọi truyền, không thì dùng id tự sinh. */
|
|
2215
2707
|
readonly inputId: _angular_core.Signal<string>;
|
|
2216
2708
|
readonly helperId: _angular_core.Signal<string>;
|
|
@@ -2227,6 +2719,18 @@ declare class OlInput implements ControlValueAccessor {
|
|
|
2227
2719
|
* lệch 2px so với thiết kế.
|
|
2228
2720
|
*/
|
|
2229
2721
|
readonly paddingClasses: _angular_core.Signal<string>;
|
|
2722
|
+
/**
|
|
2723
|
+
* Khoảng icon ↔ chữ đúng 8px (`FIELD_ICON_GAP`): icon mang lề đầu/cuối của
|
|
2724
|
+
* khung, ô gõ bỏ lề phía có icon. Khung KHÔNG có `gap` — add-on chữ/icon
|
|
2725
|
+
* phải sát ô gõ (Figma Type=Add-on: gap 0).
|
|
2726
|
+
*/
|
|
2727
|
+
protected readonly hasLeadingIcon: _angular_core.Signal<boolean>;
|
|
2728
|
+
protected readonly hasTrailingIcon: _angular_core.Signal<boolean>;
|
|
2729
|
+
protected readonly showClear: _angular_core.Signal<boolean>;
|
|
2730
|
+
protected readonly leadIconClasses: _angular_core.Signal<string>;
|
|
2731
|
+
/** Nút xoá đứng trước icon trạng thái thì để `ps-2` của icon tạo khoảng. */
|
|
2732
|
+
protected readonly clearClasses: _angular_core.Signal<string>;
|
|
2733
|
+
protected readonly trailIconClasses: _angular_core.Signal<string>;
|
|
2230
2734
|
/**
|
|
2231
2735
|
* Bốn phương thức này là thứ Angular Forms gọi tới. Thiếu chúng thì
|
|
2232
2736
|
* `formControlName` / `[formControl]` KHÔNG gắn được — dùng component trong
|
|
@@ -2251,7 +2755,7 @@ declare class OlInput implements ControlValueAccessor {
|
|
|
2251
2755
|
/** Gọi khi rời ô nhập — form dùng để đánh dấu `touched`. */
|
|
2252
2756
|
protected markTouched(): void;
|
|
2253
2757
|
static ɵfac: _angular_core.ɵɵFactoryDeclaration<OlInput, never>;
|
|
2254
|
-
static ɵcmp: _angular_core.ɵɵComponentDeclaration<OlInput, "ol-input", never, { "value": { "alias": "value"; "required": false; "isSignal": true; }; "type": { "alias": "type"; "required": false; "isSignal": true; }; "label": { "alias": "label"; "required": false; "isSignal": true; }; "placeholder": { "alias": "placeholder"; "required": false; "isSignal": true; }; "helperText": { "alias": "helperText"; "required": false; "isSignal": true; }; "disabled": { "alias": "disabled"; "required": false; "isSignal": true; }; "readonly": { "alias": "readonly"; "required": false; "isSignal": true; }; "size": { "alias": "size"; "required": false; "isSignal": true; }; "state": { "alias": "state"; "required": false; "isSignal": true; }; "required": { "alias": "required"; "required": false; "isSignal": true; }; "showAsterisk": { "alias": "showAsterisk"; "required": false; "isSignal": true; }; "labelIcon": { "alias": "labelIcon"; "required": false; "isSignal": true; }; "labelTooltip": { "alias": "labelTooltip"; "required": false; "isSignal": true; }; "ariaLabel": { "alias": "ariaLabel"; "required": false; "isSignal": true; }; "prefixText": { "alias": "prefixText"; "required": false; "isSignal": true; }; "suffixText": { "alias": "suffixText"; "required": false; "isSignal": true; }; "addOnIcon": { "alias": "addOnIcon"; "required": false; "isSignal": true; }; "leftIcon": { "alias": "leftIcon"; "required": false; "isSignal": true; }; "rightIcon": { "alias": "rightIcon"; "required": false; "isSignal": true; }; "clearable": { "alias": "clearable"; "required": false; "isSignal": true; }; "clearAriaLabel": { "alias": "clearAriaLabel"; "required": false; "isSignal": true; }; "rightHelperText": { "alias": "rightHelperText"; "required": false; "isSignal": true; }; "id": { "alias": "id"; "required": false; "isSignal": true; }; }, { "value": "valueChange"; "disabled": "disabledChange"; "cleared": "cleared"; }, never, ["[addOnIcon], [leftIcon]", "[
|
|
2758
|
+
static ɵcmp: _angular_core.ɵɵComponentDeclaration<OlInput, "ol-input", never, { "value": { "alias": "value"; "required": false; "isSignal": true; }; "type": { "alias": "type"; "required": false; "isSignal": true; }; "label": { "alias": "label"; "required": false; "isSignal": true; }; "placeholder": { "alias": "placeholder"; "required": false; "isSignal": true; }; "helperText": { "alias": "helperText"; "required": false; "isSignal": true; }; "disabled": { "alias": "disabled"; "required": false; "isSignal": true; }; "readonly": { "alias": "readonly"; "required": false; "isSignal": true; }; "size": { "alias": "size"; "required": false; "isSignal": true; }; "state": { "alias": "state"; "required": false; "isSignal": true; }; "required": { "alias": "required"; "required": false; "isSignal": true; }; "showAsterisk": { "alias": "showAsterisk"; "required": false; "isSignal": true; }; "labelIcon": { "alias": "labelIcon"; "required": false; "isSignal": true; }; "labelTooltip": { "alias": "labelTooltip"; "required": false; "isSignal": true; }; "ariaLabel": { "alias": "ariaLabel"; "required": false; "isSignal": true; }; "prefixText": { "alias": "prefixText"; "required": false; "isSignal": true; }; "suffixText": { "alias": "suffixText"; "required": false; "isSignal": true; }; "addOnIcon": { "alias": "addOnIcon"; "required": false; "isSignal": true; }; "leftIcon": { "alias": "leftIcon"; "required": false; "isSignal": true; }; "rightIcon": { "alias": "rightIcon"; "required": false; "isSignal": true; }; "clearable": { "alias": "clearable"; "required": false; "isSignal": true; }; "clearAriaLabel": { "alias": "clearAriaLabel"; "required": false; "isSignal": true; }; "rightHelperText": { "alias": "rightHelperText"; "required": false; "isSignal": true; }; "id": { "alias": "id"; "required": false; "isSignal": true; }; "floatingLabel": { "alias": "floatingLabel"; "required": false; "isSignal": true; }; "labelPosition": { "alias": "labelPosition"; "required": false; "isSignal": true; }; "labelWidth": { "alias": "labelWidth"; "required": false; "isSignal": true; }; "floatingVariant": { "alias": "floatingVariant"; "required": false; "isSignal": true; }; }, { "value": "valueChange"; "disabled": "disabledChange"; "cleared": "cleared"; }, never, ["[addOnIcon], [leftIcon]", "[rightIcon]", "[rightHelperAction]"], true, never>;
|
|
2255
2759
|
}
|
|
2256
2760
|
|
|
2257
2761
|
type TextareaState = 'default' | 'error' | 'success';
|
|
@@ -2287,6 +2791,26 @@ declare class OlTextarea implements ControlValueAccessor {
|
|
|
2287
2791
|
readonly showAsterisk: _angular_core.InputSignal<boolean>;
|
|
2288
2792
|
readonly commentBox: _angular_core.InputSignal<boolean>;
|
|
2289
2793
|
readonly id: _angular_core.InputSignal<string>;
|
|
2794
|
+
/**
|
|
2795
|
+
* Nhãn nổi: `label` nằm TRONG khung ở dòng đầu, nổi lên khi focus hoặc có
|
|
2796
|
+
* chữ. Không áp cho `commentBox` (thẻ bình luận có bố cục riêng).
|
|
2797
|
+
*/
|
|
2798
|
+
readonly floatingLabel: _angular_core.InputSignal<boolean>;
|
|
2799
|
+
/**
|
|
2800
|
+
* Nhãn `top` (trên ô, mặc định) hay `left` (cùng hàng, bên trái). Nhãn nổi
|
|
2801
|
+
* (`floatingLabel`) thắng — bật nó thì bỏ qua input này.
|
|
2802
|
+
*/
|
|
2803
|
+
readonly labelPosition: _angular_core.InputSignal<LabelPosition>;
|
|
2804
|
+
/**
|
|
2805
|
+
* Độ rộng cột nhãn khi `labelPosition="left"` — độ dài CSS bất kỳ: `140px`,
|
|
2806
|
+
* `10rem`, `30%`. Bỏ trống = 8rem. Các ô trong cùng form đặt cùng một số thì
|
|
2807
|
+
* mép ô thẳng hàng.
|
|
2808
|
+
*/
|
|
2809
|
+
readonly labelWidth: _angular_core.InputSignal<string>;
|
|
2810
|
+
protected readonly labelLayout: _angular_core.Signal<string>;
|
|
2811
|
+
protected readonly labelBeside: _angular_core.Signal<boolean>;
|
|
2812
|
+
/** Kiểu nhãn nổi — Figma Bordered / With background / Default. */
|
|
2813
|
+
readonly floatingVariant: _angular_core.InputSignal<FloatingVariant>;
|
|
2290
2814
|
readonly submitComment: _angular_core.OutputEmitterRef<string>;
|
|
2291
2815
|
onSubmit(): void;
|
|
2292
2816
|
/**
|
|
@@ -2305,7 +2829,7 @@ declare class OlTextarea implements ControlValueAccessor {
|
|
|
2305
2829
|
/** Gọi khi rời ô nhập — form dùng để đánh dấu `touched`. */
|
|
2306
2830
|
protected markTouched(): void;
|
|
2307
2831
|
static ɵfac: _angular_core.ɵɵFactoryDeclaration<OlTextarea, never>;
|
|
2308
|
-
static ɵcmp: _angular_core.ɵɵComponentDeclaration<OlTextarea, "ol-textarea", never, { "value": { "alias": "value"; "required": false; "isSignal": true; }; "label": { "alias": "label"; "required": false; "isSignal": true; }; "ariaLabel": { "alias": "ariaLabel"; "required": false; "isSignal": true; }; "placeholder": { "alias": "placeholder"; "required": false; "isSignal": true; }; "rows": { "alias": "rows"; "required": false; "isSignal": true; }; "disabled": { "alias": "disabled"; "required": false; "isSignal": true; }; "helperText": { "alias": "helperText"; "required": false; "isSignal": true; }; "maxLength": { "alias": "maxLength"; "required": false; "isSignal": true; }; "showCharCount": { "alias": "showCharCount"; "required": false; "isSignal": true; }; "state": { "alias": "state"; "required": false; "isSignal": true; }; "required": { "alias": "required"; "required": false; "isSignal": true; }; "showAsterisk": { "alias": "showAsterisk"; "required": false; "isSignal": true; }; "commentBox": { "alias": "commentBox"; "required": false; "isSignal": true; }; "id": { "alias": "id"; "required": false; "isSignal": true; }; }, { "value": "valueChange"; "disabled": "disabledChange"; "submitComment": "submitComment"; }, never, never, true, never>;
|
|
2832
|
+
static ɵcmp: _angular_core.ɵɵComponentDeclaration<OlTextarea, "ol-textarea", never, { "value": { "alias": "value"; "required": false; "isSignal": true; }; "label": { "alias": "label"; "required": false; "isSignal": true; }; "ariaLabel": { "alias": "ariaLabel"; "required": false; "isSignal": true; }; "placeholder": { "alias": "placeholder"; "required": false; "isSignal": true; }; "rows": { "alias": "rows"; "required": false; "isSignal": true; }; "disabled": { "alias": "disabled"; "required": false; "isSignal": true; }; "helperText": { "alias": "helperText"; "required": false; "isSignal": true; }; "maxLength": { "alias": "maxLength"; "required": false; "isSignal": true; }; "showCharCount": { "alias": "showCharCount"; "required": false; "isSignal": true; }; "state": { "alias": "state"; "required": false; "isSignal": true; }; "required": { "alias": "required"; "required": false; "isSignal": true; }; "showAsterisk": { "alias": "showAsterisk"; "required": false; "isSignal": true; }; "commentBox": { "alias": "commentBox"; "required": false; "isSignal": true; }; "id": { "alias": "id"; "required": false; "isSignal": true; }; "floatingLabel": { "alias": "floatingLabel"; "required": false; "isSignal": true; }; "labelPosition": { "alias": "labelPosition"; "required": false; "isSignal": true; }; "labelWidth": { "alias": "labelWidth"; "required": false; "isSignal": true; }; "floatingVariant": { "alias": "floatingVariant"; "required": false; "isSignal": true; }; }, { "value": "valueChange"; "disabled": "disabledChange"; "submitComment": "submitComment"; }, never, never, true, never>;
|
|
2309
2833
|
}
|
|
2310
2834
|
|
|
2311
2835
|
/**
|
|
@@ -2417,6 +2941,26 @@ declare class OlSelect implements ControlValueAccessor {
|
|
|
2417
2941
|
* cần `set()` được. Cách dùng từ ngoài không đổi.
|
|
2418
2942
|
*/
|
|
2419
2943
|
readonly disabled: _angular_core.ModelSignal<boolean>;
|
|
2944
|
+
/**
|
|
2945
|
+
* Nhãn nổi: `label` nằm TRONG khung, nổi lên khi focus, mở danh sách hoặc có
|
|
2946
|
+
* lựa chọn. Đa chọn: nhãn nằm yên ở dòng đầu, nổi lên không đẩy thẻ.
|
|
2947
|
+
*/
|
|
2948
|
+
readonly floatingLabel: _angular_core.InputSignal<boolean>;
|
|
2949
|
+
/**
|
|
2950
|
+
* Nhãn `top` (trên ô, mặc định) hay `left` (cùng hàng, bên trái). Nhãn nổi
|
|
2951
|
+
* (`floatingLabel`) thắng — bật nó thì bỏ qua input này.
|
|
2952
|
+
*/
|
|
2953
|
+
readonly labelPosition: _angular_core.InputSignal<LabelPosition>;
|
|
2954
|
+
/**
|
|
2955
|
+
* Độ rộng cột nhãn khi `labelPosition="left"` — độ dài CSS bất kỳ: `140px`,
|
|
2956
|
+
* `10rem`, `30%`. Bỏ trống = 8rem. Các ô trong cùng form đặt cùng một số thì
|
|
2957
|
+
* mép ô thẳng hàng.
|
|
2958
|
+
*/
|
|
2959
|
+
readonly labelWidth: _angular_core.InputSignal<string>;
|
|
2960
|
+
protected readonly labelLayout: _angular_core.Signal<string>;
|
|
2961
|
+
protected readonly labelBeside: _angular_core.Signal<boolean>;
|
|
2962
|
+
/** Kiểu nhãn nổi — Figma Bordered / With background / Default. */
|
|
2963
|
+
readonly floatingVariant: _angular_core.InputSignal<FloatingVariant>;
|
|
2420
2964
|
readonly placeholder: _angular_core.InputSignal<string>;
|
|
2421
2965
|
readonly multiple: _angular_core.InputSignal<boolean>;
|
|
2422
2966
|
readonly searchable: _angular_core.InputSignal<boolean>;
|
|
@@ -2426,6 +2970,10 @@ declare class OlSelect implements ControlValueAccessor {
|
|
|
2426
2970
|
readonly labelKey: _angular_core.InputSignal<string>;
|
|
2427
2971
|
readonly valueKey: _angular_core.InputSignal<string>;
|
|
2428
2972
|
readonly groupBy: _angular_core.InputSignal<string>;
|
|
2973
|
+
/**
|
|
2974
|
+
* Tiêu đề khi danh sách rỗng. Bỏ trống thì theo Figma: có từ khoá →
|
|
2975
|
+
* "Không tìm thấy “…”", chưa có mục nào → "Chưa có mục nào".
|
|
2976
|
+
*/
|
|
2429
2977
|
readonly emptyText: _angular_core.InputSignal<string>;
|
|
2430
2978
|
readonly searchPlaceholder: _angular_core.InputSignal<string>;
|
|
2431
2979
|
/**
|
|
@@ -2567,6 +3115,7 @@ declare class OlSelect implements ControlValueAccessor {
|
|
|
2567
3115
|
private readonly listboxRef;
|
|
2568
3116
|
/** Ô tìm ở đầu panel, để chuyển focus vào khi mở. */
|
|
2569
3117
|
private readonly oTimPanel;
|
|
3118
|
+
private readonly inlineSearch;
|
|
2570
3119
|
readonly isOpen: _angular_core.WritableSignal<boolean>;
|
|
2571
3120
|
readonly searchQuery: _angular_core.WritableSignal<string>;
|
|
2572
3121
|
readonly activeIndex: _angular_core.WritableSignal<number>;
|
|
@@ -2616,9 +3165,15 @@ declare class OlSelect implements ControlValueAccessor {
|
|
|
2616
3165
|
* 10/12/14/16px. Đặt `ol-select size="sm"` cạnh `ol-input size="sm"` là
|
|
2617
3166
|
* lệch 4px, và ở `xl` lệch 2px theo chiều ngược lại.
|
|
2618
3167
|
*
|
|
2619
|
-
*
|
|
3168
|
+
* Icon trái và cụm nút phải đều `absolute`, nên khung tự chừa chỗ cho
|
|
3169
|
+
* chúng bằng `FIELD_ICON_RESERVE_*`: icon ↔ chữ đúng 8px. Bản cũ `ps-10` /
|
|
3170
|
+
* `pe-10` cố định cho mọi cỡ ra 10px ở cỡ base, 14px ở sm (đo 2026-09-29).
|
|
2620
3171
|
*/
|
|
2621
3172
|
readonly paddingStartClass: _angular_core.Signal<string>;
|
|
3173
|
+
private readonly floatingOutlined;
|
|
3174
|
+
/** Icon trái và cụm nút phải nằm ở lề theo cỡ, như `ol-input`. */
|
|
3175
|
+
protected readonly leftIconPadClass: _angular_core.Signal<string>;
|
|
3176
|
+
protected readonly controlPadClass: _angular_core.Signal<string>;
|
|
2622
3177
|
private onChange;
|
|
2623
3178
|
private onTouched;
|
|
2624
3179
|
private readonly destroyRef;
|
|
@@ -2813,7 +3368,7 @@ declare class OlSelect implements ControlValueAccessor {
|
|
|
2813
3368
|
registerOnTouched(fn: () => void): void;
|
|
2814
3369
|
setDisabledState(isDisabled: boolean): void;
|
|
2815
3370
|
static ɵfac: _angular_core.ɵɵFactoryDeclaration<OlSelect, never>;
|
|
2816
|
-
static ɵcmp: _angular_core.ɵɵComponentDeclaration<OlSelect, "ol-select", never, { "value": { "alias": "value"; "required": false; "isSignal": true; }; "options": { "alias": "options"; "required": false; "isSignal": true; }; "label": { "alias": "label"; "required": false; "isSignal": true; }; "ariaLabel": { "alias": "ariaLabel"; "required": false; "isSignal": true; }; "size": { "alias": "size"; "required": false; "isSignal": true; }; "helperText": { "alias": "helperText"; "required": false; "isSignal": true; }; "state": { "alias": "state"; "required": false; "isSignal": true; }; "required": { "alias": "required"; "required": false; "isSignal": true; }; "showAsterisk": { "alias": "showAsterisk"; "required": false; "isSignal": true; }; "leftIcon": { "alias": "leftIcon"; "required": false; "isSignal": true; }; "id": { "alias": "id"; "required": false; "isSignal": true; }; "disabled": { "alias": "disabled"; "required": false; "isSignal": true; }; "placeholder": { "alias": "placeholder"; "required": false; "isSignal": true; }; "multiple": { "alias": "multiple"; "required": false; "isSignal": true; }; "searchable": { "alias": "searchable"; "required": false; "isSignal": true; }; "clearable": { "alias": "clearable"; "required": false; "isSignal": true; }; "loading": { "alias": "loading"; "required": false; "isSignal": true; }; "readonly": { "alias": "readonly"; "required": false; "isSignal": true; }; "labelKey": { "alias": "labelKey"; "required": false; "isSignal": true; }; "valueKey": { "alias": "valueKey"; "required": false; "isSignal": true; }; "groupBy": { "alias": "groupBy"; "required": false; "isSignal": true; }; "emptyText": { "alias": "emptyText"; "required": false; "isSignal": true; }; "searchPlaceholder": { "alias": "searchPlaceholder"; "required": false; "isSignal": true; }; "appendTo": { "alias": "appendTo"; "required": false; "isSignal": true; }; "menuClass": { "alias": "menuClass"; "required": false; "isSignal": true; }; "matchTriggerWidth": { "alias": "matchTriggerWidth"; "required": false; "isSignal": true; }; "maxSelectedItems": { "alias": "maxSelectedItems"; "required": false; "isSignal": true; }; "closeOnSelect": { "alias": "closeOnSelect"; "required": false; "isSignal": true; }; "hideSelected": { "alias": "hideSelected"; "required": false; "isSignal": true; }; "allowCreate": { "alias": "allowCreate"; "required": false; "isSignal": true; }; "createText": { "alias": "createText"; "required": false; "isSignal": true; }; "groupSeparator": { "alias": "groupSeparator"; "required": false; "isSignal": true; }; "searchPosition": { "alias": "searchPosition"; "required": false; "isSignal": true; }; "searchIcon": { "alias": "searchIcon"; "required": false; "isSignal": true; }; "searchPrefix": { "alias": "searchPrefix"; "required": false; "isSignal": true; }; "triggerIcon": { "alias": "triggerIcon"; "required": false; "isSignal": true; }; "triggerLabel": { "alias": "triggerLabel"; "required": false; "isSignal": true; }; "remoteSearch": { "alias": "remoteSearch"; "required": false; "isSignal": true; }; "minTermLength": { "alias": "minTermLength"; "required": false; "isSignal": true; }; "debounceMs": { "alias": "debounceMs"; "required": false; "isSignal": true; }; "typeToSearchText": { "alias": "typeToSearchText"; "required": false; "isSignal": true; }; "virtualScroll": { "alias": "virtualScroll"; "required": false; "isSignal": true; }; "itemHeight": { "alias": "itemHeight"; "required": false; "isSignal": true; }; "bufferAmount": { "alias": "bufferAmount"; "required": false; "isSignal": true; }; }, { "value": "valueChange"; "disabled": "disabledChange"; "search": "search"; "opened": "opened"; "closed": "closed"; "cleared": "cleared"; "added": "added"; "removed": "removed"; "selectionChange": "selectionChange"; }, ["optionTemplate", "labelTemplate"], ["[leftIcon]"], true, never>;
|
|
3371
|
+
static ɵcmp: _angular_core.ɵɵComponentDeclaration<OlSelect, "ol-select", never, { "value": { "alias": "value"; "required": false; "isSignal": true; }; "options": { "alias": "options"; "required": false; "isSignal": true; }; "label": { "alias": "label"; "required": false; "isSignal": true; }; "ariaLabel": { "alias": "ariaLabel"; "required": false; "isSignal": true; }; "size": { "alias": "size"; "required": false; "isSignal": true; }; "helperText": { "alias": "helperText"; "required": false; "isSignal": true; }; "state": { "alias": "state"; "required": false; "isSignal": true; }; "required": { "alias": "required"; "required": false; "isSignal": true; }; "showAsterisk": { "alias": "showAsterisk"; "required": false; "isSignal": true; }; "leftIcon": { "alias": "leftIcon"; "required": false; "isSignal": true; }; "id": { "alias": "id"; "required": false; "isSignal": true; }; "disabled": { "alias": "disabled"; "required": false; "isSignal": true; }; "floatingLabel": { "alias": "floatingLabel"; "required": false; "isSignal": true; }; "labelPosition": { "alias": "labelPosition"; "required": false; "isSignal": true; }; "labelWidth": { "alias": "labelWidth"; "required": false; "isSignal": true; }; "floatingVariant": { "alias": "floatingVariant"; "required": false; "isSignal": true; }; "placeholder": { "alias": "placeholder"; "required": false; "isSignal": true; }; "multiple": { "alias": "multiple"; "required": false; "isSignal": true; }; "searchable": { "alias": "searchable"; "required": false; "isSignal": true; }; "clearable": { "alias": "clearable"; "required": false; "isSignal": true; }; "loading": { "alias": "loading"; "required": false; "isSignal": true; }; "readonly": { "alias": "readonly"; "required": false; "isSignal": true; }; "labelKey": { "alias": "labelKey"; "required": false; "isSignal": true; }; "valueKey": { "alias": "valueKey"; "required": false; "isSignal": true; }; "groupBy": { "alias": "groupBy"; "required": false; "isSignal": true; }; "emptyText": { "alias": "emptyText"; "required": false; "isSignal": true; }; "searchPlaceholder": { "alias": "searchPlaceholder"; "required": false; "isSignal": true; }; "appendTo": { "alias": "appendTo"; "required": false; "isSignal": true; }; "menuClass": { "alias": "menuClass"; "required": false; "isSignal": true; }; "matchTriggerWidth": { "alias": "matchTriggerWidth"; "required": false; "isSignal": true; }; "maxSelectedItems": { "alias": "maxSelectedItems"; "required": false; "isSignal": true; }; "closeOnSelect": { "alias": "closeOnSelect"; "required": false; "isSignal": true; }; "hideSelected": { "alias": "hideSelected"; "required": false; "isSignal": true; }; "allowCreate": { "alias": "allowCreate"; "required": false; "isSignal": true; }; "createText": { "alias": "createText"; "required": false; "isSignal": true; }; "groupSeparator": { "alias": "groupSeparator"; "required": false; "isSignal": true; }; "searchPosition": { "alias": "searchPosition"; "required": false; "isSignal": true; }; "searchIcon": { "alias": "searchIcon"; "required": false; "isSignal": true; }; "searchPrefix": { "alias": "searchPrefix"; "required": false; "isSignal": true; }; "triggerIcon": { "alias": "triggerIcon"; "required": false; "isSignal": true; }; "triggerLabel": { "alias": "triggerLabel"; "required": false; "isSignal": true; }; "remoteSearch": { "alias": "remoteSearch"; "required": false; "isSignal": true; }; "minTermLength": { "alias": "minTermLength"; "required": false; "isSignal": true; }; "debounceMs": { "alias": "debounceMs"; "required": false; "isSignal": true; }; "typeToSearchText": { "alias": "typeToSearchText"; "required": false; "isSignal": true; }; "virtualScroll": { "alias": "virtualScroll"; "required": false; "isSignal": true; }; "itemHeight": { "alias": "itemHeight"; "required": false; "isSignal": true; }; "bufferAmount": { "alias": "bufferAmount"; "required": false; "isSignal": true; }; }, { "value": "valueChange"; "disabled": "disabledChange"; "search": "search"; "opened": "opened"; "closed": "closed"; "cleared": "cleared"; "added": "added"; "removed": "removed"; "selectionChange": "selectionChange"; }, ["optionTemplate", "labelTemplate"], ["[leftIcon]"], true, never>;
|
|
2817
3372
|
}
|
|
2818
3373
|
|
|
2819
3374
|
/**
|
|
@@ -3031,45 +3586,531 @@ declare class OlToggleGroup {
|
|
|
3031
3586
|
static ɵcmp: _angular_core.ɵɵComponentDeclaration<OlToggleGroup, "ol-toggle-group", never, { "label": { "alias": "label"; "required": false; "isSignal": true; }; }, {}, never, ["*"], true, never>;
|
|
3032
3587
|
}
|
|
3033
3588
|
|
|
3589
|
+
/**
|
|
3590
|
+
* Một lựa chọn của `ol-segmented`. `value` là thứ đổ vào model — dùng chuỗi
|
|
3591
|
+
* hoặc số, so bằng `===`.
|
|
3592
|
+
*/
|
|
3593
|
+
interface SegmentedOption<T = string | number> {
|
|
3594
|
+
value: T;
|
|
3595
|
+
label: string;
|
|
3596
|
+
icon?: string;
|
|
3597
|
+
disabled?: boolean;
|
|
3598
|
+
/**
|
|
3599
|
+
* Màu của mục KHI ĐANG CHỌN — cho lựa chọn mang nghĩa (Đạt / Chưa đạt,
|
|
3600
|
+
* Đúng / Sai). Không truyền thì nền trắng chữ đậm như mặc định.
|
|
3601
|
+
*/
|
|
3602
|
+
color?: SegmentedColor;
|
|
3603
|
+
}
|
|
3604
|
+
type SegmentedColor = 'neutral' | 'brand' | 'success' | 'warning' | 'danger';
|
|
3605
|
+
type SegmentedSize = 'sm' | 'base';
|
|
3606
|
+
/**
|
|
3607
|
+
* Chọn MỘT trong vài chế độ loại trừ nhau, đặt cạnh nhau trên một rãnh xám;
|
|
3608
|
+
* mục đang chọn nổi lên nền trắng (segmented control).
|
|
3609
|
+
*
|
|
3610
|
+
* Khác `ol-tabs`: tabs chuyển PANEL nội dung, đây chọn GIÁ TRỊ (có CVA, dùng
|
|
3611
|
+
* được trong form). Khác `ol-toggle`: công tắc chỉ có hai trạng thái bật/tắt.
|
|
3612
|
+
*
|
|
3613
|
+
* Trợ năng theo mẫu radio group của WAI-ARIA: `role="radiogroup"`, mỗi mục
|
|
3614
|
+
* `role="radio"`, chỉ mục đang chọn nằm trong thứ tự Tab (roving tabindex),
|
|
3615
|
+
* mũi tên trái/phải/lên/xuống chuyển VÀ chọn luôn, Home/End về đầu/cuối.
|
|
3616
|
+
*
|
|
3617
|
+
* Figma chưa có thiết kế (tra `lip4g3...` 2026-09-28: không có component nào
|
|
3618
|
+
* tên segmented) — dựng theo token của hệ thống.
|
|
3619
|
+
*/
|
|
3620
|
+
declare class OlSegmented implements ControlValueAccessor {
|
|
3621
|
+
readonly options: _angular_core.InputSignal<SegmentedOption<string | number>[]>;
|
|
3622
|
+
readonly value: _angular_core.ModelSignal<string | number | null>;
|
|
3623
|
+
readonly size: _angular_core.InputSignal<SegmentedSize>;
|
|
3624
|
+
/** Giãn hết bề ngang khung, các mục chia đều. */
|
|
3625
|
+
readonly fullWidth: _angular_core.InputSignal<boolean>;
|
|
3626
|
+
/** `model()` để `setDisabledState()` của Reactive Forms đặt được. */
|
|
3627
|
+
readonly disabled: _angular_core.ModelSignal<boolean>;
|
|
3628
|
+
/** Tên nhóm cho bộ đọc màn hình — nên đặt, vì nhóm không có nhãn nhìn thấy. */
|
|
3629
|
+
readonly ariaLabel: _angular_core.InputSignal<string>;
|
|
3630
|
+
private readonly host;
|
|
3631
|
+
private onChange;
|
|
3632
|
+
private onTouched;
|
|
3633
|
+
protected readonly hostClasses: _angular_core.Signal<"block w-full" | "inline-block max-w-full">;
|
|
3634
|
+
protected readonly trackClasses: _angular_core.Signal<string>;
|
|
3635
|
+
/** Mục đang Tab vào được: mục đang chọn, không có thì mục bật đầu tiên. */
|
|
3636
|
+
protected readonly focusIndex: _angular_core.Signal<number>;
|
|
3637
|
+
protected itemClasses(option: SegmentedOption): string;
|
|
3638
|
+
select(option: SegmentedOption): void;
|
|
3639
|
+
protected onKeydown(event: KeyboardEvent, index: number): void;
|
|
3640
|
+
/** Mục bật kế tiếp theo chiều `step`, vòng quanh. -1 khi không có. */
|
|
3641
|
+
private nextEnabled;
|
|
3642
|
+
writeValue(v: string | number | null): void;
|
|
3643
|
+
registerOnChange(fn: (v: string | number | null) => void): void;
|
|
3644
|
+
registerOnTouched(fn: () => void): void;
|
|
3645
|
+
setDisabledState(isDisabled: boolean): void;
|
|
3646
|
+
static ɵfac: _angular_core.ɵɵFactoryDeclaration<OlSegmented, never>;
|
|
3647
|
+
static ɵcmp: _angular_core.ɵɵComponentDeclaration<OlSegmented, "ol-segmented", never, { "options": { "alias": "options"; "required": false; "isSignal": true; }; "value": { "alias": "value"; "required": false; "isSignal": true; }; "size": { "alias": "size"; "required": false; "isSignal": true; }; "fullWidth": { "alias": "fullWidth"; "required": false; "isSignal": true; }; "disabled": { "alias": "disabled"; "required": false; "isSignal": true; }; "ariaLabel": { "alias": "ariaLabel"; "required": false; "isSignal": true; }; }, { "value": "valueChange"; "disabled": "disabledChange"; }, never, never, true, never>;
|
|
3648
|
+
}
|
|
3649
|
+
|
|
3650
|
+
/**
|
|
3651
|
+
* Loại tệp — nhận biết để chọn icon, màu và chữ mô tả.
|
|
3652
|
+
*
|
|
3653
|
+
* Mười loại phủ gần hết tệp giáo viên/học sinh tải lên: bài làm (ảnh, PDF,
|
|
3654
|
+
* Word), bảng điểm (Excel), bài giảng (PowerPoint, video), nghe (audio), nộp
|
|
3655
|
+
* gộp (nén), bài tin học (mã nguồn), ghi chú (văn bản thô).
|
|
3656
|
+
*/
|
|
3657
|
+
type FileKind = 'image' | 'pdf' | 'word' | 'excel' | 'powerpoint' | 'video' | 'audio' | 'archive' | 'code' | 'text' | 'other';
|
|
3658
|
+
interface FileKindMeta {
|
|
3659
|
+
label: string;
|
|
3660
|
+
/** Họ lucide `file-*` — một họ nét cho mọi loại, nhìn đồng bộ. */
|
|
3661
|
+
icon: string;
|
|
3662
|
+
/**
|
|
3663
|
+
* Màu ô icon, lấy từ bảng màu `ol-icon-shape` — không tự tô. KHÔNG dùng
|
|
3664
|
+
* `dark`: nó là ô ĐẶC đen giữa các ô nền nhạt, nặng hơn hẳn (đo 2026-09-28).
|
|
3665
|
+
*/
|
|
3666
|
+
color: IconShapeColor;
|
|
3667
|
+
}
|
|
3668
|
+
declare const FILE_KIND_META: Record<FileKind, FileKindMeta>;
|
|
3669
|
+
/** Phần mở rộng, chữ thường, không dấu chấm. Không có → chuỗi rỗng. */
|
|
3670
|
+
declare function fileExtension(name: string): string;
|
|
3671
|
+
/**
|
|
3672
|
+
* Nhận biết loại tệp — ưu tiên PHẦN MỞ RỘNG, lùi về MIME.
|
|
3673
|
+
*
|
|
3674
|
+
* Không tin MIME trước: trình duyệt đoán MIME theo đuôi và hệ điều hành, nên
|
|
3675
|
+
* cùng một tệp `.docx` có máy báo `application/vnd.openxml…`, có máy báo rỗng
|
|
3676
|
+
* (Windows thiếu Office), và `.csv` có máy báo `application/vnd.ms-excel`.
|
|
3677
|
+
*/
|
|
3678
|
+
declare function detectFileKind(name: string, mime?: string): FileKind;
|
|
3679
|
+
/**
|
|
3680
|
+
* Byte → chữ ngắn theo cách người Việt đọc: `850 B`, `12,4 KB`, `3,2 MB`.
|
|
3681
|
+
* Dấu phẩy thập phân; số nguyên thì bỏ phần lẻ (`2 MB`, không `2,0 MB`).
|
|
3682
|
+
*/
|
|
3683
|
+
declare function formatFileSize(bytes: number): string;
|
|
3684
|
+
/**
|
|
3685
|
+
* Tệp có khớp chuỗi `accept` của thẻ `<input type="file">` không.
|
|
3686
|
+
*
|
|
3687
|
+
* Hiểu đủ ba dạng của chuẩn HTML: đuôi (`.pdf`), MIME đầy đủ
|
|
3688
|
+
* (`application/pdf`), MIME đại diện (`image/*`). `*` hoặc rỗng → nhận hết.
|
|
3689
|
+
*
|
|
3690
|
+
* Cần tự kiểm vì `accept` chỉ LỌC hộp thoại chọn tệp — kéo thả thì trình duyệt
|
|
3691
|
+
* không lọc gì, và người dùng đổi bộ lọc hộp thoại sang "Tất cả tệp" là chọn
|
|
3692
|
+
* được tệp bất kỳ.
|
|
3693
|
+
*/
|
|
3694
|
+
declare function matchesAccept(file: {
|
|
3695
|
+
name: string;
|
|
3696
|
+
type: string;
|
|
3697
|
+
}, accept: string): boolean;
|
|
3698
|
+
type FileRejectReason = 'type' | 'size' | 'count';
|
|
3699
|
+
interface FileRejection {
|
|
3700
|
+
file: File;
|
|
3701
|
+
reason: FileRejectReason;
|
|
3702
|
+
/** Câu báo lỗi tiếng Việt, hiện được ngay. */
|
|
3703
|
+
message: string;
|
|
3704
|
+
}
|
|
3705
|
+
interface FileValidationRules {
|
|
3706
|
+
accept?: string;
|
|
3707
|
+
/** Byte. 0 hoặc không truyền → không giới hạn. */
|
|
3708
|
+
maxSize?: number;
|
|
3709
|
+
/** Tổng số tệp tối đa, TÍNH CẢ tệp đã có. 0 → không giới hạn. */
|
|
3710
|
+
maxFiles?: number;
|
|
3711
|
+
/** Số tệp đang có sẵn trước lượt chọn này. */
|
|
3712
|
+
existingCount?: number;
|
|
3713
|
+
}
|
|
3714
|
+
interface FileValidationResult {
|
|
3715
|
+
accepted: File[];
|
|
3716
|
+
rejected: FileRejection[];
|
|
3717
|
+
}
|
|
3718
|
+
/**
|
|
3719
|
+
* Chia tệp thành nhận / loại, kèm lý do từng tệp bị loại.
|
|
3720
|
+
*
|
|
3721
|
+
* Thứ tự kiểm: định dạng → dung lượng → số lượng. Tệp sai định dạng không
|
|
3722
|
+
* chiếm chỗ trong hạn mức số lượng — chọn 3 tệp, 1 tệp `.exe`, giới hạn 2 thì
|
|
3723
|
+
* nhận 2 tệp hợp lệ chứ không loại oan tệp thứ ba vì tệp `.exe` đứng trước.
|
|
3724
|
+
*/
|
|
3725
|
+
declare function validateFiles(files: File[], rules?: FileValidationRules): FileValidationResult;
|
|
3726
|
+
/** Trạng thái tải của một tệp — nơi gọi cập nhật theo tiến trình HTTP thật. */
|
|
3727
|
+
type UploadStatus = 'idle' | 'uploading' | 'success' | 'error';
|
|
3728
|
+
/**
|
|
3729
|
+
* Một tệp trong danh sách tải lên.
|
|
3730
|
+
*
|
|
3731
|
+
* `file` có thể vắng: tệp đã có sẵn trên máy chủ (mở lại bài đã nộp) chỉ có
|
|
3732
|
+
* tên, dung lượng và `url`, không có đối tượng `File`.
|
|
3733
|
+
*/
|
|
3734
|
+
interface OlUploadFile {
|
|
3735
|
+
id: string;
|
|
3736
|
+
name: string;
|
|
3737
|
+
size: number;
|
|
3738
|
+
file?: File;
|
|
3739
|
+
/** Ảnh xem trước hoặc liên kết tải về. */
|
|
3740
|
+
url?: string;
|
|
3741
|
+
status?: UploadStatus;
|
|
3742
|
+
/** 0–100, chỉ dùng khi `status = 'uploading'`. */
|
|
3743
|
+
progress?: number;
|
|
3744
|
+
/** Câu báo lỗi khi `status = 'error'`. */
|
|
3745
|
+
error?: string;
|
|
3746
|
+
}
|
|
3747
|
+
/** File → OlUploadFile, gán id duy nhất để `@for track` không lẫn hai tệp trùng tên. */
|
|
3748
|
+
declare function toUploadFile(file: File): OlUploadFile;
|
|
3749
|
+
/**
|
|
3750
|
+
* Tệp trong một lần dán (Ctrl+V / ⌘V).
|
|
3751
|
+
*
|
|
3752
|
+
* Đọc cả `clipboardData.files` lẫn `items` loại `file`: Chrome đặt ảnh chụp
|
|
3753
|
+
* màn hình ở cả hai, Safari có lúc chỉ ở `items`. Gộp theo đối tượng để không
|
|
3754
|
+
* nhận một ảnh hai lần.
|
|
3755
|
+
*
|
|
3756
|
+
* Ảnh chụp màn hình dán vào LUÔN tên `image.png` — dán ba lần là ba tệp trùng
|
|
3757
|
+
* tên, không phân biệt được trong danh sách. Đổi thành "Ảnh dán 14-32-05.png".
|
|
3758
|
+
*/
|
|
3759
|
+
declare function filesFromClipboard(data: DataTransfer | null, now?: Date): File[];
|
|
3760
|
+
/** Phím tắt dán theo hệ điều hành — để gợi ý đúng chữ người dùng thấy trên bàn phím. */
|
|
3761
|
+
declare function pasteShortcutLabel(platform?: string): string;
|
|
3762
|
+
/** Đang gõ trong ô nhập chữ — dán ở đó là dán CHỮ, không được cướp. */
|
|
3763
|
+
declare function isEditableTarget(target: EventTarget | null): boolean;
|
|
3764
|
+
|
|
3034
3765
|
/**
|
|
3035
3766
|
* Thang cỡ theo Figma: `sm | base | lg`. `'md'` là BÍ DANH của `'base'`,
|
|
3036
3767
|
* giữ cho mã cũ chạy tiếp và sẽ bỏ ở bản sau — dùng `'base'` cho mã mới.
|
|
3037
3768
|
*/
|
|
3038
|
-
type FileInputSize = 'sm' | 'base' | 'lg' | 'md';
|
|
3039
|
-
declare class OlFileInput {
|
|
3040
|
-
/** Id tự sinh khi nơi gọi không truyền id — để <label for> và
|
|
3041
|
-
* aria-describedby luôn nối được với ô nhập. */
|
|
3042
|
-
private readonly uid;
|
|
3043
|
-
readonly inputId: _angular_core.Signal<string>;
|
|
3044
|
-
readonly helperId: _angular_core.Signal<string>;
|
|
3045
|
-
readonly describedBy: _angular_core.Signal<string | null>;
|
|
3046
|
-
readonly ariaInvalid: _angular_core.Signal<null>;
|
|
3047
|
-
readonly label: _angular_core.InputSignal<string>;
|
|
3048
|
-
readonly helperText: _angular_core.InputSignal<string>;
|
|
3049
|
-
readonly disabled: _angular_core.InputSignal<boolean>;
|
|
3050
|
-
readonly dropzone: _angular_core.InputSignal<boolean>;
|
|
3769
|
+
type FileInputSize = 'sm' | 'base' | 'lg' | 'md';
|
|
3770
|
+
declare class OlFileInput {
|
|
3771
|
+
/** Id tự sinh khi nơi gọi không truyền id — để <label for> và
|
|
3772
|
+
* aria-describedby luôn nối được với ô nhập. */
|
|
3773
|
+
private readonly uid;
|
|
3774
|
+
readonly inputId: _angular_core.Signal<string>;
|
|
3775
|
+
readonly helperId: _angular_core.Signal<string>;
|
|
3776
|
+
readonly describedBy: _angular_core.Signal<string | null>;
|
|
3777
|
+
readonly ariaInvalid: _angular_core.Signal<null>;
|
|
3778
|
+
readonly label: _angular_core.InputSignal<string>;
|
|
3779
|
+
readonly helperText: _angular_core.InputSignal<string>;
|
|
3780
|
+
readonly disabled: _angular_core.InputSignal<boolean>;
|
|
3781
|
+
readonly dropzone: _angular_core.InputSignal<boolean>;
|
|
3782
|
+
readonly title: _angular_core.InputSignal<string>;
|
|
3783
|
+
readonly description: _angular_core.InputSignal<string>;
|
|
3784
|
+
readonly size: _angular_core.InputSignal<FileInputSize>;
|
|
3785
|
+
/** Cỡ đã quy bí danh: `'md'` -> `'base'`. Template so với cái này. */
|
|
3786
|
+
protected readonly resolvedSize: _angular_core.Signal<FileInputSize>;
|
|
3787
|
+
/**
|
|
3788
|
+
* Padding theo size. Không dùng [class.p-1.5] trên template vì Angular
|
|
3789
|
+
* cắt phần sau dấu chấm — nó render ra "p-1" (4px thay vì 6px).
|
|
3790
|
+
*/
|
|
3791
|
+
readonly paddingClass: _angular_core.Signal<"p-1" | "p-1.5" | "p-2">;
|
|
3792
|
+
readonly accept: _angular_core.InputSignal<string>;
|
|
3793
|
+
readonly multiple: _angular_core.InputSignal<boolean>;
|
|
3794
|
+
readonly id: _angular_core.InputSignal<string>;
|
|
3795
|
+
/** Byte. 0 → không giới hạn. Có giá trị thì vùng kéo thả ghi "Dung lượng tối đa". */
|
|
3796
|
+
readonly maxSize: _angular_core.InputSignal<number>;
|
|
3797
|
+
/** Nhãn nút trong vùng kéo thả (Figma Advanced). Rỗng → không vẽ nút. */
|
|
3798
|
+
readonly ctaLabel: _angular_core.InputSignal<string>;
|
|
3799
|
+
/** Figma State: Danger / Success. Tệp bị loại tự chuyển sang `error`. */
|
|
3800
|
+
readonly state: _angular_core.InputSignal<"error" | "success" | "default">;
|
|
3801
|
+
/** Tệp đã nhận (sau khi kiểm). */
|
|
3802
|
+
readonly selectedFiles: _angular_core.WritableSignal<File[]>;
|
|
3803
|
+
protected readonly items: _angular_core.WritableSignal<OlUploadFile[]>;
|
|
3804
|
+
protected readonly errors: _angular_core.WritableSignal<string[]>;
|
|
3805
|
+
readonly filesChanged: _angular_core.OutputEmitterRef<File[]>;
|
|
3806
|
+
/** Tệp bị loại kèm lý do — component đã tự hiện câu lỗi. */
|
|
3807
|
+
readonly rejected: _angular_core.OutputEmitterRef<FileRejection[]>;
|
|
3808
|
+
private readonly dropInput;
|
|
3809
|
+
private readonly host;
|
|
3810
|
+
protected readonly zoneState: _angular_core.Signal<"error" | "success" | "default">;
|
|
3811
|
+
/**
|
|
3812
|
+
* Dòng phụ trong vùng: "Dung lượng tối đa" nếu có `maxSize`, không thì
|
|
3813
|
+
* `description` — giữ nguyên chữ của mã cũ đang truyền `description`.
|
|
3814
|
+
*/
|
|
3815
|
+
protected readonly zoneHint: _angular_core.Signal<string>;
|
|
3816
|
+
onFileSelected(event: Event): void;
|
|
3817
|
+
protected openPicker(): void;
|
|
3818
|
+
/** Nhận tệp từ hộp chọn hoặc kéo thả: kiểm định dạng + dung lượng rồi phát. */
|
|
3819
|
+
protected receive(incoming: File[]): void;
|
|
3820
|
+
/** Dán tệp (Ctrl+V / ⌘V) khi tiêu điểm ở ô hoặc vùng kéo thả. */
|
|
3821
|
+
protected onPaste(event: ClipboardEvent): void;
|
|
3822
|
+
/**
|
|
3823
|
+
* Ô thường (không dropzone) hiện tên tệp bằng CHÍNH `<input type="file">` —
|
|
3824
|
+
* nhận tệp dán mà không gán vào nó thì ô vẫn ghi "Chưa chọn tệp" dù đã nhận.
|
|
3825
|
+
* `DataTransfer` là cách duy nhất gán `files` cho ô tệp.
|
|
3826
|
+
*/
|
|
3827
|
+
private syncNativeInput;
|
|
3828
|
+
protected removeItem(item: OlUploadFile): void;
|
|
3829
|
+
static ɵfac: _angular_core.ɵɵFactoryDeclaration<OlFileInput, never>;
|
|
3830
|
+
static ɵcmp: _angular_core.ɵɵComponentDeclaration<OlFileInput, "ol-file-input", never, { "label": { "alias": "label"; "required": false; "isSignal": true; }; "helperText": { "alias": "helperText"; "required": false; "isSignal": true; }; "disabled": { "alias": "disabled"; "required": false; "isSignal": true; }; "dropzone": { "alias": "dropzone"; "required": false; "isSignal": true; }; "title": { "alias": "title"; "required": false; "isSignal": true; }; "description": { "alias": "description"; "required": false; "isSignal": true; }; "size": { "alias": "size"; "required": false; "isSignal": true; }; "accept": { "alias": "accept"; "required": false; "isSignal": true; }; "multiple": { "alias": "multiple"; "required": false; "isSignal": true; }; "id": { "alias": "id"; "required": false; "isSignal": true; }; "maxSize": { "alias": "maxSize"; "required": false; "isSignal": true; }; "ctaLabel": { "alias": "ctaLabel"; "required": false; "isSignal": true; }; "state": { "alias": "state"; "required": false; "isSignal": true; }; }, { "filesChanged": "filesChanged"; "rejected": "rejected"; }, never, never, true, never>;
|
|
3831
|
+
}
|
|
3832
|
+
|
|
3833
|
+
/**
|
|
3834
|
+
* Ba dạng của một tệp:
|
|
3835
|
+
*
|
|
3836
|
+
* - `row` — dòng trong danh sách: icon loại tệp, tên, dung lượng, thanh tiến
|
|
3837
|
+
* trình khi đang tải, nút thử lại khi lỗi. Figma không vẽ dạng này; dựng theo
|
|
3838
|
+
* token để danh sách tải nhiều tệp có chỗ báo tiến trình từng tệp.
|
|
3839
|
+
* - `chip` — Figma "Button header + Dropbox (uploaded no limit)": viên bo góc,
|
|
3840
|
+
* nút xem 👁 + tên + ✕.
|
|
3841
|
+
* - `card` — Figma "Button header + Dropbox (uploaded max 1 file)": khung viền,
|
|
3842
|
+
* icon + tên ở giữa, ✕ ở góc.
|
|
3843
|
+
*/
|
|
3844
|
+
type FileItemVariant = 'row' | 'chip' | 'card';
|
|
3845
|
+
declare class OlFileItem {
|
|
3846
|
+
readonly file: _angular_core.InputSignal<OlUploadFile>;
|
|
3847
|
+
readonly variant: _angular_core.InputSignal<FileItemVariant>;
|
|
3848
|
+
readonly removable: _angular_core.InputSignal<boolean>;
|
|
3849
|
+
/** Hiện nút xem 👁 — nơi gọi tự mở tệp khi nhận `(preview)`. */
|
|
3850
|
+
readonly previewable: _angular_core.InputSignal<boolean>;
|
|
3851
|
+
readonly disabled: _angular_core.InputSignal<boolean>;
|
|
3852
|
+
readonly remove: _angular_core.OutputEmitterRef<OlUploadFile>;
|
|
3853
|
+
readonly preview: _angular_core.OutputEmitterRef<OlUploadFile>;
|
|
3854
|
+
readonly retry: _angular_core.OutputEmitterRef<OlUploadFile>;
|
|
3855
|
+
protected readonly kind: _angular_core.Signal<_edmicro_olkit.FileKind>;
|
|
3856
|
+
protected readonly meta: _angular_core.Signal<_edmicro_olkit.FileKindMeta>;
|
|
3857
|
+
protected readonly sizeText: _angular_core.Signal<string>;
|
|
3858
|
+
protected readonly status: _angular_core.Signal<_edmicro_olkit.UploadStatus>;
|
|
3859
|
+
protected readonly progress: _angular_core.Signal<number>;
|
|
3860
|
+
/** Dòng phụ dưới tên: dung lượng + trạng thái, đọc được cả khi không nhìn màu. */
|
|
3861
|
+
protected readonly metaText: _angular_core.Signal<string>;
|
|
3862
|
+
protected readonly metaClass: _angular_core.Signal<"text-xs text-fg-danger" | "text-xs text-body-subtle">;
|
|
3863
|
+
protected readonly rowClass: _angular_core.Signal<string>;
|
|
3864
|
+
/** Nút hành động nhỏ — cùng hình với nút đóng của drawer/modal. */
|
|
3865
|
+
protected readonly actionClass = "inline-flex size-8 shrink-0 items-center justify-center rounded-md text-body-subtle transition-colors hover:bg-neutral-tertiary hover:text-heading focus-visible:outline-hidden focus-visible:ring-2 focus-visible:ring-brand-subtle disabled:pointer-events-none disabled:opacity-50";
|
|
3866
|
+
static ɵfac: _angular_core.ɵɵFactoryDeclaration<OlFileItem, never>;
|
|
3867
|
+
static ɵcmp: _angular_core.ɵɵComponentDeclaration<OlFileItem, "ol-file-item", never, { "file": { "alias": "file"; "required": true; "isSignal": true; }; "variant": { "alias": "variant"; "required": false; "isSignal": true; }; "removable": { "alias": "removable"; "required": false; "isSignal": true; }; "previewable": { "alias": "previewable"; "required": false; "isSignal": true; }; "disabled": { "alias": "disabled"; "required": false; "isSignal": true; }; }, { "remove": "remove"; "preview": "preview"; "retry": "retry"; }, never, never, true, never>;
|
|
3868
|
+
}
|
|
3869
|
+
|
|
3870
|
+
/**
|
|
3871
|
+
* Vùng kéo–thả, theo Figma `ol-file-input-form` Type=Advanced (1149:48977):
|
|
3872
|
+
* icon tải lên · "Nhấn để tải lên hoặc kéo thả" · "Dung lượng tối đa: …" ·
|
|
3873
|
+
* (tuỳ chọn) nút "Chọn tệp".
|
|
3874
|
+
*
|
|
3875
|
+
* ## Cả vùng là MỘT `<button>`
|
|
3876
|
+
*
|
|
3877
|
+
* Bản cũ trong `ol-file-input` đặt `<input type="file" class="hidden">` —
|
|
3878
|
+
* `display: none` nên Tab không tới được, bàn phím không mở được hộp chọn tệp.
|
|
3879
|
+
* Ở đây vùng là nút thật: Tab tới, Enter/Space mở hộp chọn (qua `(pick)`, nơi
|
|
3880
|
+
* gọi gọi `input.click()`), và trình đọc màn hình đọc nhãn của nút.
|
|
3881
|
+
*
|
|
3882
|
+
* Nút "Chọn tệp" bên trong chỉ là HÌNH (`<span>`), không lồng `<button>` trong
|
|
3883
|
+
* `<button>` — HTML cấm, và hai nút lồng nhau làm một lần bấm bắn hai sự kiện.
|
|
3884
|
+
*/
|
|
3885
|
+
declare class OlFileDropzone {
|
|
3886
|
+
readonly title: _angular_core.InputSignal<string>;
|
|
3887
|
+
/** Dòng phụ, ví dụ "Dung lượng tối đa: 30MB". Rỗng → không vẽ. */
|
|
3888
|
+
readonly hint: _angular_core.InputSignal<string>;
|
|
3889
|
+
/** Nhãn nút "Chọn tệp" trong vùng (Figma Advanced). Rỗng → không vẽ nút. */
|
|
3890
|
+
readonly ctaLabel: _angular_core.InputSignal<string>;
|
|
3891
|
+
readonly icon: _angular_core.InputSignal<string>;
|
|
3892
|
+
readonly disabled: _angular_core.InputSignal<boolean>;
|
|
3893
|
+
/** Trạng thái viền: lỗi / thành công (Figma State=Danger / Success). */
|
|
3894
|
+
readonly state: _angular_core.InputSignal<"error" | "success" | "default">;
|
|
3895
|
+
/** Chiều cao tối thiểu — vùng trong khung có tiêu đề thấp hơn vùng đứng riêng. */
|
|
3896
|
+
readonly compact: _angular_core.InputSignal<boolean>;
|
|
3897
|
+
readonly describedBy: _angular_core.InputSignal<string>;
|
|
3898
|
+
/** Dòng "hoặc dán ⌘V / Ctrl+V". Tắt khi nơi gọi không nhận tệp dán. */
|
|
3899
|
+
readonly pasteHint: _angular_core.InputSignal<boolean>;
|
|
3900
|
+
protected readonly shortcut: string;
|
|
3901
|
+
/** Bấm vào vùng (chuột hoặc bàn phím) — nơi gọi mở hộp chọn tệp. */
|
|
3902
|
+
readonly pick: _angular_core.OutputEmitterRef<void>;
|
|
3903
|
+
/** Tệp thả hoặc DÁN vào vùng. CHƯA kiểm định dạng — việc của nơi gọi. */
|
|
3904
|
+
readonly filesDropped: _angular_core.OutputEmitterRef<File[]>;
|
|
3905
|
+
protected readonly dragging: _angular_core.WritableSignal<boolean>;
|
|
3906
|
+
protected readonly zoneClass: _angular_core.Signal<string>;
|
|
3907
|
+
protected onDragOver(event: DragEvent): void;
|
|
3908
|
+
protected onDragLeave(event: DragEvent): void;
|
|
3909
|
+
/**
|
|
3910
|
+
* Dán khi tiêu điểm đang ở vùng. Có tệp thì nhận và `stopPropagation` — khung
|
|
3911
|
+
* cha (`ol-file-upload`) cũng nghe `paste`, không chặn là nhận hai lần. Không
|
|
3912
|
+
* có tệp (dán chữ) thì để yên cho trình duyệt.
|
|
3913
|
+
*/
|
|
3914
|
+
protected onPaste(event: ClipboardEvent): void;
|
|
3915
|
+
protected onDrop(event: DragEvent): void;
|
|
3916
|
+
static ɵfac: _angular_core.ɵɵFactoryDeclaration<OlFileDropzone, never>;
|
|
3917
|
+
static ɵcmp: _angular_core.ɵɵComponentDeclaration<OlFileDropzone, "ol-file-dropzone", never, { "title": { "alias": "title"; "required": false; "isSignal": true; }; "hint": { "alias": "hint"; "required": false; "isSignal": true; }; "ctaLabel": { "alias": "ctaLabel"; "required": false; "isSignal": true; }; "icon": { "alias": "icon"; "required": false; "isSignal": true; }; "disabled": { "alias": "disabled"; "required": false; "isSignal": true; }; "state": { "alias": "state"; "required": false; "isSignal": true; }; "compact": { "alias": "compact"; "required": false; "isSignal": true; }; "describedBy": { "alias": "describedBy"; "required": false; "isSignal": true; }; "pasteHint": { "alias": "pasteHint"; "required": false; "isSignal": true; }; }, { "pick": "pick"; "filesDropped": "filesDropped"; }, never, never, true, never>;
|
|
3918
|
+
}
|
|
3919
|
+
|
|
3920
|
+
/**
|
|
3921
|
+
* Toán phóng/kéo ảnh — hàm thuần, không đụng DOM, để test chính xác từng px.
|
|
3922
|
+
*
|
|
3923
|
+
* Ảnh vẽ bằng `transform: translate(x, y) scale(s)`, gốc biến đổi ở TÂM ảnh.
|
|
3924
|
+
* Một điểm `p` của ảnh (tính từ tâm, đơn vị px lúc chưa phóng) hiện ra ở
|
|
3925
|
+
* `q = t + s·p` so với tâm khung. Phóng quanh điểm `q` (chỗ bấm / con trỏ /
|
|
3926
|
+
* giữa hai ngón) nghĩa là giữ `q` đứng yên: `p = (q − t) / s`, `t' = q − s'·p`.
|
|
3927
|
+
*/
|
|
3928
|
+
interface ZoomState {
|
|
3929
|
+
scale: number;
|
|
3930
|
+
x: number;
|
|
3931
|
+
y: number;
|
|
3932
|
+
}
|
|
3933
|
+
|
|
3934
|
+
/** Một ảnh trong trình xem. */
|
|
3935
|
+
interface OlPreviewImage {
|
|
3936
|
+
src: string;
|
|
3937
|
+
/** Chữ thay thế — cũng hiện làm chú thích dưới ảnh. */
|
|
3938
|
+
alt?: string;
|
|
3939
|
+
}
|
|
3940
|
+
/**
|
|
3941
|
+
* Xem ảnh phóng to trên lớp phủ toàn màn (lightbox) — một ảnh hoặc lướt qua
|
|
3942
|
+
* nhiều ảnh.
|
|
3943
|
+
*
|
|
3944
|
+
* - Nhiều ảnh: nút ‹ › hai bên, số thứ tự "2 / 5", phím ← → chuyển ảnh, vòng quanh.
|
|
3945
|
+
* - Phóng to/thu nhỏ (1×–4×): bấm ảnh để phóng 2× đúng chỗ bấm, bấm lại để về;
|
|
3946
|
+
* nút − / + trên thanh, phím + − 0; cuộn chuột / chụm trackpad quanh con
|
|
3947
|
+
* trỏ; chụm hai ngón trên điện thoại. Đang phóng thì kéo để xem chỗ khác.
|
|
3948
|
+
* - Escape, nút ✕ hoặc bấm ra nền tối để đóng. Tiêu điểm bị giữ trong lớp phủ
|
|
3949
|
+
* và trả về chỗ cũ khi đóng; nền trang khoá cuộn (`OlFocusTrapService`).
|
|
3950
|
+
* - Escape đi qua ngăn xếp `OlOverlayContainer`: mở trình xem trong modal rồi
|
|
3951
|
+
* nhấn Escape chỉ đóng trình xem, modal còn nguyên.
|
|
3952
|
+
*
|
|
3953
|
+
* Dùng riêng được (`[(open)]` + `[images]` + `[(index)]`); `ol-file-upload`
|
|
3954
|
+
* chế độ `image`/`images` dùng nó để xem ảnh vừa chọn.
|
|
3955
|
+
*/
|
|
3956
|
+
declare class OlImagePreview {
|
|
3957
|
+
readonly images: _angular_core.InputSignal<OlPreviewImage[]>;
|
|
3958
|
+
readonly open: _angular_core.ModelSignal<boolean>;
|
|
3959
|
+
/** Ảnh đang xem, tính từ 0. */
|
|
3960
|
+
readonly index: _angular_core.ModelSignal<number>;
|
|
3961
|
+
readonly closed: _angular_core.OutputEmitterRef<void>;
|
|
3962
|
+
private readonly panel;
|
|
3963
|
+
private readonly thumbStrip;
|
|
3964
|
+
private readonly imageEl;
|
|
3965
|
+
protected readonly zoom: _angular_core.WritableSignal<ZoomState>;
|
|
3966
|
+
protected readonly dragging: _angular_core.WritableSignal<boolean>;
|
|
3967
|
+
protected readonly zoomPercent: _angular_core.Signal<number>;
|
|
3968
|
+
protected readonly canZoomIn: _angular_core.Signal<boolean>;
|
|
3969
|
+
protected readonly canZoomOut: _angular_core.Signal<boolean>;
|
|
3970
|
+
protected readonly imageStyle: _angular_core.Signal<string>;
|
|
3971
|
+
protected readonly imageClasses: _angular_core.Signal<string>;
|
|
3972
|
+
/** Ngón tay / chuột đang ấn trên ảnh, theo pointerId. */
|
|
3973
|
+
private readonly pointers;
|
|
3974
|
+
private pinchStart;
|
|
3975
|
+
private moved;
|
|
3976
|
+
/** Vừa kéo xong: cú `click` theo sau không được tính là bấm (phóng / đóng). */
|
|
3977
|
+
private suppressClick;
|
|
3978
|
+
private readonly focusTrap;
|
|
3979
|
+
private readonly overlayContainer;
|
|
3980
|
+
private releaseEscape;
|
|
3981
|
+
protected readonly count: _angular_core.Signal<number>;
|
|
3982
|
+
/** Kẹp chỉ số: danh sách ảnh có thể ngắn lại (vừa xoá ảnh) trong lúc đang mở. */
|
|
3983
|
+
protected readonly current: _angular_core.Signal<number>;
|
|
3984
|
+
protected readonly image: _angular_core.Signal<OlPreviewImage>;
|
|
3985
|
+
constructor();
|
|
3986
|
+
/** Ô ảnh nhỏ: ảnh đang xem rõ + viền trắng; ảnh khác mờ, rê chuột thì rõ. */
|
|
3987
|
+
protected thumbClasses(i: number): string;
|
|
3988
|
+
close(): void;
|
|
3989
|
+
next(): void;
|
|
3990
|
+
prev(): void;
|
|
3991
|
+
private go;
|
|
3992
|
+
protected onKeydown(event: KeyboardEvent): void;
|
|
3993
|
+
/** Bấm đúng nền tối (không phải ảnh hay nút) thì đóng. */
|
|
3994
|
+
protected onBackdropClick(event: MouseEvent): void;
|
|
3995
|
+
zoomIn(): void;
|
|
3996
|
+
zoomOut(): void;
|
|
3997
|
+
/** Bàn phím trên ảnh (Enter / Space): phóng 2× quanh tâm, hoặc về cỡ gốc. */
|
|
3998
|
+
toggleZoom(): void;
|
|
3999
|
+
resetZoom(): void;
|
|
4000
|
+
/** Kích thước ảnh khi CHƯA phóng (offsetWidth không tính transform). */
|
|
4001
|
+
private imageSize;
|
|
4002
|
+
/**
|
|
4003
|
+
* Điểm màn hình → toạ độ tính từ TÂM ảnh lúc chưa phóng. Hộp đã biến đổi có
|
|
4004
|
+
* tâm = tâm gốc + (x, y) — phóng quanh tâm không dời tâm.
|
|
4005
|
+
*/
|
|
4006
|
+
private toCenter;
|
|
4007
|
+
private zoomAround;
|
|
4008
|
+
/** Bấm ảnh: đang ở cỡ gốc thì phóng 2× đúng chỗ bấm, đang phóng thì về. */
|
|
4009
|
+
protected onImageClick(event: MouseEvent): void;
|
|
4010
|
+
/** Cuộn chuột / chụm trackpad (trình duyệt gửi wheel + ctrlKey): phóng quanh con trỏ. */
|
|
4011
|
+
protected onWheel(event: WheelEvent): void;
|
|
4012
|
+
protected onPointerDown(event: PointerEvent): void;
|
|
4013
|
+
protected onPointerMove(event: PointerEvent): void;
|
|
4014
|
+
protected onPointerUp(event: PointerEvent): void;
|
|
4015
|
+
private pinchDistance;
|
|
4016
|
+
private releaseTraps;
|
|
4017
|
+
static ɵfac: _angular_core.ɵɵFactoryDeclaration<OlImagePreview, never>;
|
|
4018
|
+
static ɵcmp: _angular_core.ɵɵComponentDeclaration<OlImagePreview, "ol-image-preview", never, { "images": { "alias": "images"; "required": false; "isSignal": true; }; "open": { "alias": "open"; "required": false; "isSignal": true; }; "index": { "alias": "index"; "required": false; "isSignal": true; }; }, { "open": "openChange"; "index": "indexChange"; "closed": "closed"; }, never, never, true, never>;
|
|
4019
|
+
}
|
|
4020
|
+
|
|
4021
|
+
/**
|
|
4022
|
+
* - `single` — một tệp; đã có thì thẻ tệp + nút "Thay đổi"
|
|
4023
|
+
* - `multiple` — nhiều tệp dạng chip (👁 + tên + ✕), cuộn khi dài
|
|
4024
|
+
* - `image` — một ảnh bìa phủ kín khung; bấm ảnh để xem phóng to
|
|
4025
|
+
* - `images` — nhiều ảnh dạng lưới ô vuông; bấm ô để xem, lướt ‹ › qua các ảnh
|
|
4026
|
+
* - `list` — nhiều tệp dạng DÒNG có thanh tiến trình — Figma không có,
|
|
4027
|
+
* dùng khi tải tệp lớn cần báo tiến trình từng tệp
|
|
4028
|
+
*/
|
|
4029
|
+
type FileUploadMode = 'single' | 'multiple' | 'image' | 'images' | 'list';
|
|
4030
|
+
/**
|
|
4031
|
+
* Khung tải tệp có tiêu đề — Figma `ol-file-input-form` "Button header + …"
|
|
4032
|
+
* (3587:6834 · 3592:6990 · 3603:2606 · 3611:3494).
|
|
4033
|
+
*
|
|
4034
|
+
* ## Component KHÔNG tự tải lên máy chủ
|
|
4035
|
+
*
|
|
4036
|
+
* Nó nhận tệp, kiểm định dạng/dung lượng/số lượng, thêm vào `files` với
|
|
4037
|
+
* `status: 'idle'` rồi phát `(filesAdded)`. Nơi gọi gửi HTTP và cập nhật
|
|
4038
|
+
* `status`/`progress` của từng tệp qua `[(files)]`. Để component tự gọi HTTP
|
|
4039
|
+
* thì nó phải biết URL, header xác thực, dạng phản hồi — ba thứ khác nhau ở
|
|
4040
|
+
* mỗi màn.
|
|
4041
|
+
*/
|
|
4042
|
+
declare class OlFileUpload {
|
|
3051
4043
|
readonly title: _angular_core.InputSignal<string>;
|
|
3052
|
-
readonly
|
|
3053
|
-
readonly
|
|
3054
|
-
/**
|
|
3055
|
-
|
|
4044
|
+
readonly required: _angular_core.InputSignal<boolean>;
|
|
4045
|
+
readonly mode: _angular_core.InputSignal<FileUploadMode>;
|
|
4046
|
+
/** Chuỗi `accept` của `<input type="file">` — cũng dùng để KIỂM tệp kéo thả. */
|
|
4047
|
+
readonly accept: _angular_core.InputSignal<string>;
|
|
4048
|
+
/** Byte. 0 → không giới hạn. */
|
|
4049
|
+
readonly maxSize: _angular_core.InputSignal<number>;
|
|
4050
|
+
/** Chỉ cho `multiple`/`list`. 0 → không giới hạn. */
|
|
4051
|
+
readonly maxFiles: _angular_core.InputSignal<number>;
|
|
4052
|
+
/** Nhãn nút ở đầu khung. Rỗng → tự chọn theo chế độ và trạng thái. */
|
|
4053
|
+
readonly buttonLabel: _angular_core.InputSignal<string>;
|
|
4054
|
+
/** Hiện nút 👁 trên từng tệp. */
|
|
4055
|
+
readonly previewable: _angular_core.InputSignal<boolean>;
|
|
4056
|
+
readonly disabled: _angular_core.InputSignal<boolean>;
|
|
3056
4057
|
/**
|
|
3057
|
-
*
|
|
3058
|
-
*
|
|
4058
|
+
* Nhận tệp dán (Ctrl+V / ⌘V) ở BẤT KỲ ĐÂU trên trang, không chỉ khi tiêu
|
|
4059
|
+
* điểm ở trong khung. Chỉ bật khi màn có MỘT khung tải — hai khung cùng bật
|
|
4060
|
+
* thì một lần dán vào cả hai. Đang gõ trong ô nhập chữ thì bỏ qua.
|
|
3059
4061
|
*/
|
|
3060
|
-
readonly
|
|
3061
|
-
|
|
3062
|
-
readonly
|
|
3063
|
-
readonly
|
|
3064
|
-
|
|
3065
|
-
readonly
|
|
3066
|
-
readonly
|
|
3067
|
-
|
|
3068
|
-
|
|
3069
|
-
|
|
3070
|
-
|
|
3071
|
-
|
|
3072
|
-
|
|
4062
|
+
readonly pasteFromPage: _angular_core.InputSignal<boolean>;
|
|
4063
|
+
/** Dòng gợi ý dưới khung, ví dụ định dạng cho phép. */
|
|
4064
|
+
readonly helperText: _angular_core.InputSignal<string>;
|
|
4065
|
+
readonly files: _angular_core.ModelSignal<OlUploadFile[]>;
|
|
4066
|
+
/** Tệp VỪA nhận, đã qua kiểm — nơi gọi bắt đầu tải lên từ đây. */
|
|
4067
|
+
readonly filesAdded: _angular_core.OutputEmitterRef<File[]>;
|
|
4068
|
+
readonly fileRemove: _angular_core.OutputEmitterRef<OlUploadFile>;
|
|
4069
|
+
readonly filePreview: _angular_core.OutputEmitterRef<OlUploadFile>;
|
|
4070
|
+
readonly fileRetry: _angular_core.OutputEmitterRef<OlUploadFile>;
|
|
4071
|
+
/** Tệp bị loại kèm lý do — component đã tự hiện câu lỗi dưới khung. */
|
|
4072
|
+
readonly rejected: _angular_core.OutputEmitterRef<FileRejection[]>;
|
|
4073
|
+
private readonly fileInput;
|
|
4074
|
+
private readonly host;
|
|
4075
|
+
protected readonly uid: string;
|
|
4076
|
+
protected readonly errors: _angular_core.WritableSignal<string[]>;
|
|
4077
|
+
protected readonly isMultiple: _angular_core.Signal<boolean>;
|
|
4078
|
+
protected readonly isImageMode: _angular_core.Signal<boolean>;
|
|
4079
|
+
protected readonly hasFiles: _angular_core.Signal<boolean>;
|
|
4080
|
+
protected readonly limitReached: _angular_core.Signal<boolean>;
|
|
4081
|
+
protected readonly resolvedButtonLabel: _angular_core.Signal<string>;
|
|
4082
|
+
protected readonly hintText: _angular_core.Signal<string>;
|
|
4083
|
+
protected readonly describedBy: _angular_core.Signal<string>;
|
|
4084
|
+
/**
|
|
4085
|
+
* Ảnh xem trước cho chế độ `image`/`images`, theo id tệp: `url` có sẵn (ảnh
|
|
4086
|
+
* đã trên máy chủ) hoặc object URL tạo từ `File`.
|
|
4087
|
+
*
|
|
4088
|
+
* Object URL phải THU HỒI khi tệp bị xoá / component huỷ, không thì mỗi ảnh
|
|
4089
|
+
* rò một khối bộ nhớ bằng cả ảnh. Giữ theo id để thêm một ảnh không tạo lại
|
|
4090
|
+
* URL của các ảnh cũ (ảnh cũ sẽ nháy vì `src` đổi).
|
|
4091
|
+
*/
|
|
4092
|
+
protected readonly imageUrls: _angular_core.WritableSignal<Record<string, string>>;
|
|
4093
|
+
private readonly objectUrls;
|
|
4094
|
+
/** Ảnh cho trình xem — chỉ tệp đã có URL. */
|
|
4095
|
+
protected readonly previewImages: _angular_core.Signal<OlPreviewImage[]>;
|
|
4096
|
+
protected readonly previewOpen: _angular_core.WritableSignal<boolean>;
|
|
4097
|
+
protected readonly previewIndex: _angular_core.WritableSignal<number>;
|
|
4098
|
+
constructor();
|
|
4099
|
+
/** Tạo URL cho ảnh mới, thu hồi URL của ảnh đã bị xoá. */
|
|
4100
|
+
private syncImageUrls;
|
|
4101
|
+
/** Mở trình xem tại ảnh của tệp này, và phát `(filePreview)`. */
|
|
4102
|
+
openPreview(file: OlUploadFile): void;
|
|
4103
|
+
openPicker(): void;
|
|
4104
|
+
protected onInputChange(event: Event): void;
|
|
4105
|
+
/** Nhận tệp từ hộp chọn hoặc kéo thả: kiểm, thêm vào `files`, phát sự kiện. */
|
|
4106
|
+
addFiles(incoming: File[]): void;
|
|
4107
|
+
/** Dán tệp khi tiêu điểm trong khung (nút, chip, dòng tệp). */
|
|
4108
|
+
protected onPaste(event: ClipboardEvent): void;
|
|
4109
|
+
/** Thả thêm tệp vào vùng chip đã có tệp. */
|
|
4110
|
+
protected onListDrop(event: DragEvent): void;
|
|
4111
|
+
protected removeFile(file: OlUploadFile): void;
|
|
4112
|
+
static ɵfac: _angular_core.ɵɵFactoryDeclaration<OlFileUpload, never>;
|
|
4113
|
+
static ɵcmp: _angular_core.ɵɵComponentDeclaration<OlFileUpload, "ol-file-upload", never, { "title": { "alias": "title"; "required": false; "isSignal": true; }; "required": { "alias": "required"; "required": false; "isSignal": true; }; "mode": { "alias": "mode"; "required": false; "isSignal": true; }; "accept": { "alias": "accept"; "required": false; "isSignal": true; }; "maxSize": { "alias": "maxSize"; "required": false; "isSignal": true; }; "maxFiles": { "alias": "maxFiles"; "required": false; "isSignal": true; }; "buttonLabel": { "alias": "buttonLabel"; "required": false; "isSignal": true; }; "previewable": { "alias": "previewable"; "required": false; "isSignal": true; }; "disabled": { "alias": "disabled"; "required": false; "isSignal": true; }; "pasteFromPage": { "alias": "pasteFromPage"; "required": false; "isSignal": true; }; "helperText": { "alias": "helperText"; "required": false; "isSignal": true; }; "files": { "alias": "files"; "required": false; "isSignal": true; }; }, { "files": "filesChange"; "filesAdded": "filesAdded"; "fileRemove": "fileRemove"; "filePreview": "filePreview"; "fileRetry": "fileRetry"; "rejected": "rejected"; }, never, ["[actions]"], true, never>;
|
|
3073
4114
|
}
|
|
3074
4115
|
|
|
3075
4116
|
declare class OlRange implements ControlValueAccessor {
|
|
@@ -3137,66 +4178,6 @@ declare class OlRange implements ControlValueAccessor {
|
|
|
3137
4178
|
static ɵcmp: _angular_core.ɵɵComponentDeclaration<OlRange, "ol-range", never, { "value": { "alias": "value"; "required": false; "isSignal": true; }; "minValue": { "alias": "minValue"; "required": false; "isSignal": true; }; "maxValue": { "alias": "maxValue"; "required": false; "isSignal": true; }; "dualRange": { "alias": "dualRange"; "required": false; "isSignal": true; }; "min": { "alias": "min"; "required": false; "isSignal": true; }; "max": { "alias": "max"; "required": false; "isSignal": true; }; "step": { "alias": "step"; "required": false; "isSignal": true; }; "label": { "alias": "label"; "required": false; "isSignal": true; }; "helperText": { "alias": "helperText"; "required": false; "isSignal": true; }; "showValue": { "alias": "showValue"; "required": false; "isSignal": true; }; "showTooltip": { "alias": "showTooltip"; "required": false; "isSignal": true; }; "showMinMaxLabels": { "alias": "showMinMaxLabels"; "required": false; "isSignal": true; }; "unit": { "alias": "unit"; "required": false; "isSignal": true; }; "disabled": { "alias": "disabled"; "required": false; "isSignal": true; }; "id": { "alias": "id"; "required": false; "isSignal": true; }; "ariaLabel": { "alias": "ariaLabel"; "required": false; "isSignal": true; }; }, { "value": "valueChange"; "minValue": "minValueChange"; "maxValue": "maxValueChange"; "disabled": "disabledChange"; }, never, ["[slot=prefix]", "[slot=suffix]"], true, never>;
|
|
3138
4179
|
}
|
|
3139
4180
|
|
|
3140
|
-
/**
|
|
3141
|
-
* Figma `ol-floating-label` #1149:50454 trục `Type` chỉ có
|
|
3142
|
-
* `Default | With background | Bordered` — ánh xạ sang `outlined`/`filled`.
|
|
3143
|
-
* `standard` không có trong thiết kế và template cũng **không có nhánh nào**
|
|
3144
|
-
* cho nó (grep ra 0 lượt), nên truyền vào là ra y hệt `outlined`. Đã xoá.
|
|
3145
|
-
*/
|
|
3146
|
-
type FloatingLabelVariant = 'outlined' | 'filled';
|
|
3147
|
-
/**
|
|
3148
|
-
* Figma `ol-floating-label` (#1149:50454) có `Size=[sm|base|lg|xl]`; code
|
|
3149
|
-
* trước đây thiếu `xl`. Đo trên Figma, `xl` giống hệt `lg` trừ chiều cao
|
|
3150
|
-
* (48 -> 52px) và padding dọc (12 -> 14px): cùng gap 8, cùng icon 20px,
|
|
3151
|
-
* cùng cỡ chữ 16px, cùng bo góc 12px.
|
|
3152
|
-
*/
|
|
3153
|
-
type FloatingLabelSize = 'sm' | 'base' | 'lg' | 'xl';
|
|
3154
|
-
type FloatingLabelState = 'default' | 'error' | 'success';
|
|
3155
|
-
declare class OlFloatingLabel implements ControlValueAccessor {
|
|
3156
|
-
readonly value: _angular_core.ModelSignal<string>;
|
|
3157
|
-
readonly label: _angular_core.InputSignal<string>;
|
|
3158
|
-
readonly type: _angular_core.InputSignal<string>;
|
|
3159
|
-
readonly variant: _angular_core.InputSignal<FloatingLabelVariant>;
|
|
3160
|
-
readonly size: _angular_core.InputSignal<FloatingLabelSize>;
|
|
3161
|
-
readonly state: _angular_core.InputSignal<FloatingLabelState>;
|
|
3162
|
-
/**
|
|
3163
|
-
* Khai bằng `model()` thay vì `input()` để Reactive Forms khoá được component:
|
|
3164
|
-
* `setDisabledState()` cần `set()` giá trị, mà `input()` chỉ đọc. Cách dùng từ
|
|
3165
|
-
* ngoài không đổi — `[disabled]="true"` và `disabled()` trong template vẫn như cũ.
|
|
3166
|
-
*/
|
|
3167
|
-
readonly disabled: _angular_core.ModelSignal<boolean>;
|
|
3168
|
-
readonly readonly: _angular_core.InputSignal<boolean>;
|
|
3169
|
-
readonly helperText: _angular_core.InputSignal<string>;
|
|
3170
|
-
readonly errorText: _angular_core.InputSignal<string>;
|
|
3171
|
-
readonly id: _angular_core.InputSignal<string>;
|
|
3172
|
-
readonly autocomplete: _angular_core.InputSignal<string>;
|
|
3173
|
-
readonly labelBg: _angular_core.InputSignal<string>;
|
|
3174
|
-
readonly prefixIcon: _angular_core.InputSignal<string>;
|
|
3175
|
-
readonly suffixIcon: _angular_core.InputSignal<string>;
|
|
3176
|
-
readonly prefixVariant: _angular_core.InputSignal<string>;
|
|
3177
|
-
readonly suffixVariant: _angular_core.InputSignal<string>;
|
|
3178
|
-
readonly hasPrefix: _angular_core.Signal<boolean>;
|
|
3179
|
-
readonly hasSuffix: _angular_core.Signal<boolean>;
|
|
3180
|
-
readonly isFocused: _angular_core.WritableSignal<boolean>;
|
|
3181
|
-
readonly isFloated: _angular_core.Signal<boolean>;
|
|
3182
|
-
private readonly generatedId;
|
|
3183
|
-
protected readonly inputId: _angular_core.Signal<string>;
|
|
3184
|
-
readonly helperId: _angular_core.Signal<string>;
|
|
3185
|
-
readonly describedBy: _angular_core.Signal<string | null>;
|
|
3186
|
-
readonly ariaInvalid: _angular_core.Signal<"true" | null>;
|
|
3187
|
-
private onChange;
|
|
3188
|
-
private onTouched;
|
|
3189
|
-
onFocus(): void;
|
|
3190
|
-
onBlur(): void;
|
|
3191
|
-
onModelChange(val: string): void;
|
|
3192
|
-
writeValue(val: string): void;
|
|
3193
|
-
registerOnChange(fn: any): void;
|
|
3194
|
-
registerOnTouched(fn: any): void;
|
|
3195
|
-
setDisabledState(isDisabled: boolean): void;
|
|
3196
|
-
static ɵfac: _angular_core.ɵɵFactoryDeclaration<OlFloatingLabel, never>;
|
|
3197
|
-
static ɵcmp: _angular_core.ɵɵComponentDeclaration<OlFloatingLabel, "ol-floating-label", never, { "value": { "alias": "value"; "required": false; "isSignal": true; }; "label": { "alias": "label"; "required": false; "isSignal": true; }; "type": { "alias": "type"; "required": false; "isSignal": true; }; "variant": { "alias": "variant"; "required": false; "isSignal": true; }; "size": { "alias": "size"; "required": false; "isSignal": true; }; "state": { "alias": "state"; "required": false; "isSignal": true; }; "disabled": { "alias": "disabled"; "required": false; "isSignal": true; }; "readonly": { "alias": "readonly"; "required": false; "isSignal": true; }; "helperText": { "alias": "helperText"; "required": false; "isSignal": true; }; "errorText": { "alias": "errorText"; "required": false; "isSignal": true; }; "id": { "alias": "id"; "required": false; "isSignal": true; }; "autocomplete": { "alias": "autocomplete"; "required": false; "isSignal": true; }; "labelBg": { "alias": "labelBg"; "required": false; "isSignal": true; }; "prefixIcon": { "alias": "prefixIcon"; "required": false; "isSignal": true; }; "suffixIcon": { "alias": "suffixIcon"; "required": false; "isSignal": true; }; "prefixVariant": { "alias": "prefixVariant"; "required": false; "isSignal": true; }; "suffixVariant": { "alias": "suffixVariant"; "required": false; "isSignal": true; }; }, { "value": "valueChange"; "disabled": "disabledChange"; }, never, never, true, never>;
|
|
3198
|
-
}
|
|
3199
|
-
|
|
3200
4181
|
/**
|
|
3201
4182
|
* Thang cỡ theo Figma: `sm | base | lg`. `'md'` là BÍ DANH của `'base'`,
|
|
3202
4183
|
* giữ cho mã cũ chạy tiếp và sẽ bỏ ở bản sau — dùng `'base'` cho mã mới.
|
|
@@ -3367,6 +4348,26 @@ declare class OlTagInput implements ControlValueAccessor {
|
|
|
3367
4348
|
readonly maxTags: _angular_core.InputSignal<number | undefined>;
|
|
3368
4349
|
readonly id: _angular_core.InputSignal<string>;
|
|
3369
4350
|
readonly size: _angular_core.InputSignal<TagInputSize>;
|
|
4351
|
+
/**
|
|
4352
|
+
* Nhãn nổi: `label` nằm TRONG khung ở dòng đầu, nổi lên khi focus, đang gõ
|
|
4353
|
+
* hoặc đã có thẻ. Khung giãn nhiều dòng — nhãn nổi không đẩy thẻ.
|
|
4354
|
+
*/
|
|
4355
|
+
readonly floatingLabel: _angular_core.InputSignal<boolean>;
|
|
4356
|
+
/**
|
|
4357
|
+
* Nhãn `top` (trên ô, mặc định) hay `left` (cùng hàng, bên trái). Nhãn nổi
|
|
4358
|
+
* (`floatingLabel`) thắng — bật nó thì bỏ qua input này.
|
|
4359
|
+
*/
|
|
4360
|
+
readonly labelPosition: _angular_core.InputSignal<LabelPosition>;
|
|
4361
|
+
/**
|
|
4362
|
+
* Độ rộng cột nhãn khi `labelPosition="left"` — độ dài CSS bất kỳ: `140px`,
|
|
4363
|
+
* `10rem`, `30%`. Bỏ trống = 8rem. Các ô trong cùng form đặt cùng một số thì
|
|
4364
|
+
* mép ô thẳng hàng.
|
|
4365
|
+
*/
|
|
4366
|
+
readonly labelWidth: _angular_core.InputSignal<string>;
|
|
4367
|
+
protected readonly labelLayout: _angular_core.Signal<string>;
|
|
4368
|
+
protected readonly labelBeside: _angular_core.Signal<boolean>;
|
|
4369
|
+
/** Kiểu nhãn nổi — Figma Bordered / With background / Default. */
|
|
4370
|
+
readonly floatingVariant: _angular_core.InputSignal<FloatingVariant>;
|
|
3370
4371
|
/**
|
|
3371
4372
|
* Gom chiều cao + padding vào MỘT chuỗi thay vì nhiều `[class.X]`: hai class
|
|
3372
4373
|
* cùng thuộc tính đều nằm trên thẻ thì trình duyệt chọn theo thứ tự luật CSS
|
|
@@ -3403,7 +4404,7 @@ declare class OlTagInput implements ControlValueAccessor {
|
|
|
3403
4404
|
*/
|
|
3404
4405
|
protected markTouched(): void;
|
|
3405
4406
|
static ɵfac: _angular_core.ɵɵFactoryDeclaration<OlTagInput, never>;
|
|
3406
|
-
static ɵcmp: _angular_core.ɵɵComponentDeclaration<OlTagInput, "ol-tag-input", never, { "tags": { "alias": "tags"; "required": false; "isSignal": true; }; "label": { "alias": "label"; "required": false; "isSignal": true; }; "placeholder": { "alias": "placeholder"; "required": false; "isSignal": true; }; "disabled": { "alias": "disabled"; "required": false; "isSignal": true; }; "helperText": { "alias": "helperText"; "required": false; "isSignal": true; }; "maxTags": { "alias": "maxTags"; "required": false; "isSignal": true; }; "id": { "alias": "id"; "required": false; "isSignal": true; }; "size": { "alias": "size"; "required": false; "isSignal": true; }; }, { "tags": "tagsChange"; "disabled": "disabledChange"; }, never, never, true, never>;
|
|
4407
|
+
static ɵcmp: _angular_core.ɵɵComponentDeclaration<OlTagInput, "ol-tag-input", never, { "tags": { "alias": "tags"; "required": false; "isSignal": true; }; "label": { "alias": "label"; "required": false; "isSignal": true; }; "placeholder": { "alias": "placeholder"; "required": false; "isSignal": true; }; "disabled": { "alias": "disabled"; "required": false; "isSignal": true; }; "helperText": { "alias": "helperText"; "required": false; "isSignal": true; }; "maxTags": { "alias": "maxTags"; "required": false; "isSignal": true; }; "id": { "alias": "id"; "required": false; "isSignal": true; }; "size": { "alias": "size"; "required": false; "isSignal": true; }; "floatingLabel": { "alias": "floatingLabel"; "required": false; "isSignal": true; }; "labelPosition": { "alias": "labelPosition"; "required": false; "isSignal": true; }; "labelWidth": { "alias": "labelWidth"; "required": false; "isSignal": true; }; "floatingVariant": { "alias": "floatingVariant"; "required": false; "isSignal": true; }; }, { "tags": "tagsChange"; "disabled": "disabledChange"; }, never, never, true, never>;
|
|
3407
4408
|
}
|
|
3408
4409
|
|
|
3409
4410
|
declare class OlRichTextEditor implements ControlValueAccessor {
|
|
@@ -3476,6 +4477,26 @@ declare class OlTimepicker implements ControlValueAccessor {
|
|
|
3476
4477
|
* `aria-labelledby` đã lo — không cần truyền cái này.
|
|
3477
4478
|
*/
|
|
3478
4479
|
readonly ariaLabel: _angular_core.InputSignal<string>;
|
|
4480
|
+
/**
|
|
4481
|
+
* Nhãn nổi: `label` nằm TRONG khung (sau icon đồng hồ), nổi lên khi focus,
|
|
4482
|
+
* mở bảng chọn hoặc đã có giờ. Có addon thì nhãn nằm trong ô, không trùm addon.
|
|
4483
|
+
*/
|
|
4484
|
+
readonly floatingLabel: _angular_core.InputSignal<boolean>;
|
|
4485
|
+
/**
|
|
4486
|
+
* Nhãn `top` (trên ô, mặc định) hay `left` (cùng hàng, bên trái). Nhãn nổi
|
|
4487
|
+
* (`floatingLabel`) thắng — bật nó thì bỏ qua input này.
|
|
4488
|
+
*/
|
|
4489
|
+
readonly labelPosition: _angular_core.InputSignal<LabelPosition>;
|
|
4490
|
+
/**
|
|
4491
|
+
* Độ rộng cột nhãn khi `labelPosition="left"` — độ dài CSS bất kỳ: `140px`,
|
|
4492
|
+
* `10rem`, `30%`. Bỏ trống = 8rem. Các ô trong cùng form đặt cùng một số thì
|
|
4493
|
+
* mép ô thẳng hàng.
|
|
4494
|
+
*/
|
|
4495
|
+
readonly labelWidth: _angular_core.InputSignal<string>;
|
|
4496
|
+
protected readonly labelLayout: _angular_core.Signal<string>;
|
|
4497
|
+
protected readonly labelBeside: _angular_core.Signal<boolean>;
|
|
4498
|
+
/** Kiểu nhãn nổi — Figma Bordered / With background / Default. */
|
|
4499
|
+
readonly floatingVariant: _angular_core.InputSignal<FloatingVariant>;
|
|
3479
4500
|
readonly placeholder: _angular_core.InputSignal<string>;
|
|
3480
4501
|
readonly format: _angular_core.InputSignal<TimepickerFormat>;
|
|
3481
4502
|
readonly size: _angular_core.InputSignal<TimepickerSize>;
|
|
@@ -3587,7 +4608,7 @@ declare class OlTimepicker implements ControlValueAccessor {
|
|
|
3587
4608
|
registerOnTouched(fn: any): void;
|
|
3588
4609
|
setDisabledState(isDisabled: boolean): void;
|
|
3589
4610
|
static ɵfac: _angular_core.ɵɵFactoryDeclaration<OlTimepicker, never>;
|
|
3590
|
-
static ɵcmp: _angular_core.ɵɵComponentDeclaration<OlTimepicker, "ol-timepicker", never, { "value": { "alias": "value"; "required": false; "isSignal": true; }; "label": { "alias": "label"; "required": false; "isSignal": true; }; "ariaLabel": { "alias": "ariaLabel"; "required": false; "isSignal": true; }; "placeholder": { "alias": "placeholder"; "required": false; "isSignal": true; }; "format": { "alias": "format"; "required": false; "isSignal": true; }; "size": { "alias": "size"; "required": false; "isSignal": true; }; "state": { "alias": "state"; "required": false; "isSignal": true; }; "disabled": { "alias": "disabled"; "required": false; "isSignal": true; }; "readonly": { "alias": "readonly"; "required": false; "isSignal": true; }; "required": { "alias": "required"; "required": false; "isSignal": true; }; "showAsterisk": { "alias": "showAsterisk"; "required": false; "isSignal": true; }; "helperText": { "alias": "helperText"; "required": false; "isSignal": true; }; "errorText": { "alias": "errorText"; "required": false; "isSignal": true; }; "id": { "alias": "id"; "required": false; "isSignal": true; }; "minuteStep": { "alias": "minuteStep"; "required": false; "isSignal": true; }; "appendTo": { "alias": "appendTo"; "required": false; "isSignal": true; }; "showPresets": { "alias": "showPresets"; "required": false; "isSignal": true; }; "addonType": { "alias": "addonType"; "required": false; "isSignal": true; }; "addonText": { "alias": "addonText"; "required": false; "isSignal": true; }; "addonIcon": { "alias": "addonIcon"; "required": false; "isSignal": true; }; }, { "value": "valueChange"; "disabled": "disabledChange"; "timeChange": "timeChange"; "timestampChange": "timestampChange"; "isoChange": "isoChange"; "timeObjectChange": "timeObjectChange"; }, never, never, true, never>;
|
|
4611
|
+
static ɵcmp: _angular_core.ɵɵComponentDeclaration<OlTimepicker, "ol-timepicker", never, { "value": { "alias": "value"; "required": false; "isSignal": true; }; "label": { "alias": "label"; "required": false; "isSignal": true; }; "ariaLabel": { "alias": "ariaLabel"; "required": false; "isSignal": true; }; "floatingLabel": { "alias": "floatingLabel"; "required": false; "isSignal": true; }; "labelPosition": { "alias": "labelPosition"; "required": false; "isSignal": true; }; "labelWidth": { "alias": "labelWidth"; "required": false; "isSignal": true; }; "floatingVariant": { "alias": "floatingVariant"; "required": false; "isSignal": true; }; "placeholder": { "alias": "placeholder"; "required": false; "isSignal": true; }; "format": { "alias": "format"; "required": false; "isSignal": true; }; "size": { "alias": "size"; "required": false; "isSignal": true; }; "state": { "alias": "state"; "required": false; "isSignal": true; }; "disabled": { "alias": "disabled"; "required": false; "isSignal": true; }; "readonly": { "alias": "readonly"; "required": false; "isSignal": true; }; "required": { "alias": "required"; "required": false; "isSignal": true; }; "showAsterisk": { "alias": "showAsterisk"; "required": false; "isSignal": true; }; "helperText": { "alias": "helperText"; "required": false; "isSignal": true; }; "errorText": { "alias": "errorText"; "required": false; "isSignal": true; }; "id": { "alias": "id"; "required": false; "isSignal": true; }; "minuteStep": { "alias": "minuteStep"; "required": false; "isSignal": true; }; "appendTo": { "alias": "appendTo"; "required": false; "isSignal": true; }; "showPresets": { "alias": "showPresets"; "required": false; "isSignal": true; }; "addonType": { "alias": "addonType"; "required": false; "isSignal": true; }; "addonText": { "alias": "addonText"; "required": false; "isSignal": true; }; "addonIcon": { "alias": "addonIcon"; "required": false; "isSignal": true; }; }, { "value": "valueChange"; "disabled": "disabledChange"; "timeChange": "timeChange"; "timestampChange": "timestampChange"; "isoChange": "isoChange"; "timeObjectChange": "timeObjectChange"; }, never, never, true, never>;
|
|
3591
4612
|
}
|
|
3592
4613
|
|
|
3593
4614
|
/**
|
|
@@ -3611,6 +4632,28 @@ declare class OlAutocomplete implements ControlValueAccessor {
|
|
|
3611
4632
|
readonly value: _angular_core.ModelSignal<any>;
|
|
3612
4633
|
readonly options: _angular_core.InputSignal<any[]>;
|
|
3613
4634
|
readonly label: _angular_core.InputSignal<string>;
|
|
4635
|
+
/**
|
|
4636
|
+
* Nhãn nổi: `label` nằm TRONG khung (sau icon kính lúp), nổi lên khi focus,
|
|
4637
|
+
* đang gõ, mở danh sách hoặc đã chọn. Đa chọn: nổi lên không đẩy thẻ.
|
|
4638
|
+
*/
|
|
4639
|
+
readonly floatingLabel: _angular_core.InputSignal<boolean>;
|
|
4640
|
+
/**
|
|
4641
|
+
* Nhãn `top` (trên ô, mặc định) hay `left` (cùng hàng, bên trái). Nhãn nổi
|
|
4642
|
+
* (`floatingLabel`) thắng — bật nó thì bỏ qua input này.
|
|
4643
|
+
*/
|
|
4644
|
+
readonly labelPosition: _angular_core.InputSignal<LabelPosition>;
|
|
4645
|
+
/**
|
|
4646
|
+
* Độ rộng cột nhãn khi `labelPosition="left"` — độ dài CSS bất kỳ: `140px`,
|
|
4647
|
+
* `10rem`, `30%`. Bỏ trống = 8rem. Các ô trong cùng form đặt cùng một số thì
|
|
4648
|
+
* mép ô thẳng hàng.
|
|
4649
|
+
*/
|
|
4650
|
+
readonly labelWidth: _angular_core.InputSignal<string>;
|
|
4651
|
+
protected readonly labelLayout: _angular_core.Signal<string>;
|
|
4652
|
+
protected readonly labelBeside: _angular_core.Signal<boolean>;
|
|
4653
|
+
/** Kiểu nhãn nổi — Figma Bordered / With background / Default. */
|
|
4654
|
+
readonly floatingVariant: _angular_core.InputSignal<FloatingVariant>;
|
|
4655
|
+
/** Có giá trị để nhãn nổi: đã chọn (một hay nhiều) hoặc đang có chữ gõ. */
|
|
4656
|
+
protected readonly hasFloatValue: _angular_core.Signal<boolean>;
|
|
3614
4657
|
readonly placeholder: _angular_core.InputSignal<string>;
|
|
3615
4658
|
readonly labelKey: _angular_core.InputSignal<string>;
|
|
3616
4659
|
readonly valueKey: _angular_core.InputSignal<string>;
|
|
@@ -3628,7 +4671,7 @@ declare class OlAutocomplete implements ControlValueAccessor {
|
|
|
3628
4671
|
protected readonly resolvedSize: _angular_core.Signal<FieldSize>;
|
|
3629
4672
|
/**
|
|
3630
4673
|
* Đệm ngang theo BẢNG CHUẨN họ form. Chỉ dùng khi KHÔNG `multiple` —
|
|
3631
|
-
* chế độ nhiều thẻ
|
|
4674
|
+
* chế độ nhiều thẻ dùng `boxPaddingClass`.
|
|
3632
4675
|
*
|
|
3633
4676
|
* Ba lỗi cũ gộp làm một chỗ này (đo /autocomplete 2026-09-24):
|
|
3634
4677
|
* sm `[class.px-2.5]` -> Angular CẮT ở dấu chấm, render `px-2` = 8px
|
|
@@ -3637,6 +4680,26 @@ declare class OlAutocomplete implements ControlValueAccessor {
|
|
|
3637
4680
|
* xl có `px-4` nhưng nằm ở `[class.px-4]` rời, dễ lệch khỏi ba cỡ kia.
|
|
3638
4681
|
*/
|
|
3639
4682
|
protected readonly fieldPaddingClass: _angular_core.Signal<string>;
|
|
4683
|
+
/**
|
|
4684
|
+
* Đệm khung. Chọn nhiều: icon kính lúp vẫn là phần tử đầu nên lề đầu theo
|
|
4685
|
+
* cỡ như ô đơn (bản cũ `ps-1.5` để icon cách mép 6px, ô đơn 12px — hai ô
|
|
4686
|
+
* cạnh nhau lệch nhau rõ). Lề cuối chừa chỗ cụm nút absolute: lề cỡ + icon
|
|
4687
|
+
* 16px + `FIELD_ICON_GAP` 8px.
|
|
4688
|
+
*/
|
|
4689
|
+
protected readonly boxPaddingClass: _angular_core.Signal<string>;
|
|
4690
|
+
/**
|
|
4691
|
+
* Cụm nút cuối (xoá / chevron / spinner). Rộng icon 16px + `ps-0.5` để chữ
|
|
4692
|
+
* ↔ icon đúng 8px (`gap-1.5` của khung + 2px) — bản cũ `w-7` ra 18px.
|
|
4693
|
+
* `justify-end`: spinner 12px vẫn neo mép phải như icon.
|
|
4694
|
+
*/
|
|
4695
|
+
protected readonly controlClass: _angular_core.Signal<string>;
|
|
4696
|
+
/**
|
|
4697
|
+
* Đã có thẻ (chọn nhiều): khi KHÔNG gõ, ô gõ co về 0 (`min-w-0`, vẫn
|
|
4698
|
+
* `flex-1`) nên luôn ở cùng dòng chip cuối — không đẻ ra một dòng trống.
|
|
4699
|
+
* Focus để gõ thì mới cần chỗ (`focus:min-w-16`), lúc đó xuống dòng là đúng.
|
|
4700
|
+
* Đo 2026-09-29: dòng chip cuối còn 43px, `min-w-12` (48px) vẫn rớt.
|
|
4701
|
+
*/
|
|
4702
|
+
protected readonly hasChips: _angular_core.Signal<boolean>;
|
|
3640
4703
|
/**
|
|
3641
4704
|
* Cỡ chữ theo BẢNG CHUẨN. Trước đây `[class.text-base]` chỉ khai cho `lg`,
|
|
3642
4705
|
* `xl` không có nhánh nào nên rơi về 16px MẶC ĐỊNH của trình duyệt — trùng
|
|
@@ -3816,7 +4879,7 @@ declare class OlAutocomplete implements ControlValueAccessor {
|
|
|
3816
4879
|
registerOnTouched(fn: any): void;
|
|
3817
4880
|
setDisabledState(isDisabled: boolean): void;
|
|
3818
4881
|
static ɵfac: _angular_core.ɵɵFactoryDeclaration<OlAutocomplete, never>;
|
|
3819
|
-
static ɵcmp: _angular_core.ɵɵComponentDeclaration<OlAutocomplete, "ol-autocomplete", never, { "value": { "alias": "value"; "required": false; "isSignal": true; }; "options": { "alias": "options"; "required": false; "isSignal": true; }; "label": { "alias": "label"; "required": false; "isSignal": true; }; "placeholder": { "alias": "placeholder"; "required": false; "isSignal": true; }; "labelKey": { "alias": "labelKey"; "required": false; "isSignal": true; }; "valueKey": { "alias": "valueKey"; "required": false; "isSignal": true; }; "multiple": { "alias": "multiple"; "required": false; "isSignal": true; }; "disabled": { "alias": "disabled"; "required": false; "isSignal": true; }; "readonly": { "alias": "readonly"; "required": false; "isSignal": true; }; "loading": { "alias": "loading"; "required": false; "isSignal": true; }; "size": { "alias": "size"; "required": false; "isSignal": true; }; "state": { "alias": "state"; "required": false; "isSignal": true; }; "required": { "alias": "required"; "required": false; "isSignal": true; }; "showAsterisk": { "alias": "showAsterisk"; "required": false; "isSignal": true; }; "helperText": { "alias": "helperText"; "required": false; "isSignal": true; }; "errorText": { "alias": "errorText"; "required": false; "isSignal": true; }; "id": { "alias": "id"; "required": false; "isSignal": true; }; "allowCreate": { "alias": "allowCreate"; "required": false; "isSignal": true; }; "emptyText": { "alias": "emptyText"; "required": false; "isSignal": true; }; "appendTo": { "alias": "appendTo"; "required": false; "isSignal": true; }; "menuClass": { "alias": "menuClass"; "required": false; "isSignal": true; }; "matchTriggerWidth": { "alias": "matchTriggerWidth"; "required": false; "isSignal": true; }; "groupBy": { "alias": "groupBy"; "required": false; "isSignal": true; }; "remoteSearch": { "alias": "remoteSearch"; "required": false; "isSignal": true; }; "minTermLength": { "alias": "minTermLength"; "required": false; "isSignal": true; }; "debounceMs": { "alias": "debounceMs"; "required": false; "isSignal": true; }; "typeToSearchText": { "alias": "typeToSearchText"; "required": false; "isSignal": true; }; }, { "value": "valueChange"; "disabled": "disabledChange"; "createOption": "createOption"; "search": "search"; "opened": "opened"; "closed": "closed"; "cleared": "cleared"; "added": "added"; "removed": "removed"; "selectionChange": "selectionChange"; }, ["optionTemplate"], never, true, never>;
|
|
4882
|
+
static ɵcmp: _angular_core.ɵɵComponentDeclaration<OlAutocomplete, "ol-autocomplete", never, { "value": { "alias": "value"; "required": false; "isSignal": true; }; "options": { "alias": "options"; "required": false; "isSignal": true; }; "label": { "alias": "label"; "required": false; "isSignal": true; }; "floatingLabel": { "alias": "floatingLabel"; "required": false; "isSignal": true; }; "labelPosition": { "alias": "labelPosition"; "required": false; "isSignal": true; }; "labelWidth": { "alias": "labelWidth"; "required": false; "isSignal": true; }; "floatingVariant": { "alias": "floatingVariant"; "required": false; "isSignal": true; }; "placeholder": { "alias": "placeholder"; "required": false; "isSignal": true; }; "labelKey": { "alias": "labelKey"; "required": false; "isSignal": true; }; "valueKey": { "alias": "valueKey"; "required": false; "isSignal": true; }; "multiple": { "alias": "multiple"; "required": false; "isSignal": true; }; "disabled": { "alias": "disabled"; "required": false; "isSignal": true; }; "readonly": { "alias": "readonly"; "required": false; "isSignal": true; }; "loading": { "alias": "loading"; "required": false; "isSignal": true; }; "size": { "alias": "size"; "required": false; "isSignal": true; }; "state": { "alias": "state"; "required": false; "isSignal": true; }; "required": { "alias": "required"; "required": false; "isSignal": true; }; "showAsterisk": { "alias": "showAsterisk"; "required": false; "isSignal": true; }; "helperText": { "alias": "helperText"; "required": false; "isSignal": true; }; "errorText": { "alias": "errorText"; "required": false; "isSignal": true; }; "id": { "alias": "id"; "required": false; "isSignal": true; }; "allowCreate": { "alias": "allowCreate"; "required": false; "isSignal": true; }; "emptyText": { "alias": "emptyText"; "required": false; "isSignal": true; }; "appendTo": { "alias": "appendTo"; "required": false; "isSignal": true; }; "menuClass": { "alias": "menuClass"; "required": false; "isSignal": true; }; "matchTriggerWidth": { "alias": "matchTriggerWidth"; "required": false; "isSignal": true; }; "groupBy": { "alias": "groupBy"; "required": false; "isSignal": true; }; "remoteSearch": { "alias": "remoteSearch"; "required": false; "isSignal": true; }; "minTermLength": { "alias": "minTermLength"; "required": false; "isSignal": true; }; "debounceMs": { "alias": "debounceMs"; "required": false; "isSignal": true; }; "typeToSearchText": { "alias": "typeToSearchText"; "required": false; "isSignal": true; }; }, { "value": "valueChange"; "disabled": "disabledChange"; "createOption": "createOption"; "search": "search"; "opened": "opened"; "closed": "closed"; "cleared": "cleared"; "added": "added"; "removed": "removed"; "selectionChange": "selectionChange"; }, ["optionTemplate"], never, true, never>;
|
|
3820
4883
|
}
|
|
3821
4884
|
|
|
3822
4885
|
declare class OlKbd {
|
|
@@ -4082,6 +5145,30 @@ declare class OlModalFooter {
|
|
|
4082
5145
|
static ɵcmp: _angular_core.ɵɵComponentDeclaration<OlModalFooter, "ol-modal-footer", never, { "layout": { "alias": "layout"; "required": false; "isSignal": true; }; }, {}, never, ["*"], true, never>;
|
|
4083
5146
|
}
|
|
4084
5147
|
|
|
5148
|
+
/**
|
|
5149
|
+
* Mốc gập menu vào ☰, theo bề rộng THANH. `xl` (78rem ≈ 1248px) là mặc định cũ.
|
|
5150
|
+
* `md` (48rem = 768px) / `lg` (64rem = 1024px) cho thanh muốn giữ menu lâu hơn —
|
|
5151
|
+
* thường kèm `compactItems`, vì menu đầy đủ chữ hiếm khi vừa 768px.
|
|
5152
|
+
*/
|
|
5153
|
+
type NavbarCollapseAt = 'md' | 'lg' | 'xl';
|
|
5154
|
+
/**
|
|
5155
|
+
* Ba nấc hiển thị khi `compactItems` bật — thanh ĐO chỗ trống thật và chọn nấc
|
|
5156
|
+
* đầy đủ nhất còn vừa, ghi vào `data-density` trên gốc `<nav>`:
|
|
5157
|
+
*
|
|
5158
|
+
* - `full` — đủ hết.
|
|
5159
|
+
* - `medium` — vẫn ĐỦ CHỮ và icon menu; bỏ phần PHỤ của nơi gọi.
|
|
5160
|
+
* - `text` — đủ chữ, bỏ icon đầu mục (−24px mỗi mục).
|
|
5161
|
+
* - `compact` — mục có icon chỉ còn icon (chữ `sr-only`, có `title`).
|
|
5162
|
+
*
|
|
5163
|
+
* Từ `medium` trở xuống gốc có thêm `data-condensed`: nơi gọi ẩn phần phụ
|
|
5164
|
+
* (dòng phụ dưới logo, nhãn "Năm học:"…) bằng MỘT class
|
|
5165
|
+
* `group-data-[condensed]/navbar:hidden`, không phải liệt kê từng nấc.
|
|
5166
|
+
*
|
|
5167
|
+
* Bản trước đổi sang icon ở mốc CỨNG 78rem: thanh 1180px chỉ thiếu 3px là vừa
|
|
5168
|
+
* đủ chữ mà vẫn thành icon, để trống một khoảng lớn giữa menu và nút (báo
|
|
5169
|
+
* 2026-09-28 kèm ảnh).
|
|
5170
|
+
*/
|
|
5171
|
+
type NavbarDensity = 'full' | 'medium' | 'text' | 'compact';
|
|
4085
5172
|
declare class OlNavbar {
|
|
4086
5173
|
readonly brandLogo: _angular_core.InputSignal<string>;
|
|
4087
5174
|
readonly brandName: _angular_core.InputSignal<string>;
|
|
@@ -4090,19 +5177,71 @@ declare class OlNavbar {
|
|
|
4090
5177
|
readonly fluid: _angular_core.InputSignal<boolean>;
|
|
4091
5178
|
readonly showSearch: _angular_core.InputSignal<boolean>;
|
|
4092
5179
|
readonly searchPlaceholder: _angular_core.InputSignal<string>;
|
|
5180
|
+
/** Thanh hẹp hơn mốc này thì mục menu gập vào ☰. Xem `NavbarCollapseAt`. */
|
|
5181
|
+
readonly collapseAt: _angular_core.InputSignal<NavbarCollapseAt>;
|
|
5182
|
+
/**
|
|
5183
|
+
* Tự co theo chỗ trống thật (`full` → `medium` → `compact`, xem
|
|
5184
|
+
* `NavbarDensity`) thay vì gập menu. Thường đi kèm `collapseAt="md"`/`"lg"`.
|
|
5185
|
+
*/
|
|
5186
|
+
readonly compactItems: _angular_core.InputSignal<boolean>;
|
|
4093
5187
|
readonly isCollapsed: _angular_core.ModelSignal<boolean>;
|
|
4094
5188
|
readonly onSearch: _angular_core.OutputEmitterRef<string>;
|
|
4095
5189
|
readonly onToggleMobileMenu: _angular_core.OutputEmitterRef<boolean>;
|
|
4096
5190
|
searchQuery: string;
|
|
4097
5191
|
private readonly elementRef;
|
|
5192
|
+
private readonly mobilePanel;
|
|
5193
|
+
private readonly navWrap;
|
|
5194
|
+
private readonly destroyRef;
|
|
5195
|
+
/** Nơi gọi có khai `slot="mobile-links"` (hoặc `slot="mobile"`) riêng. */
|
|
5196
|
+
readonly hasMobileLinks: _angular_core.WritableSignal<boolean>;
|
|
5197
|
+
/** Panel ☰ có gì để hiện — không thì đừng vẽ một dải trống có padding. */
|
|
5198
|
+
readonly hasPanelContent: _angular_core.WritableSignal<boolean>;
|
|
5199
|
+
constructor();
|
|
5200
|
+
/** Chiều cao khối mục xếp dọc (0 khi không xếp dọc) → `--ol-nav-stack-h`. */
|
|
5201
|
+
private observeStackHeight;
|
|
5202
|
+
private observeDensity;
|
|
5203
|
+
/**
|
|
5204
|
+
* Thử từ nấc đầy đủ nhất xuống, dừng ở nấc đầu tiên vừa hàng. Đặt thuộc tính
|
|
5205
|
+
* rồi đọc kích thước NGAY (ép trình duyệt tính lại) nên không nháy khung nào
|
|
5206
|
+
* — trạng thái cuối được gán trước khi vẽ.
|
|
5207
|
+
*
|
|
5208
|
+
* Đo bằng `scrollWidth`: logo có `min-w-0 truncate`, bị ép co thì
|
|
5209
|
+
* `offsetWidth` nhỏ đi và phép đo báo "vừa" sai.
|
|
5210
|
+
*/
|
|
5211
|
+
updateDensity(): void;
|
|
5212
|
+
private isStacked;
|
|
5213
|
+
/**
|
|
5214
|
+
* Đo lại mỗi lần mở ☰, không chỉ lúc đầu: nội dung chiếu vào có thể nằm
|
|
5215
|
+
* trong @if của nơi gọi và xuất hiện muộn.
|
|
5216
|
+
*/
|
|
5217
|
+
private detectMobileSlots;
|
|
5218
|
+
/**
|
|
5219
|
+
* Khối mục menu. Khung ≥ 78rem: nằm ngang cạnh logo.
|
|
5220
|
+
*
|
|
5221
|
+
* Khung hẹp mà ☰ đang mở và KHÔNG có menu di động riêng: xuống dòng
|
|
5222
|
+
* (`col-span-full row-start-2`) và xếp dọc — chính các mục desktop thành menu
|
|
5223
|
+
* di động. Bản trước chỉ ẩn chúng, nên 5/7 thanh trên /navbar và /blocks bấm
|
|
5224
|
+
* ☰ ra bảng trống (đo iPhone 13 giả lập, 2026-09-28).
|
|
5225
|
+
*/
|
|
5226
|
+
protected readonly bp: _angular_core.Signal<{
|
|
5227
|
+
row: string;
|
|
5228
|
+
wide: string;
|
|
5229
|
+
stackReset: string;
|
|
5230
|
+
hide: string;
|
|
5231
|
+
}>;
|
|
5232
|
+
/** Hàng trên: lưới ở khung hẹp (logo | nút), flex từ mốc gập trở lên. */
|
|
5233
|
+
readonly rowClasses: _angular_core.Signal<string>;
|
|
5234
|
+
readonly toggleClasses: _angular_core.Signal<string>;
|
|
5235
|
+
readonly navWrapClasses: _angular_core.Signal<string>;
|
|
5236
|
+
readonly mobilePanelClasses: _angular_core.Signal<string>;
|
|
4098
5237
|
readonly navbarClasses: _angular_core.Signal<string>;
|
|
4099
|
-
readonly containerClasses: _angular_core.Signal<"w-full px-4
|
|
5238
|
+
readonly containerClasses: _angular_core.Signal<"w-full px-4 @[40rem]:px-6" | "max-w-7xl mx-auto px-4 @[40rem]:px-6 @5xl:px-8">;
|
|
4100
5239
|
toggleMobileMenu(): void;
|
|
4101
5240
|
handleSearchSubmit(): void;
|
|
4102
5241
|
handleSearchInput(event: Event): void;
|
|
4103
5242
|
handleGlobalKeydown(event: KeyboardEvent): void;
|
|
4104
5243
|
static ɵfac: _angular_core.ɵɵFactoryDeclaration<OlNavbar, never>;
|
|
4105
|
-
static ɵcmp: _angular_core.ɵɵComponentDeclaration<OlNavbar, "ol-navbar", never, { "brandLogo": { "alias": "brandLogo"; "required": false; "isSignal": true; }; "brandName": { "alias": "brandName"; "required": false; "isSignal": true; }; "sticky": { "alias": "sticky"; "required": false; "isSignal": true; }; "bordered": { "alias": "bordered"; "required": false; "isSignal": true; }; "fluid": { "alias": "fluid"; "required": false; "isSignal": true; }; "showSearch": { "alias": "showSearch"; "required": false; "isSignal": true; }; "searchPlaceholder": { "alias": "searchPlaceholder"; "required": false; "isSignal": true; }; "isCollapsed": { "alias": "isCollapsed"; "required": false; "isSignal": true; }; }, { "isCollapsed": "isCollapsedChange"; "onSearch": "onSearch"; "onToggleMobileMenu": "onToggleMobileMenu"; }, never, ["[slot=brand], [brand]", "[slot=navigation], [navigation], ol-navbar-item, ol-nav-dropdown", "[slot=actions], [actions]", "[slot=mobile-user]", "[slot=mobile], [slot=mobile-links]", "[slot=mobile-actions]", "[slot=mobile-footer]"], true, never>;
|
|
5244
|
+
static ɵcmp: _angular_core.ɵɵComponentDeclaration<OlNavbar, "ol-navbar", never, { "brandLogo": { "alias": "brandLogo"; "required": false; "isSignal": true; }; "brandName": { "alias": "brandName"; "required": false; "isSignal": true; }; "sticky": { "alias": "sticky"; "required": false; "isSignal": true; }; "bordered": { "alias": "bordered"; "required": false; "isSignal": true; }; "fluid": { "alias": "fluid"; "required": false; "isSignal": true; }; "showSearch": { "alias": "showSearch"; "required": false; "isSignal": true; }; "searchPlaceholder": { "alias": "searchPlaceholder"; "required": false; "isSignal": true; }; "collapseAt": { "alias": "collapseAt"; "required": false; "isSignal": true; }; "compactItems": { "alias": "compactItems"; "required": false; "isSignal": true; }; "isCollapsed": { "alias": "isCollapsed"; "required": false; "isSignal": true; }; }, { "isCollapsed": "isCollapsedChange"; "onSearch": "onSearch"; "onToggleMobileMenu": "onToggleMobileMenu"; }, never, ["[slot=brand], [brand]", "[slot=navigation], [navigation], ol-navbar-item, ol-nav-dropdown", "[slot=actions], [actions]", "[slot=mobile-user]", "[slot=mobile], [slot=mobile-links]", "[slot=mobile-actions]", "[slot=mobile-footer]"], true, never>;
|
|
4106
5245
|
}
|
|
4107
5246
|
|
|
4108
5247
|
declare class OlNavbarItem {
|
|
@@ -4125,7 +5264,40 @@ declare class OlNavDropdown {
|
|
|
4125
5264
|
readonly label: _angular_core.InputSignal<string>;
|
|
4126
5265
|
readonly icon: _angular_core.InputSignal<string | null>;
|
|
4127
5266
|
readonly alignRight: _angular_core.InputSignal<boolean>;
|
|
5267
|
+
/**
|
|
5268
|
+
* Đang ở một trang CON của menu này (ví dụ "Lớp học" khi đang xem 10A1).
|
|
5269
|
+
* Cùng hình với `ol-navbar-item` active — nền brand nhạt, chữ brand đậm —
|
|
5270
|
+
* để thanh điều hướng luôn chỉ ra người dùng đang ở phân hệ nào.
|
|
5271
|
+
*/
|
|
5272
|
+
readonly active: _angular_core.InputSignal<boolean>;
|
|
5273
|
+
protected readonly triggerClasses: _angular_core.Signal<string>;
|
|
5274
|
+
/**
|
|
5275
|
+
* Số cột của panel. `1` (mặc định) là menu thường; từ `2` là mega-menu.
|
|
5276
|
+
*
|
|
5277
|
+
* Mega-menu dùng cho menu có nhiều nhóm mục — thay vì một cột dài phải cuộn,
|
|
5278
|
+
* chia thành cột đứng cạnh nhau và người dùng quét mắt một lượt là thấy hết.
|
|
5279
|
+
*
|
|
5280
|
+
* Dưới `md` LUÔN về một cột bất kể giá trị: hai cột trên màn 390px là mỗi
|
|
5281
|
+
* cột 150px, chữ vỡ dòng giữa từ. Ngưỡng theo breakpoint chứ không theo bề
|
|
5282
|
+
* ngang panel vì panel treo tự do, không có container để đo.
|
|
5283
|
+
*/
|
|
5284
|
+
readonly columns: _angular_core.InputSignal<1 | 2 | 3 | 4>;
|
|
5285
|
+
/**
|
|
5286
|
+
* Panel rộng bằng cả navbar thay vì bám mép nút.
|
|
5287
|
+
*
|
|
5288
|
+
* Mega-menu nhiều cột mà vẫn bám mép nút thì nửa panel tràn ra ngoài màn
|
|
5289
|
+
* hình khi nút nằm bên phải. Trải hết chiều ngang thì luôn nằm trong khung.
|
|
5290
|
+
*/
|
|
5291
|
+
readonly fullWidth: _angular_core.InputSignal<boolean>;
|
|
4128
5292
|
readonly isOpen: _angular_core.WritableSignal<boolean>;
|
|
5293
|
+
/**
|
|
5294
|
+
* Class của panel.
|
|
5295
|
+
*
|
|
5296
|
+
* Gom vào MỘT chuỗi thay vì nhiều `[class.x]` rời: hai class cùng thuộc tính
|
|
5297
|
+
* thì trình duyệt chọn theo thứ tự luật trong file CSS chứ không theo thứ tự
|
|
5298
|
+
* viết, kết quả đổi theo bản build.
|
|
5299
|
+
*/
|
|
5300
|
+
protected readonly panelClasses: _angular_core.Signal<string>;
|
|
4129
5301
|
private readonly elementRef;
|
|
4130
5302
|
private readonly overlayContainer;
|
|
4131
5303
|
constructor();
|
|
@@ -4133,9 +5305,120 @@ declare class OlNavDropdown {
|
|
|
4133
5305
|
close(): void;
|
|
4134
5306
|
handleClickOutside(event: MouseEvent): void;
|
|
4135
5307
|
static ɵfac: _angular_core.ɵɵFactoryDeclaration<OlNavDropdown, never>;
|
|
4136
|
-
static ɵcmp: _angular_core.ɵɵComponentDeclaration<OlNavDropdown, "ol-nav-dropdown", never, { "label": { "alias": "label"; "required": false; "isSignal": true; }; "icon": { "alias": "icon"; "required": false; "isSignal": true; }; "alignRight": { "alias": "alignRight"; "required": false; "isSignal": true; }; }, {}, never, ["[slot=trigger], [trigger]", "*"], true, never>;
|
|
5308
|
+
static ɵcmp: _angular_core.ɵɵComponentDeclaration<OlNavDropdown, "ol-nav-dropdown", never, { "label": { "alias": "label"; "required": false; "isSignal": true; }; "icon": { "alias": "icon"; "required": false; "isSignal": true; }; "alignRight": { "alias": "alignRight"; "required": false; "isSignal": true; }; "active": { "alias": "active"; "required": false; "isSignal": true; }; "columns": { "alias": "columns"; "required": false; "isSignal": true; }; "fullWidth": { "alias": "fullWidth"; "required": false; "isSignal": true; }; }, {}, never, ["[slot=trigger], [trigger]", "*"], true, never>;
|
|
5309
|
+
}
|
|
5310
|
+
|
|
5311
|
+
/** Một mục trong menu thả xuống. */
|
|
5312
|
+
interface OlMenubarItem {
|
|
5313
|
+
id: string;
|
|
5314
|
+
label: string;
|
|
5315
|
+
/** Chữ phụ bên phải: phím tắt, ví dụ "⌘S". */
|
|
5316
|
+
shortcut?: string;
|
|
5317
|
+
disabled?: boolean;
|
|
5318
|
+
/** Kẻ ngăn NGAY TRƯỚC mục này. */
|
|
5319
|
+
separatorBefore?: boolean;
|
|
5320
|
+
}
|
|
5321
|
+
/** Một menu trên thanh: nhãn trên thanh + danh sách mục. */
|
|
5322
|
+
interface OlMenubarMenu {
|
|
5323
|
+
id: string;
|
|
5324
|
+
label: string;
|
|
5325
|
+
items: OlMenubarItem[];
|
|
5326
|
+
disabled?: boolean;
|
|
5327
|
+
}
|
|
5328
|
+
/**
|
|
5329
|
+
* Thanh menu kiểu ứng dụng để bàn — Tệp · Sửa · Xem.
|
|
5330
|
+
*
|
|
5331
|
+
* Chưa có node Figma — dựng theo design system, dùng lại cách trình bày của
|
|
5332
|
+
* `ol-dropdown-item`.
|
|
5333
|
+
*
|
|
5334
|
+
* ## Khác `ol-dropdown` ở ba điểm, và đó là lý do có component riêng
|
|
5335
|
+
*
|
|
5336
|
+
* 1. **Mở một menu rồi RÊ sang menu kế là mở luôn**, không phải bấm lại. Đây
|
|
5337
|
+
* là hành vi người dùng đã quen từ phần mềm để bàn; thiếu nó thì thanh menu
|
|
5338
|
+
* chỉ là mấy cái dropdown đặt cạnh nhau.
|
|
5339
|
+
* 2. **Mũi tên trái/phải đi giữa các menu**, lên/xuống đi trong menu đang mở.
|
|
5340
|
+
* WAI-ARIA quy định `role="menubar"` phải làm vậy.
|
|
5341
|
+
* 3. **Một menu mở thì menu khác đóng** — không bao giờ có hai panel cùng lúc.
|
|
5342
|
+
*
|
|
5343
|
+
* ## Vì sao KHÔNG treo panel ra `<body>`
|
|
5344
|
+
*
|
|
5345
|
+
* Thanh menu thường nằm ngay dưới tiêu đề cửa sổ, không bị `overflow: hidden`
|
|
5346
|
+
* cắt như dropdown trong bảng. Giữ panel trong cây DOM thì Tab đi vào được tự
|
|
5347
|
+
* nhiên, không phải xử lý riêng như `ol-dropdown` đã phải làm.
|
|
5348
|
+
*
|
|
5349
|
+
* ## Lưu ý khi viết test
|
|
5350
|
+
*
|
|
5351
|
+
* Rê chuột giữa các menu cần bố cục thật để tính vị trí. jsdom không có, nên
|
|
5352
|
+
* spec khoá phần bàn phím và trạng thái mở/đóng; hành vi rê nghiệm thu trên
|
|
5353
|
+
* trình duyệt.
|
|
5354
|
+
*/
|
|
5355
|
+
declare class OlMenubar {
|
|
5356
|
+
private readonly elementRef;
|
|
5357
|
+
private readonly destroyRef;
|
|
5358
|
+
private readonly overlayContainer;
|
|
5359
|
+
readonly menus: _angular_core.InputSignal<OlMenubarMenu[]>;
|
|
5360
|
+
readonly ariaLabel: _angular_core.InputSignal<string>;
|
|
5361
|
+
/** `id` của menu đang mở. Rỗng nghĩa là không menu nào mở. */
|
|
5362
|
+
private readonly openId;
|
|
5363
|
+
readonly openMenuId: _angular_core.Signal<string>;
|
|
5364
|
+
readonly itemSelect: _angular_core.OutputEmitterRef<{
|
|
5365
|
+
menu: OlMenubarMenu;
|
|
5366
|
+
item: OlMenubarItem;
|
|
5367
|
+
}>;
|
|
5368
|
+
private releaseEscape;
|
|
5369
|
+
constructor();
|
|
5370
|
+
protected toggle(menu: OlMenubarMenu): void;
|
|
5371
|
+
/**
|
|
5372
|
+
* Rê sang menu khác khi ĐANG có menu mở thì mở luôn menu đó.
|
|
5373
|
+
*
|
|
5374
|
+
* Không mở khi chưa menu nào mở — nếu không, lướt chuột ngang thanh là bung
|
|
5375
|
+
* ra một panel người dùng không định mở.
|
|
5376
|
+
*/
|
|
5377
|
+
protected onMenuHover(menu: OlMenubarMenu): void;
|
|
5378
|
+
private open;
|
|
5379
|
+
private closeAll;
|
|
5380
|
+
protected onItemClick(menu: OlMenubarMenu, item: OlMenubarItem): void;
|
|
5381
|
+
/**
|
|
5382
|
+
* Mũi tên trái/phải đi giữa các menu — WAI-ARIA quy định cho `role="menubar"`.
|
|
5383
|
+
*
|
|
5384
|
+
* Vòng lại đầu khi tới cuối: thanh menu là một dải kín, không phải danh sách
|
|
5385
|
+
* có điểm dừng. Người dùng nhấn phải liên tục thì quay về menu đầu.
|
|
5386
|
+
*
|
|
5387
|
+
* Dùng `(keydown)` trần rồi tự lọc phím vì thẻ đã có `(click)` — hai listener
|
|
5388
|
+
* khác kiểu sự kiện trên cùng thẻ thì Angular suy `$event` theo cái đầu.
|
|
5389
|
+
*/
|
|
5390
|
+
protected onTriggerKeydown(event: KeyboardEvent, index: number): void;
|
|
5391
|
+
/**
|
|
5392
|
+
* Menu kế tiếp **còn dùng được** theo hướng `step`, vòng lại khi tới biên.
|
|
5393
|
+
*
|
|
5394
|
+
* Phải bỏ qua menu `disabled`: nút gốc có thuộc tính `disabled` nên
|
|
5395
|
+
* `.focus()` trên nó KHÔNG có tác dụng nào — tiêu điểm đứng nguyên chỗ cũ và
|
|
5396
|
+
* người dùng tưởng bàn phím hỏng. Spec bắt đúng lỗi này khi menu cuối bị vô
|
|
5397
|
+
* hiệu: nhấn End là tiêu điểm rơi về `<body>`.
|
|
5398
|
+
*
|
|
5399
|
+
* Trả `null` khi KHÔNG có menu nào dùng được — lúc đó không `preventDefault`,
|
|
5400
|
+
* để phím về lại hành vi mặc định của trình duyệt.
|
|
5401
|
+
*
|
|
5402
|
+
* Nhận `from` ngoài dải (-1 hoặc `length`) để Home/End dùng chung một phép:
|
|
5403
|
+
* Home là "từ trước mục đầu, đi sang phải", End là "từ sau mục cuối, đi sang
|
|
5404
|
+
* trái".
|
|
5405
|
+
*/
|
|
5406
|
+
private nextEnabled;
|
|
5407
|
+
protected triggerClasses(menu: OlMenubarMenu): string;
|
|
5408
|
+
protected itemClasses(item: OlMenubarItem): string;
|
|
5409
|
+
protected readonly hasMenus: _angular_core.Signal<boolean>;
|
|
5410
|
+
static ɵfac: _angular_core.ɵɵFactoryDeclaration<OlMenubar, never>;
|
|
5411
|
+
static ɵcmp: _angular_core.ɵɵComponentDeclaration<OlMenubar, "ol-menubar", never, { "menus": { "alias": "menus"; "required": false; "isSignal": true; }; "ariaLabel": { "alias": "ariaLabel"; "required": false; "isSignal": true; }; }, { "itemSelect": "itemSelect"; }, never, never, true, never>;
|
|
4137
5412
|
}
|
|
4138
5413
|
|
|
5414
|
+
/**
|
|
5415
|
+
* Bố cục thanh phân trang (Figma `ol-pagination` #1149:81850).
|
|
5416
|
+
*
|
|
5417
|
+
* `with-dropdown` là BÍ DANH: ≡ `text-buttons` + `[withDropdown]="true"`. Ô
|
|
5418
|
+
* chọn cỡ trang nay là cờ riêng gắn được vào MỌI type; giữ giá trị này vì gói
|
|
5419
|
+
* đã publish. (Chú thích đặt ở đây, không chen giữa các giá trị: guard
|
|
5420
|
+
* `check:gia-tri-ma-mau` đọc union sẽ đứt ở khối chú thích.)
|
|
5421
|
+
*/
|
|
4139
5422
|
type PaginationType = 'default' | 'arrows' | 'dropdown-buttons' | 'text-buttons' | 'two-buttons' | 'buttons-helper' | 'with-dropdown' | 'with-input' | 'simple-input'
|
|
4140
5423
|
/**
|
|
4141
5424
|
* `grouped` và `separated` trước chỉ có ở `PaginationVariant`. Thêm vào đây
|
|
@@ -4180,6 +5463,17 @@ declare class OlPagination {
|
|
|
4180
5463
|
readonly showText: _angular_core.InputSignal<boolean>;
|
|
4181
5464
|
readonly text: _angular_core.InputSignal<string>;
|
|
4182
5465
|
readonly showInfo: _angular_core.InputSignal<boolean>;
|
|
5466
|
+
/**
|
|
5467
|
+
* Thêm ô chọn số dòng mỗi trang ("10 mỗi trang") vào BẤT KỲ type nào — cạnh
|
|
5468
|
+
* dãy số, cạnh hai nút, cạnh ô nhập trang… Trước đây nó chỉ có ở một type
|
|
5469
|
+
* riêng (`with-dropdown`), muốn nó cạnh `arrows` hay `two-buttons` là không
|
|
5470
|
+
* được. Danh sách lấy từ `pageSizeOptions`, đổi thì phát `(pageChange)` về 1.
|
|
5471
|
+
*/
|
|
5472
|
+
readonly withDropdown: _angular_core.InputSignal<boolean>;
|
|
5473
|
+
/**
|
|
5474
|
+
* @deprecated Dùng `withDropdown`. Bí danh: bật là thêm ô chọn cỡ trang. Khi
|
|
5475
|
+
* không đặt `type`, nó vẫn chọn bố cục `with-dropdown` như trước.
|
|
5476
|
+
*/
|
|
4183
5477
|
readonly showSizeChanger: _angular_core.InputSignal<boolean>;
|
|
4184
5478
|
readonly showQuickJumper: _angular_core.InputSignal<boolean>;
|
|
4185
5479
|
readonly pageChange: _angular_core.OutputEmitterRef<number>;
|
|
@@ -4193,6 +5487,10 @@ declare class OlPagination {
|
|
|
4193
5487
|
* xảy ra. `type` đặt tường minh vẫn thắng; cờ chỉ điền vào chỗ trống.
|
|
4194
5488
|
*/
|
|
4195
5489
|
readonly effectiveType: _angular_core.Signal<PaginationType>;
|
|
5490
|
+
/** Bố cục vẽ ra: `with-dropdown` là bí danh nên quy về `text-buttons`. */
|
|
5491
|
+
readonly layoutType: _angular_core.Signal<PaginationType>;
|
|
5492
|
+
/** Có vẽ ô chọn cỡ trang không — cờ riêng, độc lập với type. */
|
|
5493
|
+
readonly hasPageSizeDropdown: _angular_core.Signal<boolean>;
|
|
4196
5494
|
/**
|
|
4197
5495
|
* Trang đang xem — gộp `pageIndex` và bí danh `currentPage`.
|
|
4198
5496
|
*
|
|
@@ -4264,7 +5562,7 @@ declare class OlPagination {
|
|
|
4264
5562
|
onPageSizeSelect(event: Event): void;
|
|
4265
5563
|
handleJump(): void;
|
|
4266
5564
|
static ɵfac: _angular_core.ɵɵFactoryDeclaration<OlPagination, never>;
|
|
4267
|
-
static ɵcmp: _angular_core.ɵɵComponentDeclaration<OlPagination, "ol-pagination", never, { "type": { "alias": "type"; "required": false; "isSignal": true; }; "variant": { "alias": "variant"; "required": false; "isSignal": true; }; "total": { "alias": "total"; "required": false; "isSignal": true; }; "pageSize": { "alias": "pageSize"; "required": false; "isSignal": true; }; "pageIndex": { "alias": "pageIndex"; "required": false; "isSignal": true; }; "currentPage": { "alias": "currentPage"; "required": false; "isSignal": true; }; "totalPagesInput": { "alias": "totalPages"; "required": false; "isSignal": true; }; "pageSizeOptions": { "alias": "pageSizeOptions"; "required": false; "isSignal": true; }; "showText": { "alias": "showText"; "required": false; "isSignal": true; }; "text": { "alias": "text"; "required": false; "isSignal": true; }; "showInfo": { "alias": "showInfo"; "required": false; "isSignal": true; }; "showSizeChanger": { "alias": "showSizeChanger"; "required": false; "isSignal": true; }; "showQuickJumper": { "alias": "showQuickJumper"; "required": false; "isSignal": true; }; }, { "pageSize": "pageSizeChange"; "pageIndex": "pageIndexChange"; "currentPage": "currentPageChange"; "pageChange": "pageChange"; }, never, never, true, never>;
|
|
5565
|
+
static ɵcmp: _angular_core.ɵɵComponentDeclaration<OlPagination, "ol-pagination", never, { "type": { "alias": "type"; "required": false; "isSignal": true; }; "variant": { "alias": "variant"; "required": false; "isSignal": true; }; "total": { "alias": "total"; "required": false; "isSignal": true; }; "pageSize": { "alias": "pageSize"; "required": false; "isSignal": true; }; "pageIndex": { "alias": "pageIndex"; "required": false; "isSignal": true; }; "currentPage": { "alias": "currentPage"; "required": false; "isSignal": true; }; "totalPagesInput": { "alias": "totalPages"; "required": false; "isSignal": true; }; "pageSizeOptions": { "alias": "pageSizeOptions"; "required": false; "isSignal": true; }; "showText": { "alias": "showText"; "required": false; "isSignal": true; }; "text": { "alias": "text"; "required": false; "isSignal": true; }; "showInfo": { "alias": "showInfo"; "required": false; "isSignal": true; }; "withDropdown": { "alias": "withDropdown"; "required": false; "isSignal": true; }; "showSizeChanger": { "alias": "showSizeChanger"; "required": false; "isSignal": true; }; "showQuickJumper": { "alias": "showQuickJumper"; "required": false; "isSignal": true; }; }, { "pageSize": "pageSizeChange"; "pageIndex": "pageIndexChange"; "currentPage": "currentPageChange"; "pageChange": "pageChange"; }, never, never, true, never>;
|
|
4268
5566
|
}
|
|
4269
5567
|
|
|
4270
5568
|
type PopoverPlacement = 'top' | 'bottom' | 'left' | 'right';
|
|
@@ -4320,6 +5618,29 @@ declare class OlPopover {
|
|
|
4320
5618
|
private cleanupAutoUpdate;
|
|
4321
5619
|
/** Hàm trả panel về chỗ cũ khi đóng. */
|
|
4322
5620
|
private detachPanel;
|
|
5621
|
+
/**
|
|
5622
|
+
* Selector cho phần tử nhận được tiêu điểm.
|
|
5623
|
+
*
|
|
5624
|
+
* `tabindex="-1"` bị loại: đó là dấu hiệu tác giả cố ý đưa phần tử ra khỏi
|
|
5625
|
+
* đường Tab. `:disabled` cũng loại — trình duyệt không cho nó nhận tiêu điểm.
|
|
5626
|
+
*/
|
|
5627
|
+
private static readonly FOCUSABLE;
|
|
5628
|
+
/**
|
|
5629
|
+
* Phần tử nhận tiêu điểm bên trong `root`, theo thứ tự nhìn thấy.
|
|
5630
|
+
*
|
|
5631
|
+
* Lọc phần ẩn bằng `[hidden]`/`[aria-hidden]` chứ KHÔNG `offsetParent`:
|
|
5632
|
+
* `offsetParent` là `null` với mọi phần tử trong `position: fixed` — mà panel
|
|
5633
|
+
* nổi hay dùng đúng kiểu định vị đó — nên danh sách sẽ rỗng và toàn bộ xử lý
|
|
5634
|
+
* Tab lặng lẽ không chạy.
|
|
5635
|
+
*/
|
|
5636
|
+
private focusablesIn;
|
|
5637
|
+
/**
|
|
5638
|
+
* Phần tử nhận tiêu điểm đứng ngay sau `element` trong thứ tự Tab của trang.
|
|
5639
|
+
*
|
|
5640
|
+
* Loại chính panel ra: nó treo cuối `<body>` nên nếu tính cả thì "phần tử sau
|
|
5641
|
+
* nút trigger" lại rơi vào panel vừa đóng.
|
|
5642
|
+
*/
|
|
5643
|
+
private nextFocusableAfter;
|
|
4323
5644
|
constructor();
|
|
4324
5645
|
toggle(): void;
|
|
4325
5646
|
open(): void;
|
|
@@ -4607,6 +5928,99 @@ declare class OlRating {
|
|
|
4607
5928
|
static ɵcmp: _angular_core.ɵɵComponentDeclaration<OlRating, "ol-rating", never, { "rating": { "alias": "rating"; "required": false; "isSignal": true; }; "max": { "alias": "max"; "required": false; "isSignal": true; }; "type": { "alias": "type"; "required": false; "isSignal": true; }; "score": { "alias": "score"; "required": false; "isSignal": true; }; "badgeText": { "alias": "badgeText"; "required": false; "isSignal": true; }; "minLabel": { "alias": "minLabel"; "required": false; "isSignal": true; }; "maxLabel": { "alias": "maxLabel"; "required": false; "isSignal": true; }; "ariaLabel": { "alias": "ariaLabel"; "required": false; "isSignal": true; }; "name": { "alias": "name"; "required": false; "isSignal": true; }; "value": { "alias": "value"; "required": false; "isSignal": true; }; }, { "value": "valueChange"; }, never, never, true, never>;
|
|
4608
5929
|
}
|
|
4609
5930
|
|
|
5931
|
+
type OlResizableDirection = 'horizontal' | 'vertical';
|
|
5932
|
+
/**
|
|
5933
|
+
* Hai khung chia nhau một vùng, kéo vạch giữa để đổi tỉ lệ.
|
|
5934
|
+
*
|
|
5935
|
+
* Chưa có node Figma — dựng theo design system: vạch kéo dùng `bg-default`,
|
|
5936
|
+
* sáng lên `bg-brand` khi rê chuột hoặc đang kéo.
|
|
5937
|
+
*
|
|
5938
|
+
* ## Vì sao tỉ lệ phần trăm chứ không pixel
|
|
5939
|
+
*
|
|
5940
|
+
* Người dùng đổi cỡ cửa sổ thì hai khung phải giãn theo. Lưu pixel thì khung
|
|
5941
|
+
* trái giữ nguyên còn khung phải nuốt toàn bộ phần thêm — tỉ lệ người dùng
|
|
5942
|
+
* chọn biến mất.
|
|
5943
|
+
*
|
|
5944
|
+
* ## Bắt chuột trên `document`, không trên vạch
|
|
5945
|
+
*
|
|
5946
|
+
* Kéo nhanh thì con trỏ rời khỏi vạch trước khi trình duyệt kịp gửi sự kiện
|
|
5947
|
+
* tiếp theo; nghe trên chính vạch thì kéo đứt đoạn. Nghe trên `document` lúc
|
|
5948
|
+
* đang kéo và gỡ ngay khi thả.
|
|
5949
|
+
*
|
|
5950
|
+
* `setPointerCapture` giải quyết đúng việc này nhưng không có trong jsdom, nên
|
|
5951
|
+
* spec sẽ không chạy được nhánh kéo — dùng `document` thì cả hai môi trường
|
|
5952
|
+
* cùng một đường mã.
|
|
5953
|
+
*
|
|
5954
|
+
* ## Bàn phím
|
|
5955
|
+
*
|
|
5956
|
+
* Vạch là `role="separator"` có `tabindex`, mũi tên đổi 2% mỗi lần, Home/End
|
|
5957
|
+
* về hai biên. Không có phần này thì người dùng bàn phím không đổi được tỉ lệ
|
|
5958
|
+
* — và một khung chia đôi không kéo được thì chỉ là hai `<div>` cạnh nhau.
|
|
5959
|
+
*
|
|
5960
|
+
* ## Lưu ý khi viết test
|
|
5961
|
+
*
|
|
5962
|
+
* jsdom không tính bố cục: `getBoundingClientRect()` trả 0 cho mọi thứ, nên
|
|
5963
|
+
* phép quy đổi toạ độ chuột sang phần trăm luôn ra `NaN` hoặc 0. Spec khoá
|
|
5964
|
+
* phần bàn phím và ràng buộc min/max (tính thuần số); việc kéo chuột nghiệm
|
|
5965
|
+
* thu trên trình duyệt.
|
|
5966
|
+
*/
|
|
5967
|
+
declare class OlResizable {
|
|
5968
|
+
private readonly elementRef;
|
|
5969
|
+
private readonly destroyRef;
|
|
5970
|
+
readonly direction: _angular_core.InputSignal<OlResizableDirection>;
|
|
5971
|
+
/** Tỉ lệ khung ĐẦU, tính bằng phần trăm. Hai chiều để nơi dùng lưu lại được. */
|
|
5972
|
+
readonly ratio: _angular_core.ModelSignal<number>;
|
|
5973
|
+
/** Chặn dưới và chặn trên, phần trăm. Khung nào cũng không nhỏ hơn `minRatio`. */
|
|
5974
|
+
readonly minRatio: _angular_core.InputSignal<number>;
|
|
5975
|
+
readonly maxRatio: _angular_core.InputSignal<number>;
|
|
5976
|
+
/** Bước đổi mỗi lần nhấn mũi tên, phần trăm. */
|
|
5977
|
+
readonly keyboardStep: _angular_core.InputSignal<number>;
|
|
5978
|
+
readonly disabled: _angular_core.InputSignal<boolean>;
|
|
5979
|
+
readonly ariaLabel: _angular_core.InputSignal<string>;
|
|
5980
|
+
/**
|
|
5981
|
+
* Bắn khi thả chuột hoặc nhấn phím — KHÔNG bắn liên tục lúc đang kéo.
|
|
5982
|
+
*
|
|
5983
|
+
* Tên là `resizeEnd` chứ không `ratioChange`: `model()` đã tự sinh
|
|
5984
|
+
* `ratioChange` cho binding hai chiều, khai thêm output trùng tên là lỗi
|
|
5985
|
+
* biên dịch NG1054. Hai thứ cũng khác nghĩa — `ratioChange` bắn mỗi lần giá
|
|
5986
|
+
* trị đổi (kể cả từng nhịp kéo), còn `resizeEnd` chỉ bắn khi người dùng đã
|
|
5987
|
+
* thả tay, đúng lúc nên lưu tỉ lệ xuống máy chủ.
|
|
5988
|
+
*/
|
|
5989
|
+
readonly resizeEnd: _angular_core.OutputEmitterRef<number>;
|
|
5990
|
+
private readonly dragging;
|
|
5991
|
+
private releaseDrag;
|
|
5992
|
+
constructor();
|
|
5993
|
+
/** Ép tỉ lệ vào khoảng cho phép. Tách ra để spec khoá được mà không cần DOM. */
|
|
5994
|
+
clamp(value: number): number;
|
|
5995
|
+
protected onPointerDown(event: PointerEvent): void;
|
|
5996
|
+
private stopDrag;
|
|
5997
|
+
private applyFromPointer;
|
|
5998
|
+
protected onKeydown(event: KeyboardEvent): void;
|
|
5999
|
+
protected readonly rootClasses: _angular_core.Signal<"flex h-full w-full" | "flex h-full w-full flex-col">;
|
|
6000
|
+
/** Kích thước khung đầu — `flex-basis` phần trăm, khung sau lấp phần còn lại. */
|
|
6001
|
+
protected readonly firstStyle: _angular_core.Signal<string>;
|
|
6002
|
+
/**
|
|
6003
|
+
* Vạch chia.
|
|
6004
|
+
*
|
|
6005
|
+
* ## Vùng bấm rộng hơn vạch nhìn thấy
|
|
6006
|
+
*
|
|
6007
|
+
* Vạch chỉ dày 6px thì đúng thẩm mỹ nhưng vùng bấm 6px vi phạm WCAG 2.5.8
|
|
6008
|
+
* (ngưỡng 24px) — đo trên trình duyệt ra `6×188px`. Nên vạch nhận
|
|
6009
|
+
* `w-6`/`h-6` để vùng bấm đủ 24px, còn phần MÀU nằm ở `::before` chỉ
|
|
6010
|
+
* 6px ở giữa. Người dùng thấy vạch mảnh, tay và con trỏ thì có 24px để bắt.
|
|
6011
|
+
*
|
|
6012
|
+
* `::before` khai trong `handleBarClasses()` và đặt qua một `<span>` con chứ
|
|
6013
|
+
* không dùng biến thể `before:` của Tailwind: `before:` cần nhiều class cho
|
|
6014
|
+
* cùng một hình và khó đọc hơn một phần tử thật.
|
|
6015
|
+
*/
|
|
6016
|
+
protected readonly handleClasses: _angular_core.Signal<string>;
|
|
6017
|
+
/** Phần MÀU của vạch — mảnh 6px, nằm giữa vùng bấm 24px. */
|
|
6018
|
+
protected readonly handleBarClasses: _angular_core.Signal<string>;
|
|
6019
|
+
protected readonly ariaOrientation: _angular_core.Signal<"vertical" | "horizontal">;
|
|
6020
|
+
static ɵfac: _angular_core.ɵɵFactoryDeclaration<OlResizable, never>;
|
|
6021
|
+
static ɵcmp: _angular_core.ɵɵComponentDeclaration<OlResizable, "ol-resizable", never, { "direction": { "alias": "direction"; "required": false; "isSignal": true; }; "ratio": { "alias": "ratio"; "required": false; "isSignal": true; }; "minRatio": { "alias": "minRatio"; "required": false; "isSignal": true; }; "maxRatio": { "alias": "maxRatio"; "required": false; "isSignal": true; }; "keyboardStep": { "alias": "keyboardStep"; "required": false; "isSignal": true; }; "disabled": { "alias": "disabled"; "required": false; "isSignal": true; }; "ariaLabel": { "alias": "ariaLabel"; "required": false; "isSignal": true; }; }, { "ratio": "ratioChange"; "resizeEnd": "resizeEnd"; }, never, ["[first]", "[second]"], true, never>;
|
|
6022
|
+
}
|
|
6023
|
+
|
|
4610
6024
|
/**
|
|
4611
6025
|
* Kiểu dữ liệu cho `ol-app-nav` — menu điều hướng Ôn Luyện.
|
|
4612
6026
|
*
|
|
@@ -5402,13 +6816,13 @@ declare class OlToastContainer {
|
|
|
5402
6816
|
* cùng một union, tách thành hai kiểu riêng là để người dùng phải nhớ chúng
|
|
5403
6817
|
* bằng nhau.
|
|
5404
6818
|
*/
|
|
5405
|
-
type OlTooltipTheme = 'dark' | 'light' | 'brand';
|
|
6819
|
+
type OlTooltipTheme = 'subtle' | 'dark' | 'light' | 'brand';
|
|
5406
6820
|
/** Hướng hiện tooltip so với phần tử đích. */
|
|
5407
6821
|
type OlTooltipPosition = 'top' | 'bottom' | 'left' | 'right';
|
|
5408
6822
|
declare class OlTooltip {
|
|
5409
6823
|
/** Tooltip content text */
|
|
5410
6824
|
readonly content: _angular_core.InputSignal<string>;
|
|
5411
|
-
/** Theme variant */
|
|
6825
|
+
/** Theme variant — mặc định `subtle` (nền Primary 50). */
|
|
5412
6826
|
readonly theme: _angular_core.InputSignal<OlTooltipTheme>;
|
|
5413
6827
|
/** Tooltip ID for ARIA */
|
|
5414
6828
|
readonly tooltipId: _angular_core.InputSignal<string>;
|
|
@@ -5585,6 +6999,134 @@ declare class OlIconService {
|
|
|
5585
6999
|
static ɵprov: _angular_core.ɵɵInjectableDeclaration<any>;
|
|
5586
7000
|
}
|
|
5587
7001
|
|
|
7002
|
+
type OlIconStackSize = 'sm' | 'base' | 'lg';
|
|
7003
|
+
/**
|
|
7004
|
+
* Chồng nhiều icon hoặc logo lên nhau, kèm số đếm "+N".
|
|
7005
|
+
*
|
|
7006
|
+
* Chưa có node Figma — dựng theo `ol-avatar-group`, component cùng cơ chế đã
|
|
7007
|
+
* có trong thư viện. Khác ở chỗ: avatar là ảnh người nên luôn tròn, còn icon
|
|
7008
|
+
* thường là biểu tượng dịch vụ hay môn học nên mặc định bo vừa (`rounded-lg`)
|
|
7009
|
+
* và có nền để icon một màu vẫn tách khỏi icon bên dưới.
|
|
7010
|
+
*
|
|
7011
|
+
* ## Vòng viền là thứ làm nên hiệu ứng chồng
|
|
7012
|
+
*
|
|
7013
|
+
* Mỗi ô có `ring-2 ring-buffer` — vòng viền màu nền trang, không phải viền
|
|
7014
|
+
* màu. Nhờ nó hai ô chồng nhau vẫn thấy rõ ranh giới. Bỏ vòng này thì các ô
|
|
7015
|
+
* dính thành một khối nhoè.
|
|
7016
|
+
*
|
|
7017
|
+
* `ring-buffer` chứ không `ring-white`: ở chế độ tối nền không phải trắng, và
|
|
7018
|
+
* viền trắng trên nền đen là đường kẻ sáng chói quanh mỗi icon.
|
|
7019
|
+
*
|
|
7020
|
+
* ## Thứ tự chồng
|
|
7021
|
+
*
|
|
7022
|
+
* Mặc định ô ĐẦU nằm trên — giống xếp bài. `reverse` lật lại cho ô cuối nằm
|
|
7023
|
+
* trên, dùng khi ô cuối là thứ cần nhấn (icon "thêm", trạng thái mới nhất).
|
|
7024
|
+
*
|
|
7025
|
+
* Làm bằng `flex-row-reverse` cộng đảo thứ tự dữ liệu chứ không bằng
|
|
7026
|
+
* `z-index`: `z-index` cần stacking context và sẽ hỏng khi nơi gọi đặt
|
|
7027
|
+
* component vào một phần tử có `transform` hay `opacity`.
|
|
7028
|
+
*/
|
|
7029
|
+
declare class OlIconStack {
|
|
7030
|
+
readonly size: _angular_core.InputSignal<OlIconStackSize>;
|
|
7031
|
+
/** Số đếm "+N" ở cuối. `null` thì không vẽ. */
|
|
7032
|
+
readonly counter: _angular_core.InputSignal<string | number | null>;
|
|
7033
|
+
readonly counterAriaLabel: _angular_core.InputSignal<string>;
|
|
7034
|
+
/** Lật thứ tự chồng: ô CUỐI nằm trên thay vì ô đầu. */
|
|
7035
|
+
readonly reverse: _angular_core.InputSignal<boolean>;
|
|
7036
|
+
/**
|
|
7037
|
+
* Bo góc của từng ô. `full` cho logo tròn, `lg` cho biểu tượng vuông.
|
|
7038
|
+
*
|
|
7039
|
+
* Áp lên CON qua biến thể `*:` của Tailwind, nên nơi gọi chỉ việc đặt
|
|
7040
|
+
* `<ol-icon>` hay `<img>` vào là xong.
|
|
7041
|
+
*/
|
|
7042
|
+
readonly rounded: _angular_core.InputSignal<"lg" | "full">;
|
|
7043
|
+
protected readonly rootClasses: _angular_core.Signal<string>;
|
|
7044
|
+
/**
|
|
7045
|
+
* Ô đếm "+N".
|
|
7046
|
+
*
|
|
7047
|
+
* `text-heading` chứ KHÔNG `text-body`: tổ hợp `bg-neutral-quaternary` +
|
|
7048
|
+
* `text-body` đo được 6.10 ở chế độ sáng nhưng chỉ 3.96 ở chế độ tối — dưới
|
|
7049
|
+
* ngưỡng WCAG 4.5. Đây là kết luận đã đo ở `ol-avatar-group` (BUG-016 mục 5),
|
|
7050
|
+
* theo tiền lệ sẵn có chứ không đoán lại.
|
|
7051
|
+
*
|
|
7052
|
+
* Chú thích để Ở ĐÂY chứ không trong template: template là một chuỗi
|
|
7053
|
+
* template literal, nên dấu backtick trong chú thích HTML đóng chuỗi sớm và
|
|
7054
|
+
* TS báo lỗi ở dòng chẳng liên quan (đã mắc khi viết file này).
|
|
7055
|
+
*/
|
|
7056
|
+
protected readonly counterClasses: _angular_core.Signal<string>;
|
|
7057
|
+
static ɵfac: _angular_core.ɵɵFactoryDeclaration<OlIconStack, never>;
|
|
7058
|
+
static ɵcmp: _angular_core.ɵɵComponentDeclaration<OlIconStack, "ol-icon-stack", never, { "size": { "alias": "size"; "required": false; "isSignal": true; }; "counter": { "alias": "counter"; "required": false; "isSignal": true; }; "counterAriaLabel": { "alias": "counterAriaLabel"; "required": false; "isSignal": true; }; "reverse": { "alias": "reverse"; "required": false; "isSignal": true; }; "rounded": { "alias": "rounded"; "required": false; "isSignal": true; }; }, {}, never, ["*"], true, never>;
|
|
7059
|
+
}
|
|
7060
|
+
|
|
7061
|
+
type OlItemSize = 'sm' | 'base' | 'lg';
|
|
7062
|
+
type OlItemAlign = 'start' | 'center';
|
|
7063
|
+
/**
|
|
7064
|
+
* Một dòng nội dung: phần dẫn đầu · tiêu đề + mô tả · phần hành động.
|
|
7065
|
+
*
|
|
7066
|
+
* Chưa có node Figma — dựng theo design system, lấy khoảng cách và cỡ chữ từ
|
|
7067
|
+
* `ol-checkbox-radio-form` (component gần nhất đang có cấu trúc này).
|
|
7068
|
+
*
|
|
7069
|
+
* ## Vì sao KHÔNG mở rộng `ol-list-group-item`
|
|
7070
|
+
*
|
|
7071
|
+
* Cái đó là `<li>` và phải nằm trong `<ul>` của `ol-list-group` — HTML quy
|
|
7072
|
+
* định vậy. Còn dòng nội dung thì hay đứng một mình trong thẻ, trong ngăn kéo,
|
|
7073
|
+
* hay trong kết quả tìm kiếm. Nhồi cấu trúc vào `<li>` là buộc mọi nơi dùng
|
|
7074
|
+
* phải bọc thêm `<ul>` không có ý nghĩa ngữ nghĩa nào.
|
|
7075
|
+
*
|
|
7076
|
+
* Hai component dùng chung cách xếp; `ol-item` lo phần bên trong, đặt ở đâu là
|
|
7077
|
+
* việc của nơi gọi.
|
|
7078
|
+
*
|
|
7079
|
+
* ## Ba khe, KHÔNG phải ba input
|
|
7080
|
+
*
|
|
7081
|
+
* `[lead]` và `[actions]` là khe cắm chứ không phải input nhận tên icon: phần
|
|
7082
|
+
* dẫn đầu có thể là icon, avatar, ảnh bìa hay số thứ tự; phần hành động có thể
|
|
7083
|
+
* là nút, huy hiệu, hay một dòng chữ. Nhận tên icon thì mỗi lần cần thứ khác
|
|
7084
|
+
* lại phải thêm một input.
|
|
7085
|
+
*
|
|
7086
|
+
* Riêng `icon` giữ lại làm lối tắt cho ca hay gặp nhất. Nó nằm TRONG cùng khe
|
|
7087
|
+
* `[lead]`, sau nội dung chiếu — nơi gọi truyền cả hai thì có hai phần dẫn đầu
|
|
7088
|
+
* cạnh nhau, nhưng đó là ca hiếm và không đáng thêm selector CSS để chặn.
|
|
7089
|
+
*/
|
|
7090
|
+
declare class OlItem {
|
|
7091
|
+
readonly title: _angular_core.InputSignal<string>;
|
|
7092
|
+
readonly description: _angular_core.InputSignal<string>;
|
|
7093
|
+
/** Lối tắt cho phần dẫn đầu dạng icon. Khe `[lead]` đè lên nó. */
|
|
7094
|
+
readonly icon: _angular_core.InputSignal<string>;
|
|
7095
|
+
readonly size: _angular_core.InputSignal<OlItemSize>;
|
|
7096
|
+
/**
|
|
7097
|
+
* Căn phần dẫn đầu và hành động theo chiều dọc.
|
|
7098
|
+
*
|
|
7099
|
+
* `start` khi mô tả dài hai ba dòng — icon căn giữa một khối cao trông như
|
|
7100
|
+
* trôi lơ lửng. `center` khi chỉ có tiêu đề.
|
|
7101
|
+
*/
|
|
7102
|
+
readonly align: _angular_core.InputSignal<OlItemAlign>;
|
|
7103
|
+
/** Bấm được: thêm hiệu ứng hover và con trỏ tay, phát `itemClick`. */
|
|
7104
|
+
readonly interactive: _angular_core.InputSignal<boolean>;
|
|
7105
|
+
readonly disabled: _angular_core.InputSignal<boolean>;
|
|
7106
|
+
/** Biến cả dòng thành liên kết. Bỏ qua khi `disabled`. */
|
|
7107
|
+
readonly href: _angular_core.InputSignal<string | null>;
|
|
7108
|
+
readonly itemClick: _angular_core.OutputEmitterRef<MouseEvent>;
|
|
7109
|
+
/**
|
|
7110
|
+
* Enter và Space kích hoạt dòng `interactive`, như một `<button>` thật.
|
|
7111
|
+
*
|
|
7112
|
+
* Dùng `(keydown)` trần rồi tự lọc phím, KHÔNG `(keydown.enter)`: hai
|
|
7113
|
+
* listener khác kiểu sự kiện trên cùng một thẻ thì Angular suy `$event` theo
|
|
7114
|
+
* cái đầu — `(click)` đứng trước nên `$event` thành `MouseEvent` và TS báo
|
|
7115
|
+
* lỗi ở dòng `keydown`.
|
|
7116
|
+
*
|
|
7117
|
+
* `preventDefault` cho Space, nếu không trang cuộn xuống một màn cùng lúc.
|
|
7118
|
+
*/
|
|
7119
|
+
protected onKeyActivate(event: KeyboardEvent): void;
|
|
7120
|
+
protected onClick(event: MouseEvent): void;
|
|
7121
|
+
protected readonly rootClasses: _angular_core.Signal<string>;
|
|
7122
|
+
protected readonly titleClasses: _angular_core.Signal<string>;
|
|
7123
|
+
protected readonly descriptionClasses: _angular_core.Signal<string>;
|
|
7124
|
+
/** Cỡ icon lối tắt, theo cỡ dòng. */
|
|
7125
|
+
protected readonly iconSize: _angular_core.Signal<number>;
|
|
7126
|
+
static ɵfac: _angular_core.ɵɵFactoryDeclaration<OlItem, never>;
|
|
7127
|
+
static ɵcmp: _angular_core.ɵɵComponentDeclaration<OlItem, "ol-item", never, { "title": { "alias": "title"; "required": false; "isSignal": true; }; "description": { "alias": "description"; "required": false; "isSignal": true; }; "icon": { "alias": "icon"; "required": false; "isSignal": true; }; "size": { "alias": "size"; "required": false; "isSignal": true; }; "align": { "alias": "align"; "required": false; "isSignal": true; }; "interactive": { "alias": "interactive"; "required": false; "isSignal": true; }; "disabled": { "alias": "disabled"; "required": false; "isSignal": true; }; "href": { "alias": "href"; "required": false; "isSignal": true; }; }, { "itemClick": "itemClick"; }, never, ["[lead]", "*", "[actions]"], true, never>;
|
|
7128
|
+
}
|
|
7129
|
+
|
|
5588
7130
|
type OlBottomNavPosition = 'fixed' | 'relative';
|
|
5589
7131
|
declare class OlBottomNav {
|
|
5590
7132
|
readonly bordered: _angular_core.InputSignal<boolean>;
|
|
@@ -6423,6 +7965,24 @@ declare class OlFocusTrapService {
|
|
|
6423
7965
|
* @param autoFocus Tự động focus vào element đầu tiên (default: true)
|
|
6424
7966
|
*/
|
|
6425
7967
|
trap(element: HTMLElement, autoFocus?: boolean): void;
|
|
7968
|
+
/**
|
|
7969
|
+
* Chọn phần tử nhận focus khi overlay mở.
|
|
7970
|
+
*
|
|
7971
|
+
* Bản trước lấy phần tử focus được ĐẦU TIÊN theo thứ tự DOM. Header đứng
|
|
7972
|
+
* trước nội dung nên mở modal/drawer nào tiêu điểm cũng rơi vào nút ✕ —
|
|
7973
|
+
* người dùng phải Tab qua nút đóng mới tới ô nhập đầu tiên, và lỡ Enter là
|
|
7974
|
+
* đóng mất hộp thoại vừa mở (báo 2026-09-28).
|
|
7975
|
+
*
|
|
7976
|
+
* Thứ tự ưu tiên:
|
|
7977
|
+
* 1. phần tử nơi gọi đánh dấu `autofocus` / `data-autofocus` — trình duyệt
|
|
7978
|
+
* chỉ tôn trọng `autofocus` lúc tải trang, không phải lúc chèn hộp thoại,
|
|
7979
|
+
* nên service tự làm
|
|
7980
|
+
* 2. phần tử đầu tiên KHÔNG phải nút đóng (`[data-ol-dismiss]`) — thường là ô
|
|
7981
|
+
* nhập đầu tiên trong nội dung; nội dung không có gì bấm được thì tới nút
|
|
7982
|
+
* đầu tiên ở footer
|
|
7983
|
+
* 3. không còn gì khác mới về nút đóng, như cũ
|
|
7984
|
+
*/
|
|
7985
|
+
private initialFocusTarget;
|
|
6426
7986
|
/**
|
|
6427
7987
|
* Release focus trap và restore focus về element trước đó
|
|
6428
7988
|
*/
|
|
@@ -6458,6 +8018,15 @@ declare class OlFocusTrapService {
|
|
|
6458
8018
|
* Update danh sách focusable elements trong trap element
|
|
6459
8019
|
*/
|
|
6460
8020
|
private updateFocusableElements;
|
|
8021
|
+
/**
|
|
8022
|
+
* Phần tử có đang hiện không.
|
|
8023
|
+
*
|
|
8024
|
+
* KHÔNG dùng `offsetParent !== null`: nó trả `null` cho chính phần tử
|
|
8025
|
+
* `position: fixed` (nút nổi trong drawer/modal) dù phần tử hiện rõ, và luôn
|
|
8026
|
+
* `null` trong jsdom — nên mọi phần tử bị lọc mất, service không focus được
|
|
8027
|
+
* gì và spec không viết được.
|
|
8028
|
+
*/
|
|
8029
|
+
private isVisible;
|
|
6461
8030
|
/**
|
|
6462
8031
|
* Handle keyboard navigation trong trap
|
|
6463
8032
|
*/
|
|
@@ -6744,6 +8313,6 @@ declare class OlOverlayContainer {
|
|
|
6744
8313
|
static ɵprov: _angular_core.ɵɵInjectableDeclaration<any>;
|
|
6745
8314
|
}
|
|
6746
8315
|
|
|
6747
|
-
export { CHAT_BUBBLE_STATUS, FIELD_ASTERISK, FIELD_DISABLED, FIELD_HEIGHT, FIELD_HELPER, FIELD_HELPER_GAP, FIELD_LABEL, FIELD_LABEL_GAP, FIELD_MIN_HEIGHT, FIELD_PADDING_X, FIELD_RADIUS, FIELD_STATE, FIELD_TEXT, MONTHS_FULL_EN, MONTHS_FULL_VI, MONTHS_SHORT_VI, OlAccordion, OlAccordionItem, OlAlert, OlAlertDialog, OlAppNav, OlAspectRatio, OlAutocomplete, OlAvatar, OlAvatarGroup, OlBackdrop, OlBadge, OlBanner, OlBottomNav, OlBottomNavItem, OlBreadcrumb, OlBreadcrumbItem, OlButton, OlButtonGroup, OlCard, OlCarousel, OlCarouselSlide, OlChart, OlChatBubble, OlChatContainer, OlCheckbox, OlCheckboxRadioForm, OlCheckboxRadioGroup, OlClipboard, OlCollapse, OlCommand, OlDateRangePicker, OlDatepicker, OlDatepickerDirective, OlDatepickerFooter, OlDatepickerHeader, OlDatepickerPopup, OlDatepickerStateService, OlDayView, OlDeviceMockup, OlDownloadAppButton, OlDrawer, OlDrawerFooter, OlDrawerHeader, OlDropdown, OlDropdownHeader, OlDropdownItem, OlEmpty, OlFileInput,
|
|
6748
|
-
export type { AccordionVariant, AlertColor, AlertDialogTone, AlertLayout, AlertRounded, AlertType, AlertVariant, AppDevice, AppNavConfig, AppNavGroup, AppNavItem, AppNavUser, AppTheme, AutocompleteOption, AutocompleteSize, AutocompleteState, AvatarShape, AvatarSize, AvatarStatus, BadgeColor, BadgeShape, BadgeSize, BadgeTheme, BadgeType, BannerPosition, BannerVariant, BoxplotDataPoint, BreadcrumbItemStatus, BreadcrumbSeparator, BreadcrumbVariant, ButtonColor, ButtonGroupColor, ButtonGroupOrientation, ButtonGroupSize, ButtonSize, CardPadding, CardRadius, CardShadow, CardVariant, ChartDataPoint, ChartSeries, ChartType, ChatBubbleStatus, ChatSender, CheckboxSize, ChoiceControl, ChoiceControlPosition, ChoiceGroupLayout, ChoiceLayout, ChoiceShape, CommandGroup, CommandItem, DateCustomClass, DateRange, DatepickerPreset, DatepickerSelectionMode, DatepickerSize, DatepickerViewMode, DayCell, DeviceType, DrawerFooterLayout, DrawerPlacement, DrawerSize, DropdownAutoClose, DropdownPlacement, DropdownTrigger, EmptySize, FieldSize, FieldState, FileInputSize,
|
|
8316
|
+
export { CHAT_BUBBLE_STATUS, FIELD_ASTERISK, FIELD_CLEAR_RESERVE_END, FIELD_DISABLED, FIELD_HEIGHT, FIELD_HELPER, FIELD_HELPER_GAP, FIELD_ICON_GAP, FIELD_ICON_RESERVE_END, FIELD_ICON_RESERVE_START, FIELD_LABEL, FIELD_LABEL_BESIDE, FIELD_LABEL_GAP, FIELD_MIN_HEIGHT, FIELD_PADDING_END, FIELD_PADDING_START, FIELD_PADDING_X, FIELD_RADIUS, FIELD_STATE, FIELD_TEXT, FILE_KIND_META, FLOAT_LABEL_START, MONTHS_FULL_EN, MONTHS_FULL_VI, MONTHS_SHORT_VI, OlAccordion, OlAccordionItem, OlAlert, OlAlertDialog, OlAppNav, OlAspectRatio, OlAutocomplete, OlAvatar, OlAvatarGroup, OlBackdrop, OlBadge, OlBanner, OlBottomNav, OlBottomNavItem, OlBreadcrumb, OlBreadcrumbItem, OlButton, OlButtonGroup, OlCard, OlCarousel, OlCarouselSlide, OlChart, OlChatBubble, OlChatContainer, OlCheckbox, OlCheckboxRadioForm, OlCheckboxRadioGroup, OlClipboard, OlCollapse, OlCommand, OlDateRangePicker, OlDatepicker, OlDatepickerDirective, OlDatepickerFooter, OlDatepickerHeader, OlDatepickerPopup, OlDatepickerStateService, OlDayView, OlDeviceMockup, OlDownloadAppButton, OlDrawer, OlDrawerFooter, OlDrawerHeader, OlDropdown, OlDropdownHeader, OlDropdownItem, OlDropdownSearch, OlDropdownState, OlEmpty, OlFileDropzone, OlFileInput, OlFileItem, OlFileUpload, OlFocusTrapService, OlFooter, OlFrame, OlGallery, OlGalleryItem, OlHelper, OlIcon, OlIconService, OlIconShape, OlIconStack, OlImagePreview, OlInput, OlInputCounter, OlItem, OlJumbotron, OlKbd, OlLabel, OlListGroup, OlListGroupItem, OlLoadingOverlay, OlMenubar, OlModal, OlModalFooter, OlModalHeader, OlMonthView, OlNavDropdown, OlNavbar, OlNavbarItem, OlOtpInput, OlOverlayContainer, OlPagination, OlPopover, OlPopoverContent, OlPositioningService, OlProgress, OlProgressBarService, OlProgressBarTop, OlRadio, OlRange, OlRating, OlResizable, OlRichTextEditor, OlScrollArea, OlScrollspy, OlSegmented, OlSelect, OlSeparator, OlSidebar, OlSidebarGroup, OlSidebarItem, OlSidebarSubmenu, OlSkeleton, OlSpeedDial, OlSpeedDialItem, OlSpinner, OlStepItem, OlStepper, OlTabItem, OlTable, OlTableLoading, OlTableRow, OlTabs, OlTagInput, OlTextarea, OlTimeline, OlTimelineItem, OlTimepicker, OlToast, OlToastContainer, OlToastService, OlToggle, OlToggleGroup, OlToggleInput, OlTooltip, OlTooltipDirective, OlTree, OlTreeNodeItem, OlYearView, PICKER_ICON_RESERVE_START, WEEKDAYS_SHORT_EN, WEEKDAYS_SHORT_VI, boDau, cloneDate, detectFileKind, endOfDay, fieldLabelLayout, fieldSizeClasses, fileExtension, filesFromClipboard, formatDate, formatFileSize, generateMonthMatrix, generateMonthsMatrix, generateYearsMatrix, isBetween, isDateDisabled, isEditableTarget, isSameDay, isSameMonth, isSameYear, isToday, matchesAccept, multiValuePadY, parseDate, pasteShortcutLabel, startOfDay, stripDiacritics, toUploadFile, validateFiles };
|
|
8317
|
+
export type { AccordionVariant, AlertColor, AlertDialogTone, AlertLayout, AlertRounded, AlertType, AlertVariant, AppDevice, AppNavConfig, AppNavGroup, AppNavItem, AppNavUser, AppTheme, AutocompleteOption, AutocompleteSize, AutocompleteState, AvatarShape, AvatarSize, AvatarStatus, BadgeColor, BadgeShape, BadgeSize, BadgeTheme, BadgeType, BannerPosition, BannerVariant, BoxplotDataPoint, BreadcrumbItemStatus, BreadcrumbSeparator, BreadcrumbVariant, ButtonColor, ButtonGroupColor, ButtonGroupOrientation, ButtonGroupSize, ButtonSize, CardPadding, CardRadius, CardShadow, CardVariant, ChartDataPoint, ChartSeries, ChartType, ChatBubbleStatus, ChatSender, CheckboxSize, ChoiceControl, ChoiceControlPosition, ChoiceGroupLayout, ChoiceLayout, ChoiceShape, CommandGroup, CommandItem, DateCustomClass, DateRange, DatepickerPreset, DatepickerSelectionMode, DatepickerSize, DatepickerViewMode, DayCell, DeviceType, DrawerFooterLayout, DrawerPlacement, DrawerSize, DropdownAutoClose, DropdownPlacement, DropdownStateType, DropdownTrigger, EmptySize, FieldSize, FieldState, FileInputSize, FileItemVariant, FileKind, FileKindMeta, FileRejectReason, FileRejection, FileUploadMode, FileValidationResult, FileValidationRules, FloatingVariant, HeatmapData, HelperFeature, HelperRule, HelperSize, HelperState, IconColor, IconShapeColor, IconShapeSize, IconShapeType, IconSize, IconVariant, InputCounterSize, InputSize, InputState, JumbotronVariant, LabelPosition, ListGroupType, ModalFooterLayout, ModalPlacement, ModalSize, MonthCell, NavbarCollapseAt, NavbarDensity, OlAvatarStatusPosition, OlBottomNavPosition, OlButtonType, OlCheckboxRadioFormAlign, OlCheckboxRadioGroupRole, OlDateRangePickerVariant, OlFrameRounded, OlFrameSpacing, OlFrameVariant, OlGalleryGap, OlGalleryRatio, OlHelperType, OlIconStackSize, OlItemAlign, OlItemSize, OlMenubarItem, OlMenubarMenu, OlModalBackdrop, OlModalRole, OlPreviewImage, OlResizableDirection, OlScrollspyItem, OlScrollspyOrientation, OlSkeletonAnimation, OlSkeletonAspectRatio, OlSkeletonRounded, OlSkeletonType, OlSpeedDialTooltipPosition, OlTimepickerAddonType, OlToggleInputAlign, OlTreeNode, OlTreeNodeSelectionMode, OlTreeNodeToggleIcon, OlTreeSelectionMode, OlTreeToggleIcon, OlUploadFile, OtpInputSize, OverlayLayer, PaginationType, PaginationVariant, PopoverPlacement, PopoverTrigger, PositionedCoordinates, PositioningOptions, ProgressColor, ProgressLabelPosition, ProgressSize, RadarIndicator, RadioSize, RatingType, ScatterDataPoint, ScatterSeries, ScrollAreaAxis, ScrollAreaScrollbar, SegmentedColor, SegmentedOption, SegmentedSize, SelectOption, SelectSize, SelectState, SeparatorOrientation, SpeedDialAction, SpeedDialColor, SpeedDialDirection, SpeedDialTrigger, SpeedDialType, StepState, StepperBreakpoint, StepperOrientation, StepperVariant, TabsSize, TabsVariant, TagInputSize, TextareaState, TimeObject, TimepickerFormat, TimepickerSize, TimepickerState, Toast, ToastConfig, ToastPosition, ToggleColor, TogglePosition, ToggleSize, UploadStatus, YearCell };
|
|
6749
8318
|
//# sourceMappingURL=edmicro-olkit.d.ts.map
|