@sd-angular/core 19.0.0-beta.36 → 19.0.0-beta.38
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/assets/scss/core/bootstrap.scss +17 -0
- package/assets/scss/core/grid.scss +40 -0
- package/assets/scss/sd-core.scss +1 -0
- package/components/avatar/src/avatar.component.d.ts +2 -1
- package/components/button/src/button.component.d.ts +26 -27
- package/components/document-builder/index.d.ts +1 -0
- package/components/document-builder/src/document-builder.component.d.ts +3 -42
- package/components/document-builder/src/document-builder.model.d.ts +3 -14
- package/components/document-builder/src/plugins/ck-comment/ck-comment.plugin.d.ts +43 -0
- package/components/document-builder/src/plugins/ck-comment/ck-comment.plugin.model.d.ts +50 -0
- package/components/document-builder/src/plugins/index.d.ts +2 -1
- package/components/table/src/components/selector-action/action-filter.pipe.d.ts +11 -10
- package/components/table/src/models/table-option-selector.model.d.ts +11 -10
- package/fesm2022/sd-angular-core-components-avatar.mjs +15 -13
- package/fesm2022/sd-angular-core-components-avatar.mjs.map +1 -1
- package/fesm2022/sd-angular-core-components-button.mjs +63 -96
- package/fesm2022/sd-angular-core-components-button.mjs.map +1 -1
- package/fesm2022/sd-angular-core-components-document-builder.mjs +729 -255
- package/fesm2022/sd-angular-core-components-document-builder.mjs.map +1 -1
- package/fesm2022/sd-angular-core-components-import-excel.mjs +1 -1
- package/fesm2022/sd-angular-core-components-import-excel.mjs.map +1 -1
- package/fesm2022/sd-angular-core-components-preview.mjs +1 -1
- package/fesm2022/sd-angular-core-components-preview.mjs.map +1 -1
- package/fesm2022/sd-angular-core-components-table.mjs +6 -6
- package/fesm2022/sd-angular-core-components-table.mjs.map +1 -1
- package/fesm2022/sd-angular-core-components-upload-file.mjs +1 -1
- package/fesm2022/sd-angular-core-components-upload-file.mjs.map +1 -1
- package/fesm2022/sd-angular-core-components-workflow.mjs +11 -11
- package/fesm2022/sd-angular-core-components-workflow.mjs.map +1 -1
- package/fesm2022/sd-angular-core-modules-layout.mjs +3 -3
- package/fesm2022/sd-angular-core-modules-layout.mjs.map +1 -1
- package/fesm2022/sd-angular-core-services-confirm.mjs +1 -1
- package/fesm2022/sd-angular-core-services-confirm.mjs.map +1 -1
- package/package.json +52 -52
- package/sd-angular-core-19.0.0-beta.38.tgz +0 -0
- package/utilities/models/index.d.ts +1 -0
- package/utilities/models/src/unwrap-signal.model.d.ts +6 -0
- package/components/document-builder/src/plugins/comment/comment.plugin.d.ts +0 -4
- package/sd-angular-core-19.0.0-beta.36.tgz +0 -0
|
@@ -81,6 +81,23 @@
|
|
|
81
81
|
.fs-#{$i} {
|
|
82
82
|
font-size: #{$i}px !important;
|
|
83
83
|
}
|
|
84
|
+
|
|
85
|
+
// Gap
|
|
86
|
+
.gap-#{$i} {
|
|
87
|
+
gap: #{$i}px !important;
|
|
88
|
+
}
|
|
89
|
+
|
|
90
|
+
.gap-y-#{$i} {
|
|
91
|
+
row-gap: #{$i}px !important;
|
|
92
|
+
}
|
|
93
|
+
|
|
94
|
+
.gap-x-#{$i} {
|
|
95
|
+
column-gap: #{$i}px !important;
|
|
96
|
+
}
|
|
97
|
+
}
|
|
98
|
+
|
|
99
|
+
.flex-1 {
|
|
100
|
+
flex: 1;
|
|
84
101
|
}
|
|
85
102
|
|
|
86
103
|
.w-full {
|
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
/* ==========================================================================
|
|
2
|
+
CSS GRID UTILITIES
|
|
3
|
+
========================================================================== */
|
|
4
|
+
|
|
5
|
+
/* 1. Kích hoạt Grid cơ bản */
|
|
6
|
+
.sd-grid-container {
|
|
7
|
+
display: grid;
|
|
8
|
+
column-gap: 8px;
|
|
9
|
+
row-gap: 0px;
|
|
10
|
+
|
|
11
|
+
/* 2. Định nghĩa tổng số cột của Grid Cha (từ 1 đến 12 cột) */
|
|
12
|
+
@for $i from 1 through 12 {
|
|
13
|
+
&.grid-cols-#{$i} {
|
|
14
|
+
/* Dùng minmax(0, 1fr) thay vì 1fr để chống vỡ layout khi nội dung text quá dài */
|
|
15
|
+
grid-template-columns: repeat($i, minmax(0, 1fr));
|
|
16
|
+
}
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
/* 3. Tiện ích chiếm CỘT (Column Spanning) cho phần tử con */
|
|
20
|
+
@for $i from 1 through 12 {
|
|
21
|
+
.col-span-#{$i} {
|
|
22
|
+
grid-column: span #{$i} / span #{$i};
|
|
23
|
+
}
|
|
24
|
+
}
|
|
25
|
+
/* Chiếm toàn bộ số cột hiện có (Full width) */
|
|
26
|
+
.col-span-full {
|
|
27
|
+
grid-column: 1 / -1;
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
/* 4. Tiện ích chiếm HÀNG (Row Spanning) cho phần tử con */
|
|
31
|
+
@for $i from 1 through 12 {
|
|
32
|
+
.row-span-#{$i} {
|
|
33
|
+
grid-row: span #{$i} / span #{$i};
|
|
34
|
+
}
|
|
35
|
+
}
|
|
36
|
+
/* Chiếm toàn bộ hàng (Full height) */
|
|
37
|
+
.row-span-full {
|
|
38
|
+
grid-row: 1 / -1;
|
|
39
|
+
}
|
|
40
|
+
}
|
package/assets/scss/sd-core.scss
CHANGED
|
@@ -4,11 +4,12 @@ export declare class SdAvatar implements OnInit {
|
|
|
4
4
|
#private;
|
|
5
5
|
src: string | undefined | null;
|
|
6
6
|
size: number;
|
|
7
|
+
name: string;
|
|
7
8
|
isUrl: boolean;
|
|
8
9
|
initials: string;
|
|
9
10
|
bgColor: string;
|
|
10
11
|
ngOnInit(): void;
|
|
11
12
|
handleError(): void;
|
|
12
13
|
static ɵfac: i0.ɵɵFactoryDeclaration<SdAvatar, never>;
|
|
13
|
-
static ɵcmp: i0.ɵɵComponentDeclaration<SdAvatar, "sd-avatar", never, { "src": { "alias": "src"; "required": true; }; "size": { "alias": "size"; "required": false; }; }, {}, never, never, true, never>;
|
|
14
|
+
static ɵcmp: i0.ɵɵComponentDeclaration<SdAvatar, "sd-avatar", never, { "src": { "alias": "src"; "required": true; }; "size": { "alias": "size"; "required": false; }; "name": { "alias": "name"; "required": false; }; }, {}, never, never, true, never>;
|
|
14
15
|
}
|
|
@@ -1,39 +1,38 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { OnDestroy, OnInit } from '@angular/core';
|
|
2
2
|
import { SdBaseSecureComponent } from '@sd-angular/core/components/base';
|
|
3
3
|
import { SdColor } from '@sd-angular/core/utilities/models';
|
|
4
4
|
import * as i0 from "@angular/core";
|
|
5
|
+
export type SdButtonFontSet = 'material-icons' | 'material-icons-outlined' | 'material-icons-round' | 'material-icons-sharp' | 'material-symbols-outlined';
|
|
6
|
+
export type SdButtonType = 'fill' | 'light' | 'outline' | 'link';
|
|
7
|
+
export type SdButtonSize = 'sm' | 'md' | 'lg';
|
|
5
8
|
export declare class SdButton extends SdBaseSecureComponent implements OnInit, OnDestroy {
|
|
6
9
|
#private;
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
type:
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
title: string |
|
|
14
|
-
width: string |
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
get disabledAttr(): "true" | null;
|
|
23
|
-
set _disabled(value: '' | boolean | undefined | null);
|
|
24
|
-
loading: boolean;
|
|
25
|
-
click: EventEmitter<Event>;
|
|
26
|
-
constructor();
|
|
27
|
-
ngOnInit(): void;
|
|
28
|
-
onInternalClick(event: Event): void;
|
|
29
|
-
ngOnDestroy(): void;
|
|
30
|
-
get buttonClasses(): {
|
|
10
|
+
private el;
|
|
11
|
+
autoIdInput: import("@angular/core").InputSignal<string | null | undefined>;
|
|
12
|
+
type: import("@angular/core").InputSignalWithTransform<SdButtonType, SdButtonType | null | undefined>;
|
|
13
|
+
color: import("@angular/core").InputSignalWithTransform<SdColor, SdColor | null | undefined>;
|
|
14
|
+
size: import("@angular/core").InputSignalWithTransform<SdButtonSize, SdButtonSize | null | undefined>;
|
|
15
|
+
fontSet: import("@angular/core").InputSignalWithTransform<SdButtonFontSet, SdButtonFontSet | null | undefined>;
|
|
16
|
+
title: import("@angular/core").InputSignal<string | null | undefined>;
|
|
17
|
+
width: import("@angular/core").InputSignal<string | null | undefined>;
|
|
18
|
+
tooltip: import("@angular/core").InputSignal<string | null | undefined>;
|
|
19
|
+
prefixIcon: import("@angular/core").InputSignal<string | null | undefined>;
|
|
20
|
+
suffixIcon: import("@angular/core").InputSignal<string | null | undefined>;
|
|
21
|
+
disabled: import("@angular/core").InputSignalWithTransform<boolean, unknown>;
|
|
22
|
+
loading: import("@angular/core").InputSignalWithTransform<boolean, unknown>;
|
|
23
|
+
autoId: import("@angular/core").Signal<string | undefined>;
|
|
24
|
+
buttonClasses: import("@angular/core").Signal<{
|
|
31
25
|
'c-square': boolean | "" | null | undefined;
|
|
32
26
|
'c-sm': boolean;
|
|
33
27
|
'c-md': boolean;
|
|
34
28
|
'c-lg': boolean;
|
|
35
29
|
'c-disabled': boolean;
|
|
36
|
-
}
|
|
30
|
+
}>;
|
|
31
|
+
click: import("@angular/core").OutputEmitterRef<Event>;
|
|
32
|
+
constructor();
|
|
33
|
+
ngOnInit(): void;
|
|
34
|
+
onInternalClick(event: Event): void;
|
|
35
|
+
ngOnDestroy(): void;
|
|
37
36
|
static ɵfac: i0.ɵɵFactoryDeclaration<SdButton, never>;
|
|
38
|
-
static ɵcmp: i0.ɵɵComponentDeclaration<SdButton, "sd-button", never, { "
|
|
37
|
+
static ɵcmp: i0.ɵɵComponentDeclaration<SdButton, "sd-button", never, { "autoIdInput": { "alias": "autoId"; "required": false; "isSignal": true; }; "type": { "alias": "type"; "required": false; "isSignal": true; }; "color": { "alias": "color"; "required": false; "isSignal": true; }; "size": { "alias": "size"; "required": false; "isSignal": true; }; "fontSet": { "alias": "fontSet"; "required": false; "isSignal": true; }; "title": { "alias": "title"; "required": false; "isSignal": true; }; "width": { "alias": "width"; "required": false; "isSignal": true; }; "tooltip": { "alias": "tooltip"; "required": false; "isSignal": true; }; "prefixIcon": { "alias": "prefixIcon"; "required": false; "isSignal": true; }; "suffixIcon": { "alias": "suffixIcon"; "required": false; "isSignal": true; }; "disabled": { "alias": "disabled"; "required": false; "isSignal": true; }; "loading": { "alias": "loading"; "required": false; "isSignal": true; }; }, { "click": "click"; }, never, never, true, never>;
|
|
39
38
|
}
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import { EventEmitter } from '@angular/core';
|
|
2
2
|
import { ClassicEditor, ModelRange } from 'ckeditor5';
|
|
3
|
-
import {
|
|
3
|
+
import { CkCommentPlugin } from './plugins';
|
|
4
|
+
import { SdDocumentBuilderHeading, SdDocumentBuilderOption, SdDocumentBuilderVariable, SdEditorConfig } from './document-builder.model';
|
|
4
5
|
import * as i0 from "@angular/core";
|
|
5
6
|
export declare class SdDocumentBuilder {
|
|
6
7
|
#private;
|
|
@@ -30,47 +31,7 @@ export declare class SdDocumentBuilder {
|
|
|
30
31
|
*/
|
|
31
32
|
scroll: (id: string) => void;
|
|
32
33
|
};
|
|
33
|
-
|
|
34
|
-
/**
|
|
35
|
-
* Lấy tất cả comments trong document
|
|
36
|
-
* @returns Danh sách tất cả comments
|
|
37
|
-
*/
|
|
38
|
-
all: () => SdDocumentBuilderComment[];
|
|
39
|
-
/**
|
|
40
|
-
* Thêm comment vào vùng text đang được chọn
|
|
41
|
-
* @param comment - Dữ liệu comment
|
|
42
|
-
* @param data - Dữ liệu extra data
|
|
43
|
-
* @returns SdDocumentBuilderComment hoặc null nếu không có text được chọn
|
|
44
|
-
*/
|
|
45
|
-
add: <T = any>(range: ModelRange, comment: string, args?: {
|
|
46
|
-
markerIdExternal?: string | number;
|
|
47
|
-
data?: T;
|
|
48
|
-
}) => SdDocumentBuilderComment<T> | null;
|
|
49
|
-
/**
|
|
50
|
-
* Cập nhật nội dung comment
|
|
51
|
-
* @param markerId - ID của marker
|
|
52
|
-
* @param commentData - Dữ liệu mới
|
|
53
|
-
* @returns Comment đã cập nhật hoặc null
|
|
54
|
-
*/
|
|
55
|
-
update: <T = any>(markerId: string, comment: string, data?: T) => SdDocumentBuilderComment<T> | null;
|
|
56
|
-
/**
|
|
57
|
-
* Lấy chi tiết comment theo markerId
|
|
58
|
-
* @param markerId - ID của marker
|
|
59
|
-
* @returns Comment hoặc null
|
|
60
|
-
*/
|
|
61
|
-
detail: (markerId: string) => SdDocumentBuilderComment | null;
|
|
62
|
-
/**
|
|
63
|
-
* Xóa comment theo markerId
|
|
64
|
-
* @param markerId - ID của marker cần xóa
|
|
65
|
-
* @returns true nếu xóa thành công, false nếu không tìm thấy
|
|
66
|
-
*/
|
|
67
|
-
remove: (markerId: string) => boolean;
|
|
68
|
-
/**
|
|
69
|
-
* Scroll đến vị trí comment
|
|
70
|
-
* @param markerId - ID của marker cần scroll tới
|
|
71
|
-
*/
|
|
72
|
-
scroll: (markerId: string) => void;
|
|
73
|
-
};
|
|
34
|
+
getCommentPluginAPI(): CkCommentPlugin | null;
|
|
74
35
|
variable: {
|
|
75
36
|
/**
|
|
76
37
|
* Lấy tất cả variabes trong document
|
|
@@ -1,11 +1,11 @@
|
|
|
1
|
-
import { EditorConfig, EventInfo, ModelDocumentSelection,
|
|
1
|
+
import { EditorConfig, EventInfo, ModelDocumentSelection, ViewDataTransfer } from 'ckeditor5';
|
|
2
|
+
import { CkCommentConfig } from './plugins/ck-comment/ck-comment.plugin.model';
|
|
2
3
|
export type SdEditorConfig = EditorConfig & {
|
|
3
4
|
getOption?: () => SdDocumentBuilderOption;
|
|
4
5
|
};
|
|
5
6
|
export interface SdDocumentBuilderOption {
|
|
6
7
|
onDropVariable?: (variable: SdDocumentBuilderVariable, dropIndex: number) => boolean | Promise<boolean | SdDocumentBuilderVariable>;
|
|
7
|
-
|
|
8
|
-
onSelectComment?: (markerId: string) => void;
|
|
8
|
+
comment?: CkCommentConfig;
|
|
9
9
|
onSelection?: (selection: ModelDocumentSelection, $event: EventInfo<string, unknown>) => void;
|
|
10
10
|
onOrientation?: (orientation: 'PORTRAIT' | 'LANDSCAPE') => void;
|
|
11
11
|
onPaste?: (data: SdPasteEventData) => void | Promise<void>;
|
|
@@ -18,17 +18,6 @@ export interface SdDocumentBuilderVariable<T = any> {
|
|
|
18
18
|
display: string;
|
|
19
19
|
data?: T;
|
|
20
20
|
}
|
|
21
|
-
export interface SdDocumentBuilderSelectedComment {
|
|
22
|
-
range: ModelRange;
|
|
23
|
-
selectedText: string;
|
|
24
|
-
}
|
|
25
|
-
export interface SdDocumentBuilderComment<T = any> {
|
|
26
|
-
markerId: string;
|
|
27
|
-
selectedText: string;
|
|
28
|
-
comment?: string;
|
|
29
|
-
createdAt?: Date;
|
|
30
|
-
data?: T;
|
|
31
|
-
}
|
|
32
21
|
export interface SdDocumentBuilderHeading {
|
|
33
22
|
id: string;
|
|
34
23
|
text: string;
|
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
import { Plugin, ContextualBalloon } from 'ckeditor5';
|
|
2
|
+
import { CkComment, CkCommentConfig, CkCommentColors } from './ck-comment.plugin.model';
|
|
3
|
+
export declare class CkCommentPlugin extends Plugin {
|
|
4
|
+
#private;
|
|
5
|
+
static get pluginName(): string;
|
|
6
|
+
static get requires(): (typeof ContextualBalloon)[];
|
|
7
|
+
static readonly PENDING_MARKER_ID = "__pending_comment__";
|
|
8
|
+
static readonly DEFAULT_SEARCH_RANGE = 5;
|
|
9
|
+
static readonly DEFAULT_COLORS: CkCommentColors;
|
|
10
|
+
init(): void;
|
|
11
|
+
/**
|
|
12
|
+
* Thiết lập config với callbacks
|
|
13
|
+
*/
|
|
14
|
+
setConfig(config: CkCommentConfig): void;
|
|
15
|
+
/**
|
|
16
|
+
* Thêm comment và tạo marker
|
|
17
|
+
*/
|
|
18
|
+
addComment(comment: CkComment): boolean;
|
|
19
|
+
/**
|
|
20
|
+
* Xóa comment theo id
|
|
21
|
+
*/
|
|
22
|
+
removeComment(id: string | number): boolean;
|
|
23
|
+
/**
|
|
24
|
+
* Chọn comment theo id - chỉ thêm class highlight, không bôi đen text
|
|
25
|
+
*/
|
|
26
|
+
selectComment(id: string | number, scrollIntoView?: boolean): void;
|
|
27
|
+
/**
|
|
28
|
+
* Thiết lập tất cả comments (khôi phục từ dữ liệu)
|
|
29
|
+
*/
|
|
30
|
+
setComments(comments: CkComment[]): void;
|
|
31
|
+
/**
|
|
32
|
+
* Lấy tất cả comments
|
|
33
|
+
*/
|
|
34
|
+
get comments(): CkComment[];
|
|
35
|
+
/**
|
|
36
|
+
* Thiết lập pending highlight cho selection (khi user đang nhập nội dung comment)
|
|
37
|
+
*/
|
|
38
|
+
setPendingSelection(startPath: number[], endPath: number[]): boolean;
|
|
39
|
+
/**
|
|
40
|
+
* Xóa pending highlight và fire onCancelPending callback
|
|
41
|
+
*/
|
|
42
|
+
clearPendingSelection(): void;
|
|
43
|
+
}
|
|
@@ -0,0 +1,50 @@
|
|
|
1
|
+
import { ModelRange } from 'ckeditor5';
|
|
2
|
+
/**
|
|
3
|
+
* Comment status based on text changes
|
|
4
|
+
*/
|
|
5
|
+
export type CkCommentStatus = 'normal' | 'modified' | 'broken';
|
|
6
|
+
/**
|
|
7
|
+
* Color configuration for comment markers
|
|
8
|
+
*/
|
|
9
|
+
export interface CkCommentColors {
|
|
10
|
+
marker?: string;
|
|
11
|
+
markerSelected?: string;
|
|
12
|
+
markerPending?: string;
|
|
13
|
+
markerModified?: string;
|
|
14
|
+
markerBroken?: string;
|
|
15
|
+
}
|
|
16
|
+
/**
|
|
17
|
+
* Comment data structure for CkCommentPlugin
|
|
18
|
+
*/
|
|
19
|
+
export interface CkComment<T = any> {
|
|
20
|
+
id: string | number;
|
|
21
|
+
startPath: number[];
|
|
22
|
+
endPath: number[];
|
|
23
|
+
originalText: string;
|
|
24
|
+
currentText: string;
|
|
25
|
+
status: CkCommentStatus;
|
|
26
|
+
data?: T;
|
|
27
|
+
}
|
|
28
|
+
/**
|
|
29
|
+
* Config for CkCommentPlugin
|
|
30
|
+
*/
|
|
31
|
+
export interface CkCommentConfig {
|
|
32
|
+
onPendingComment?: (comment: CkComment) => void;
|
|
33
|
+
onAddComment?: (comment: CkComment) => void;
|
|
34
|
+
onSelectComment?: (id: string | number) => void;
|
|
35
|
+
onRemoveComment?: (id: string | number) => void;
|
|
36
|
+
onChange?: (comments: CkComment[]) => void;
|
|
37
|
+
onCancelPending?: () => void;
|
|
38
|
+
searchRange?: number;
|
|
39
|
+
debug?: boolean;
|
|
40
|
+
colors?: CkCommentColors;
|
|
41
|
+
}
|
|
42
|
+
/**
|
|
43
|
+
* Data returned when user selects text for comment
|
|
44
|
+
*/
|
|
45
|
+
export interface CkCommentSelection {
|
|
46
|
+
range: ModelRange;
|
|
47
|
+
startPath: number[];
|
|
48
|
+
endPath: number[];
|
|
49
|
+
text: string;
|
|
50
|
+
}
|
|
@@ -1,5 +1,4 @@
|
|
|
1
1
|
export * from './heading/heading.plugin';
|
|
2
|
-
export * from './comment/comment.plugin';
|
|
3
2
|
export * from './variable/variable.plugin';
|
|
4
3
|
export * from './table-custom';
|
|
5
4
|
export * from './image-upload/image-upload.plugin';
|
|
@@ -8,3 +7,5 @@ export * from './page-orientation/page-orientation.plugin';
|
|
|
8
7
|
export * from './paste-handler';
|
|
9
8
|
export * from './highlight-range/highlight-range.plugin';
|
|
10
9
|
export * from './block-space/block-space.plugin';
|
|
10
|
+
export * from './ck-comment/ck-comment.plugin';
|
|
11
|
+
export * from './ck-comment/ck-comment.plugin.model';
|
|
@@ -2,6 +2,7 @@ import { PipeTransform } from '@angular/core';
|
|
|
2
2
|
import { SdTableAction } from '../../models/table-option-selector.model';
|
|
3
3
|
import { SdTableItem } from '../../models/table-item.model';
|
|
4
4
|
import { SdButton } from '@sd-angular/core/components/button';
|
|
5
|
+
import { SdUnwrapSignal } from '@sd-angular/core/utilities/models';
|
|
5
6
|
import * as i0 from "@angular/core";
|
|
6
7
|
export declare class ActionFilterPipe implements PipeTransform {
|
|
7
8
|
#private;
|
|
@@ -13,21 +14,21 @@ export type Action<T = any> = ActionNormal<T> | ActionChildren<T>;
|
|
|
13
14
|
interface ActionNormal<T = any> {
|
|
14
15
|
variant: 'normal';
|
|
15
16
|
icon?: string;
|
|
16
|
-
fontSet?: SdButton['fontSet']
|
|
17
|
-
tooltip?: SdButton['tooltip']
|
|
18
|
-
title?: SdButton['title']
|
|
19
|
-
color?: SdButton['color']
|
|
20
|
-
type?: SdButton['type']
|
|
17
|
+
fontSet?: SdUnwrapSignal<SdButton['fontSet']>;
|
|
18
|
+
tooltip?: SdUnwrapSignal<SdButton['tooltip']>;
|
|
19
|
+
title?: SdUnwrapSignal<SdButton['title']>;
|
|
20
|
+
color?: SdUnwrapSignal<SdButton['color']>;
|
|
21
|
+
type?: SdUnwrapSignal<SdButton['type']>;
|
|
21
22
|
click: (selectedItems?: T[]) => void;
|
|
22
23
|
}
|
|
23
24
|
interface ActionChildren<T = any> {
|
|
24
25
|
variant: 'children';
|
|
25
26
|
icon?: string;
|
|
26
|
-
fontSet?: SdButton['fontSet']
|
|
27
|
-
tooltip?: SdButton['tooltip']
|
|
28
|
-
title?: SdButton['title']
|
|
29
|
-
color?: SdButton['color']
|
|
30
|
-
type?: SdButton['type']
|
|
27
|
+
fontSet?: SdUnwrapSignal<SdButton['fontSet']>;
|
|
28
|
+
tooltip?: SdUnwrapSignal<SdButton['tooltip']>;
|
|
29
|
+
title?: SdUnwrapSignal<SdButton['title']>;
|
|
30
|
+
color?: SdUnwrapSignal<SdButton['color']>;
|
|
31
|
+
type?: SdUnwrapSignal<SdButton['type']>;
|
|
31
32
|
children: ActionNormal<T>[];
|
|
32
33
|
}
|
|
33
34
|
export {};
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import { SdButton } from '@sd-angular/core/components/button';
|
|
2
|
+
import { SdUnwrapSignal } from '@sd-angular/core/utilities/models';
|
|
2
3
|
export interface SdTableOptionSelector<T = any> {
|
|
3
4
|
visible?: boolean;
|
|
4
5
|
single?: boolean;
|
|
@@ -11,22 +12,22 @@ export interface SdTableOptionSelector<T = any> {
|
|
|
11
12
|
export type SdTableAction<T = any> = SdTableActionNormal<T> | SdTableActionChildren<T>;
|
|
12
13
|
export interface SdTableActionNormal<T = any> {
|
|
13
14
|
icon?: string;
|
|
14
|
-
fontSet?: SdButton['fontSet']
|
|
15
|
-
tooltip?: SdButton['tooltip']
|
|
16
|
-
title?: SdButton['title']
|
|
17
|
-
color?: SdButton['color']
|
|
18
|
-
type?: SdButton['type']
|
|
15
|
+
fontSet?: SdUnwrapSignal<SdButton['fontSet']>;
|
|
16
|
+
tooltip?: SdUnwrapSignal<SdButton['tooltip']>;
|
|
17
|
+
title?: SdUnwrapSignal<SdButton['title']>;
|
|
18
|
+
color?: SdUnwrapSignal<SdButton['color']>;
|
|
19
|
+
type?: SdUnwrapSignal<SdButton['type']>;
|
|
19
20
|
hidden?: boolean | ((rowData?: T) => boolean);
|
|
20
21
|
isGrouped?: boolean;
|
|
21
22
|
click: (selectedItems?: T[]) => void;
|
|
22
23
|
}
|
|
23
24
|
interface SdTableActionChildren<T = any> {
|
|
24
25
|
icon?: string;
|
|
25
|
-
fontSet?: SdButton['fontSet']
|
|
26
|
-
tooltip?: SdButton['tooltip']
|
|
27
|
-
title?: SdButton['title']
|
|
28
|
-
color?: SdButton['color']
|
|
29
|
-
type?: SdButton['type']
|
|
26
|
+
fontSet?: SdUnwrapSignal<SdButton['fontSet']>;
|
|
27
|
+
tooltip?: SdUnwrapSignal<SdButton['tooltip']>;
|
|
28
|
+
title?: SdUnwrapSignal<SdButton['title']>;
|
|
29
|
+
color?: SdUnwrapSignal<SdButton['color']>;
|
|
30
|
+
type?: SdUnwrapSignal<SdButton['type']>;
|
|
30
31
|
hidden?: boolean | ((rowData?: T) => boolean);
|
|
31
32
|
isGrouped?: boolean;
|
|
32
33
|
children: SdTableActionNormal<T>[];
|
|
@@ -5,6 +5,7 @@ import { Input, ChangeDetectionStrategy, Component } from '@angular/core';
|
|
|
5
5
|
class SdAvatar {
|
|
6
6
|
src;
|
|
7
7
|
size = 32;
|
|
8
|
+
name = '';
|
|
8
9
|
isUrl = false;
|
|
9
10
|
initials = '';
|
|
10
11
|
bgColor = '#ccc';
|
|
@@ -12,18 +13,16 @@ class SdAvatar {
|
|
|
12
13
|
this.#init();
|
|
13
14
|
}
|
|
14
15
|
#init = () => {
|
|
15
|
-
if (!this.src) {
|
|
16
|
-
this.isUrl = false;
|
|
17
|
-
this.initials = '?';
|
|
18
|
-
this.bgColor = '#bdc3c7';
|
|
19
|
-
return;
|
|
20
|
-
}
|
|
21
16
|
// Kiểm tra xem src có phải là URL (http, https, data:image, hoặc path /)
|
|
22
17
|
const urlPattern = /^(http|https|data:image|\/)/;
|
|
23
|
-
this.isUrl = urlPattern.test(this.src);
|
|
24
|
-
if (!this.isUrl) {
|
|
25
|
-
this.
|
|
26
|
-
this.
|
|
18
|
+
this.isUrl = urlPattern.test(this.src || '');
|
|
19
|
+
if (this.name || !this.isUrl) {
|
|
20
|
+
this.bgColor = this.#generateColor(this.name || this.src || '');
|
|
21
|
+
this.initials = this.#getInitials(this.name || this.src || '');
|
|
22
|
+
}
|
|
23
|
+
else {
|
|
24
|
+
this.bgColor = '#bdc3c7';
|
|
25
|
+
this.initials = '?';
|
|
27
26
|
}
|
|
28
27
|
};
|
|
29
28
|
handleError() {
|
|
@@ -31,13 +30,14 @@ class SdAvatar {
|
|
|
31
30
|
this.#init();
|
|
32
31
|
}
|
|
33
32
|
#getInitials = (name) => {
|
|
34
|
-
return name
|
|
33
|
+
return (name
|
|
35
34
|
.trim()
|
|
36
35
|
.split(' ')
|
|
36
|
+
.filter(Boolean)
|
|
37
37
|
.map(n => n[0])
|
|
38
38
|
.join('')
|
|
39
39
|
.toUpperCase()
|
|
40
|
-
.substring(0, 2);
|
|
40
|
+
.substring(0, 2) || '');
|
|
41
41
|
};
|
|
42
42
|
#generateColor = (name) => {
|
|
43
43
|
const colors = [
|
|
@@ -68,7 +68,7 @@ class SdAvatar {
|
|
|
68
68
|
return colors[Math.abs(hash) % colors.length];
|
|
69
69
|
};
|
|
70
70
|
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "19.2.17", ngImport: i0, type: SdAvatar, deps: [], target: i0.ɵɵFactoryTarget.Component });
|
|
71
|
-
static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "19.2.17", type: SdAvatar, isStandalone: true, selector: "sd-avatar", inputs: { src: "src", size: "size" }, ngImport: i0, template: "<div class=\"sd-avatar\" [style.width.px]=\"size\" [style.height.px]=\"size\" [style.line-height.px]=\"size\" [style.backgroundColor]=\"bgColor\">\r\n @if (isUrl) {\r\n <img [src]=\"src\" (error)=\"handleError()\" alt=\"avatar\" />\r\n } @else {\r\n <span class=\"sd-avatar-text\" [style.fontSize.px]=\"size / 2.5\">\r\n {{ initials }}\r\n </span>\r\n }\r\n</div>\r\n", styles: [".sd-avatar{display:inline-flex;align-items:center;justify-content:center;border-radius:50%;overflow:hidden;color:#fff;font-weight:500;-webkit-user-select:none;user-select:none;background-size:cover}.sd-avatar img{width:100%;height:100%;object-fit:cover}\n"], dependencies: [{ kind: "ngmodule", type: CommonModule }], changeDetection: i0.ChangeDetectionStrategy.OnPush });
|
|
71
|
+
static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "19.2.17", type: SdAvatar, isStandalone: true, selector: "sd-avatar", inputs: { src: "src", size: "size", name: "name" }, ngImport: i0, template: "<div class=\"sd-avatar\" [style.width.px]=\"size\" [style.height.px]=\"size\" [style.line-height.px]=\"size\" [style.backgroundColor]=\"bgColor\">\r\n @if (isUrl) {\r\n <img [src]=\"src\" (error)=\"handleError()\" alt=\"avatar\" />\r\n } @else {\r\n <span class=\"sd-avatar-text\" [style.fontSize.px]=\"size / 2.5\">\r\n {{ initials }}\r\n </span>\r\n }\r\n</div>\r\n", styles: [".sd-avatar{display:inline-flex;align-items:center;justify-content:center;border-radius:50%;overflow:hidden;color:#fff;font-weight:500;-webkit-user-select:none;user-select:none;background-size:cover}.sd-avatar img{width:100%;height:100%;object-fit:cover}\n"], dependencies: [{ kind: "ngmodule", type: CommonModule }], changeDetection: i0.ChangeDetectionStrategy.OnPush });
|
|
72
72
|
}
|
|
73
73
|
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.2.17", ngImport: i0, type: SdAvatar, decorators: [{
|
|
74
74
|
type: Component,
|
|
@@ -78,6 +78,8 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.2.17", ngImpo
|
|
|
78
78
|
args: [{ required: true }]
|
|
79
79
|
}], size: [{
|
|
80
80
|
type: Input
|
|
81
|
+
}], name: [{
|
|
82
|
+
type: Input
|
|
81
83
|
}] } });
|
|
82
84
|
|
|
83
85
|
/**
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"sd-angular-core-components-avatar.mjs","sources":["../../../projects/sd-angular/components/avatar/src/avatar.component.ts","../../../projects/sd-angular/components/avatar/src/avatar.component.html","../../../projects/sd-angular/components/avatar/sd-angular-core-components-avatar.ts"],"sourcesContent":["import { CommonModule } from '@angular/common';\r\nimport { ChangeDetectionStrategy, Component, Input,
|
|
1
|
+
{"version":3,"file":"sd-angular-core-components-avatar.mjs","sources":["../../../projects/sd-angular/components/avatar/src/avatar.component.ts","../../../projects/sd-angular/components/avatar/src/avatar.component.html","../../../projects/sd-angular/components/avatar/sd-angular-core-components-avatar.ts"],"sourcesContent":["import { CommonModule } from '@angular/common';\r\nimport { ChangeDetectionStrategy, Component, Input, OnInit } from '@angular/core';\r\n\r\n@Component({\r\n selector: 'sd-avatar',\r\n standalone: true,\r\n imports: [CommonModule],\r\n templateUrl: './avatar.component.html',\r\n styleUrls: ['./avatar.component.scss'],\r\n changeDetection: ChangeDetectionStrategy.OnPush,\r\n})\r\nexport class SdAvatar implements OnInit {\r\n @Input({ required: true }) src: string | undefined | null;\r\n @Input() size: number = 32;\r\n @Input() name: string = '';\r\n\r\n isUrl: boolean = false;\r\n initials: string = '';\r\n bgColor: string = '#ccc';\r\n\r\n ngOnInit(): void {\r\n this.#init();\r\n }\r\n\r\n #init = () => {\r\n // Kiểm tra xem src có phải là URL (http, https, data:image, hoặc path /)\r\n const urlPattern = /^(http|https|data:image|\\/)/;\r\n this.isUrl = urlPattern.test(this.src || '');\r\n if (this.name || !this.isUrl) {\r\n this.bgColor = this.#generateColor(this.name || this.src || '');\r\n this.initials = this.#getInitials(this.name || this.src || '');\r\n } else {\r\n this.bgColor = '#bdc3c7';\r\n this.initials = '?';\r\n }\r\n };\r\n\r\n handleError() {\r\n this.src = undefined; // Nếu ảnh lỗi, chuyển sang hiển thị initials\r\n this.#init();\r\n }\r\n\r\n #getInitials = (name: string): string => {\r\n return (\r\n name\r\n .trim()\r\n .split(' ')\r\n .filter(Boolean)\r\n .map(n => n[0])\r\n .join('')\r\n .toUpperCase()\r\n .substring(0, 2) || ''\r\n );\r\n };\r\n\r\n #generateColor = (name: string): string => {\r\n const colors = [\r\n '#1abc9c',\r\n '#2ecc71',\r\n '#3498db',\r\n '#9b59b6',\r\n '#34495e',\r\n '#16a085',\r\n '#27ae60',\r\n '#2980b9',\r\n '#8e44ad',\r\n '#2c3e50',\r\n '#f1c40f',\r\n '#e67e22',\r\n '#e74c3c',\r\n '#95a5a6',\r\n '#f39c12',\r\n '#d35400',\r\n '#c0392b',\r\n '#bdc3c7',\r\n '#7f8c8d',\r\n ];\r\n let hash = 0;\r\n for (let i = 0; i < name.length; i++) {\r\n hash = name.charCodeAt(i) + ((hash << 5) - hash);\r\n }\r\n return colors[Math.abs(hash) % colors.length];\r\n };\r\n}\r\n","<div class=\"sd-avatar\" [style.width.px]=\"size\" [style.height.px]=\"size\" [style.line-height.px]=\"size\" [style.backgroundColor]=\"bgColor\">\r\n @if (isUrl) {\r\n <img [src]=\"src\" (error)=\"handleError()\" alt=\"avatar\" />\r\n } @else {\r\n <span class=\"sd-avatar-text\" [style.fontSize.px]=\"size / 2.5\">\r\n {{ initials }}\r\n </span>\r\n }\r\n</div>\r\n","/**\n * Generated bundle index. Do not edit.\n */\n\nexport * from './index';\n"],"names":[],"mappings":"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"}
|