@sd-angular/core 19.0.0-beta.61 → 19.0.0-beta.63

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.
@@ -5,80 +5,96 @@
5
5
  // --------------------------------------------------
6
6
  // Palette M2 — generated từ hex color
7
7
  // --------------------------------------------------
8
- $custom-primary-palette: mat.m2-define-palette((
9
- 50: #F0F1F5,
10
- 100: #D7DCEA,
11
- 200: #ABBCE3,
12
- 300: #6E90E3,
13
- 400: #346AEA,
14
- 500: #2A66F4,
15
- 600: #0645DB,
16
- 700: #0131A3,
17
- 800: #00216D,
18
- 900: #001546,
19
- contrast: (
20
- 400: white,
21
- 500: white,
22
- 600: white,
23
- 700: white,
24
- 800: white,
25
- 900: white,
8
+ $custom-primary-palette: mat.m2-define-palette(
9
+ (
10
+ 50: #f0f1f5,
11
+ 100: #d7dcea,
12
+ 200: #abbce3,
13
+ 300: #6e90e3,
14
+ 400: #346aea,
15
+ 500: #2a66f4,
16
+ 600: #0645db,
17
+ 700: #0131a3,
18
+ 800: #00216d,
19
+ 900: #001546,
20
+ contrast: (
21
+ 400: white,
22
+ 500: white,
23
+ 600: white,
24
+ 700: white,
25
+ 800: white,
26
+ 900: white,
27
+ ),
26
28
  )
27
- ));
29
+ );
28
30
 
29
- $custom-accent-palette: mat.m2-define-palette((
30
- 50: #F1F3F1,
31
- 100: #DCE5DD,
32
- 200: #BBD3BC,
33
- 300: #8FC291,
34
- 400: #67B76A,
35
- 500: #4CAF50,
36
- 600: #3A8C3D,
37
- 700: #29692C,
38
- 800: #1C471E,
39
- 900: #132F14,
40
- contrast: (
41
- 700: white,
42
- 800: white,
43
- 900: white,
31
+ $custom-accent-palette: mat.m2-define-palette(
32
+ (
33
+ 50: #f1f3f1,
34
+ 100: #dce5dd,
35
+ 200: #bbd3bc,
36
+ 300: #8fc291,
37
+ 400: #67b76a,
38
+ 500: #4caf50,
39
+ 600: #3a8c3d,
40
+ 700: #29692c,
41
+ 800: #1c471e,
42
+ 900: #132f14,
43
+ contrast: (
44
+ 700: white,
45
+ 800: white,
46
+ 900: white,
47
+ ),
44
48
  )
45
- ));
49
+ );
46
50
 
47
- $custom-warn-palette: mat.m2-define-palette((
48
- 50: #F5F0F0,
49
- 100: #EAD9D6,
50
- 200: #E4B0AA,
51
- 300: #E6786B,
52
- 400: #EE4430,
53
- 500: #F82C13,
54
- 600: #D11801,
55
- 700: #9A1100,
56
- 800: #680B00,
57
- 900: #440700,
58
- contrast: (
59
- 600: white,
60
- 700: white,
61
- 800: white,
62
- 900: white,
51
+ $custom-warn-palette: mat.m2-define-palette(
52
+ (
53
+ 50: #f5f0f0,
54
+ 100: #ead9d6,
55
+ 200: #e4b0aa,
56
+ 300: #e6786b,
57
+ 400: #ee4430,
58
+ 500: #f82c13,
59
+ 600: #d11801,
60
+ 700: #9a1100,
61
+ 800: #680b00,
62
+ 900: #440700,
63
+ contrast: (
64
+ 600: white,
65
+ 700: white,
66
+ 800: white,
67
+ 900: white,
68
+ ),
63
69
  )
64
- ));
70
+ );
71
+
65
72
 
66
73
  // --------------------------------------------------
67
74
  // Theme
68
75
  // --------------------------------------------------
69
- $custom-theme: mat.m2-define-light-theme((
70
- color: (
71
- primary: $custom-primary-palette,
72
- accent: $custom-accent-palette,
73
- warn: $custom-warn-palette,
74
- ),
75
- typography: mat.m2-define-typography-config(
76
- $font-family: 'Roboto',
77
- ),
78
- density: -3,
79
- ));
76
+ $custom-theme: mat.m2-define-light-theme(
77
+ (
78
+ color: (
79
+ primary: $custom-primary-palette,
80
+ accent: $custom-accent-palette,
81
+ warn: $custom-warn-palette,
82
+ ),
83
+ density: -3,
84
+ )
85
+ );
80
86
 
81
87
  @include mat.all-component-themes($custom-theme);
82
88
 
83
89
  // Fix paginator density riêng về 0 để không bị lệch
84
- @include mat.paginator-density(0);
90
+ @include mat.theme(
91
+ (
92
+ color: (
93
+ theme-type: light,
94
+ primary: mat.$azure-palette,
95
+ tertiary: mat.$blue-palette,
96
+ ),
97
+ typography: Roboto,
98
+ density: 0,
99
+ )
100
+ );
@@ -1 +1,2 @@
1
1
  export * from './src/section.component';
2
+ export * from './src/section-item/section-item.component';
@@ -0,0 +1,7 @@
1
+ import * as i0 from "@angular/core";
2
+ export declare class SdSectionItem {
3
+ label: import("@angular/core").InputSignal<string>;
4
+ labelWidth: import("@angular/core").InputSignalWithTransform<string, string | null | undefined>;
5
+ static ɵfac: i0.ɵɵFactoryDeclaration<SdSectionItem, never>;
6
+ static ɵcmp: i0.ɵɵComponentDeclaration<SdSectionItem, "sd-section-item", never, { "label": { "alias": "label"; "required": true; "isSignal": true; }; "labelWidth": { "alias": "labelWidth"; "required": false; "isSignal": true; }; }, {}, never, ["*"], true, never>;
7
+ }
@@ -2,7 +2,7 @@ import { SdBaseSecureComponent } from '@sd-angular/core/components/base';
2
2
  import { SdColor } from '@sd-angular/core/utilities';
3
3
  import * as i0 from "@angular/core";
4
4
  export declare class SdSection extends SdBaseSecureComponent {
5
- private el;
5
+ #private;
6
6
  title: import("@angular/core").InputSignal<string | null>;
7
7
  subTitle: import("@angular/core").InputSignal<string>;
8
8
  icon: import("@angular/core").InputSignal<string | null>;
@@ -10,8 +10,9 @@ export declare class SdSection extends SdBaseSecureComponent {
10
10
  collapsed: import("@angular/core").ModelSignal<boolean>;
11
11
  collapsable: import("@angular/core").InputSignalWithTransform<boolean, unknown>;
12
12
  hideHeader: import("@angular/core").InputSignalWithTransform<boolean, unknown>;
13
+ noPaddingBody: import("@angular/core").InputSignalWithTransform<boolean, unknown>;
13
14
  constructor();
14
15
  toggleCollapse: () => void;
15
16
  static ɵfac: i0.ɵɵFactoryDeclaration<SdSection, never>;
16
- static ɵcmp: i0.ɵɵComponentDeclaration<SdSection, "sd-section", never, { "title": { "alias": "title"; "required": false; "isSignal": true; }; "subTitle": { "alias": "subTitle"; "required": false; "isSignal": true; }; "icon": { "alias": "icon"; "required": false; "isSignal": true; }; "iconColor": { "alias": "iconColor"; "required": false; "isSignal": true; }; "collapsed": { "alias": "collapsed"; "required": false; "isSignal": true; }; "collapsable": { "alias": "collapsable"; "required": false; "isSignal": true; }; "hideHeader": { "alias": "hideHeader"; "required": false; "isSignal": true; }; }, { "collapsed": "collapsedChange"; }, never, ["[sdHeaderLeft]", "[sdHeaderRight]", "*"], true, never>;
17
+ static ɵcmp: i0.ɵɵComponentDeclaration<SdSection, "sd-section", never, { "title": { "alias": "title"; "required": false; "isSignal": true; }; "subTitle": { "alias": "subTitle"; "required": false; "isSignal": true; }; "icon": { "alias": "icon"; "required": false; "isSignal": true; }; "iconColor": { "alias": "iconColor"; "required": false; "isSignal": true; }; "collapsed": { "alias": "collapsed"; "required": false; "isSignal": true; }; "collapsable": { "alias": "collapsable"; "required": false; "isSignal": true; }; "hideHeader": { "alias": "hideHeader"; "required": false; "isSignal": true; }; "noPaddingBody": { "alias": "noPaddingBody"; "required": false; "isSignal": true; }; }, { "collapsed": "collapsedChange"; }, never, ["[sdHeaderLeft]", "[sdHeaderRight]", "*"], true, never>;
17
18
  }
@@ -2,8 +2,6 @@ import { Clipboard } from '@angular/cdk/clipboard';
2
2
  import { CommonModule } from '@angular/common';
3
3
  import * as i0 from '@angular/core';
4
4
  import { inject, model, input, booleanAttribute, signal, computed, effect, untracked, ViewEncapsulation, ChangeDetectionStrategy, Component } from '@angular/core';
5
- import * as i3 from '@angular/forms';
6
- import { FormsModule } from '@angular/forms';
7
5
  import * as i1 from '@angular/material/icon';
8
6
  import { MatIconModule } from '@angular/material/icon';
9
7
  import * as i2 from '@angular/material/tooltip';
@@ -114,11 +112,11 @@ class SdCodeEditor {
114
112
  }
115
113
  }
116
114
  static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "19.2.17", ngImport: i0, type: SdCodeEditor, deps: [], target: i0.ɵɵFactoryTarget.Component });
117
- static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "19.2.17", type: SdCodeEditor, isStandalone: true, selector: "sd-code-editor", inputs: { valueModel: { classPropertyName: "valueModel", publicName: "model", isSignal: true, isRequired: false, transformFunction: null }, language: { classPropertyName: "language", publicName: "language", isSignal: true, isRequired: false, transformFunction: null }, maxHeight: { classPropertyName: "maxHeight", publicName: "maxHeight", isSignal: true, isRequired: false, transformFunction: null }, viewed: { classPropertyName: "viewed", publicName: "viewed", isSignal: true, isRequired: false, transformFunction: null } }, outputs: { valueModel: "modelChange" }, ngImport: i0, template: "<div class=\"sd-code-wrapper\" [class.is-editable]=\"!viewed()\">\r\n \r\n <div class=\"sd-code-header\">\r\n <div class=\"mac-dots\">\r\n <span class=\"dot red\"></span>\r\n <span class=\"dot yellow\"></span>\r\n <span class=\"dot green\"></span>\r\n </div>\r\n \r\n <div class=\"lang-badge\">\r\n {{ language().toUpperCase() }} \r\n <span style=\"opacity: 0.6; margin-left: 4px; font-weight: normal;\">\r\n {{ viewed() ? '(READ ONLY)' : '(EDITING)' }}\r\n </span>\r\n </div>\r\n \r\n <button class=\"copy-btn\" [matTooltip]=\"copied() ? '\u0110\u00E3 copy!' : 'Copy code'\" (click)=\"copyToClipboard()\">\r\n <mat-icon [class.text-success]=\"copied()\">{{ copied() ? 'check' : 'content_copy' }}</mat-icon>\r\n <span>{{ copied() ? 'Copied' : 'Copy' }}</span>\r\n </button>\r\n </div>\r\n\r\n <div class=\"sd-code-content\" [style.maxHeight]=\"maxHeight()\">\r\n <div class=\"editor-overlay-container\">\r\n \r\n @if (!viewed()) {\r\n <textarea \r\n class=\"code-textarea\"\r\n [ngModel]=\"textValue()\"\r\n (ngModelChange)=\"onTextChange($event)\"\r\n spellcheck=\"false\"\r\n autocomplete=\"off\"\r\n autocorrect=\"off\"\r\n autocapitalize=\"off\">\r\n </textarea>\r\n }\r\n \r\n <pre aria-hidden=\"true\" class=\"code-display\"><code [class]=\"'language-' + prismLang()\" [innerHTML]=\"highlightedCode()\"></code></pre>\r\n \r\n </div>\r\n </div>\r\n</div>", styles: ["@charset \"UTF-8\";.sd-code-wrapper{background-color:#1e1e1e;border-radius:8px;overflow:hidden;box-shadow:0 4px 12px #00000026;margin:16px 0;font-family:Fira Code,Consolas,Monaco,monospace}.sd-code-wrapper .sd-code-header{display:flex;align-items:center;justify-content:space-between;background-color:#2d2d2d;padding:8px 16px;border-bottom:1px solid #404040}.sd-code-wrapper .sd-code-header .mac-dots{display:flex;gap:6px}.sd-code-wrapper .sd-code-header .mac-dots .dot{width:12px;height:12px;border-radius:50%}.sd-code-wrapper .sd-code-header .mac-dots .dot.red{background-color:#ff5f56}.sd-code-wrapper .sd-code-header .mac-dots .dot.yellow{background-color:#ffbd2e}.sd-code-wrapper .sd-code-header .mac-dots .dot.green{background-color:#27c93f}.sd-code-wrapper .sd-code-header .lang-badge{color:#858585;font-size:12px;font-weight:600;letter-spacing:.5px}.sd-code-wrapper .sd-code-header .copy-btn{display:flex;align-items:center;gap:4px;background:none;border:none;color:#ccc;cursor:pointer;font-size:13px;padding:4px 8px;border-radius:4px;transition:all .2s ease}.sd-code-wrapper .sd-code-header .copy-btn mat-icon{font-size:16px;width:16px;height:16px}.sd-code-wrapper .sd-code-header .copy-btn:hover{background-color:#404040;color:#fff}.sd-code-wrapper .sd-code-header .copy-btn .text-success{color:#27c93f!important}.sd-code-wrapper .sd-code-content{overflow-y:auto;position:relative}.sd-code-wrapper .sd-code-content::-webkit-scrollbar{width:8px;height:8px}.sd-code-wrapper .sd-code-content::-webkit-scrollbar-thumb{background:#555;border-radius:4px}.sd-code-wrapper .sd-code-content::-webkit-scrollbar-thumb:hover{background:#777}.sd-code-wrapper .sd-code-content::-webkit-scrollbar-track{background:#1e1e1e}.sd-code-wrapper .sd-code-content .editor-overlay-container{position:relative;min-height:100px}.sd-code-wrapper .sd-code-content .code-textarea,.sd-code-wrapper .sd-code-content .code-display{margin:0;padding:16px;border:0;width:100%;min-height:100%;font-family:inherit;font-size:14px;line-height:1.5;white-space:pre-wrap;word-break:break-all;tab-size:2}.sd-code-wrapper .sd-code-content .code-textarea{position:absolute;top:0;left:0;z-index:2;background:transparent;color:transparent;caret-color:#fff;resize:none;outline:none;overflow:hidden}.sd-code-wrapper .sd-code-content .code-display{position:relative;z-index:1;pointer-events:none}.sd-code-wrapper .sd-code-content .code-display code{color:#d4d4d4;font-family:inherit}.sd-code-wrapper .token.comment,.sd-code-wrapper .token.block-comment,.sd-code-wrapper .token.prolog,.sd-code-wrapper .token.doctype,.sd-code-wrapper .token.cdata{color:#999}.sd-code-wrapper .token.punctuation{color:#ccc}.sd-code-wrapper .token.tag,.sd-code-wrapper .token.attr-name,.sd-code-wrapper .token.namespace,.sd-code-wrapper .token.deleted{color:#e2777a}.sd-code-wrapper .token.function-name{color:#6196cc}.sd-code-wrapper .token.boolean,.sd-code-wrapper .token.number,.sd-code-wrapper .token.function{color:#f08d49}.sd-code-wrapper .token.property,.sd-code-wrapper .token.class-name,.sd-code-wrapper .token.constant,.sd-code-wrapper .token.symbol{color:#f8c555}.sd-code-wrapper .token.selector,.sd-code-wrapper .token.important,.sd-code-wrapper .token.atrule,.sd-code-wrapper .token.keyword,.sd-code-wrapper .token.builtin{color:#cc99cd}.sd-code-wrapper .token.string,.sd-code-wrapper .token.char,.sd-code-wrapper .token.attr-value,.sd-code-wrapper .token.regex,.sd-code-wrapper .token.variable{color:#7ec699}.sd-code-wrapper .token.operator,.sd-code-wrapper .token.entity,.sd-code-wrapper .token.url{color:#67cdcc}.sd-code-wrapper .token.important,.sd-code-wrapper .token.bold{font-weight:700}.sd-code-wrapper .token.italic{font-style:italic}.sd-code-wrapper .token.entity{cursor:help}.sd-code-wrapper .token.inserted{color:green}\n"], dependencies: [{ kind: "ngmodule", type: CommonModule }, { kind: "ngmodule", type: MatIconModule }, { kind: "component", type: i1.MatIcon, selector: "mat-icon", inputs: ["color", "inline", "svgIcon", "fontSet", "fontIcon"], exportAs: ["matIcon"] }, { kind: "ngmodule", type: MatTooltipModule }, { kind: "directive", type: i2.MatTooltip, selector: "[matTooltip]", inputs: ["matTooltipPosition", "matTooltipPositionAtOrigin", "matTooltipDisabled", "matTooltipShowDelay", "matTooltipHideDelay", "matTooltipTouchGestures", "matTooltip", "matTooltipClass"], exportAs: ["matTooltip"] }, { kind: "ngmodule", type: FormsModule }, { kind: "directive", type: i3.DefaultValueAccessor, selector: "input:not([type=checkbox])[formControlName],textarea[formControlName],input:not([type=checkbox])[formControl],textarea[formControl],input:not([type=checkbox])[ngModel],textarea[ngModel],[ngDefaultControl]" }, { kind: "directive", type: i3.NgControlStatus, selector: "[formControlName],[ngModel],[formControl]" }, { kind: "directive", type: i3.NgModel, selector: "[ngModel]:not([formControlName]):not([formControl])", inputs: ["name", "disabled", "ngModel", "ngModelOptions"], outputs: ["ngModelChange"], exportAs: ["ngModel"] }], changeDetection: i0.ChangeDetectionStrategy.OnPush, encapsulation: i0.ViewEncapsulation.None });
115
+ static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "19.2.17", type: SdCodeEditor, isStandalone: true, selector: "sd-code-editor", inputs: { valueModel: { classPropertyName: "valueModel", publicName: "model", isSignal: true, isRequired: false, transformFunction: null }, language: { classPropertyName: "language", publicName: "language", isSignal: true, isRequired: false, transformFunction: null }, maxHeight: { classPropertyName: "maxHeight", publicName: "maxHeight", isSignal: true, isRequired: false, transformFunction: null }, viewed: { classPropertyName: "viewed", publicName: "viewed", isSignal: true, isRequired: false, transformFunction: null } }, outputs: { valueModel: "modelChange" }, ngImport: i0, template: "<div class=\"sd-code-wrapper\" [class.is-editable]=\"!viewed()\">\r\n \r\n <div class=\"sd-code-header\">\r\n <div class=\"mac-dots\">\r\n <span class=\"dot red\"></span>\r\n <span class=\"dot yellow\"></span>\r\n <span class=\"dot green\"></span>\r\n </div>\r\n \r\n <div class=\"lang-badge\">\r\n {{ language().toUpperCase() }} \r\n <span style=\"opacity: 0.6; margin-left: 4px; font-weight: normal;\">\r\n {{ viewed() ? '(READ ONLY)' : '(EDITING)' }}\r\n </span>\r\n </div>\r\n \r\n <button class=\"copy-btn\" [matTooltip]=\"copied() ? '\u0110\u00E3 copy!' : 'Copy code'\" (click)=\"copyToClipboard()\">\r\n <mat-icon [class.text-success]=\"copied()\">{{ copied() ? 'check' : 'content_copy' }}</mat-icon>\r\n <span>{{ copied() ? 'Copied' : 'Copy' }}</span>\r\n </button>\r\n </div>\r\n\r\n <div class=\"sd-code-content\" [style.maxHeight]=\"maxHeight()\">\r\n <div class=\"editor-overlay-container\">\r\n \r\n @if (!viewed()) {\r\n <textarea\r\n class=\"code-textarea\"\r\n [value]=\"textValue()\"\r\n (input)=\"onTextChange($any($event.target).value)\"\r\n spellcheck=\"false\"\r\n autocomplete=\"off\"\r\n autocorrect=\"off\"\r\n autocapitalize=\"off\">\r\n </textarea>\r\n }\r\n \r\n <pre aria-hidden=\"true\" class=\"code-display\"><code [class]=\"'language-' + prismLang()\" [innerHTML]=\"highlightedCode()\"></code></pre>\r\n \r\n </div>\r\n </div>\r\n</div>", styles: ["@charset \"UTF-8\";.sd-code-wrapper{background-color:#1e1e1e;border-radius:8px;overflow:hidden;box-shadow:0 4px 12px #00000026;margin:16px 0;font-family:Fira Code,Consolas,Monaco,monospace}.sd-code-wrapper .sd-code-header{display:flex;align-items:center;justify-content:space-between;background-color:#2d2d2d;padding:8px 16px;border-bottom:1px solid #404040}.sd-code-wrapper .sd-code-header .mac-dots{display:flex;gap:6px}.sd-code-wrapper .sd-code-header .mac-dots .dot{width:12px;height:12px;border-radius:50%}.sd-code-wrapper .sd-code-header .mac-dots .dot.red{background-color:#ff5f56}.sd-code-wrapper .sd-code-header .mac-dots .dot.yellow{background-color:#ffbd2e}.sd-code-wrapper .sd-code-header .mac-dots .dot.green{background-color:#27c93f}.sd-code-wrapper .sd-code-header .lang-badge{color:#858585;font-size:12px;font-weight:600;letter-spacing:.5px}.sd-code-wrapper .sd-code-header .copy-btn{display:flex;align-items:center;gap:4px;background:none;border:none;color:#ccc;cursor:pointer;font-size:13px;padding:4px 8px;border-radius:4px;transition:all .2s ease}.sd-code-wrapper .sd-code-header .copy-btn mat-icon{font-size:16px;width:16px;height:16px}.sd-code-wrapper .sd-code-header .copy-btn:hover{background-color:#404040;color:#fff}.sd-code-wrapper .sd-code-header .copy-btn .text-success{color:#27c93f!important}.sd-code-wrapper .sd-code-content{overflow-y:auto;position:relative}.sd-code-wrapper .sd-code-content::-webkit-scrollbar{width:8px;height:8px}.sd-code-wrapper .sd-code-content::-webkit-scrollbar-thumb{background:#555;border-radius:4px}.sd-code-wrapper .sd-code-content::-webkit-scrollbar-thumb:hover{background:#777}.sd-code-wrapper .sd-code-content::-webkit-scrollbar-track{background:#1e1e1e}.sd-code-wrapper .sd-code-content .editor-overlay-container{position:relative;min-height:100px}.sd-code-wrapper .sd-code-content .code-textarea,.sd-code-wrapper .sd-code-content .code-display{margin:0;padding:16px;border:0;width:100%;min-height:100%;font-family:inherit;font-size:14px;line-height:1.5;white-space:pre-wrap;word-break:break-all;tab-size:2}.sd-code-wrapper .sd-code-content .code-textarea{position:absolute;top:0;left:0;z-index:2;background:transparent!important;color:transparent!important;-webkit-text-fill-color:transparent!important;caret-color:#fff;resize:none;outline:none;overflow:hidden}.sd-code-wrapper .sd-code-content .code-display{position:relative;z-index:1;pointer-events:none}.sd-code-wrapper .sd-code-content .code-display code{color:#d4d4d4;font-family:inherit}.sd-code-wrapper .token.comment,.sd-code-wrapper .token.block-comment,.sd-code-wrapper .token.prolog,.sd-code-wrapper .token.doctype,.sd-code-wrapper .token.cdata{color:#999}.sd-code-wrapper .token.punctuation{color:#ccc}.sd-code-wrapper .token.tag,.sd-code-wrapper .token.attr-name,.sd-code-wrapper .token.namespace,.sd-code-wrapper .token.deleted{color:#e2777a}.sd-code-wrapper .token.function-name{color:#6196cc}.sd-code-wrapper .token.boolean,.sd-code-wrapper .token.number,.sd-code-wrapper .token.function{color:#f08d49}.sd-code-wrapper .token.property,.sd-code-wrapper .token.class-name,.sd-code-wrapper .token.constant,.sd-code-wrapper .token.symbol{color:#f8c555}.sd-code-wrapper .token.selector,.sd-code-wrapper .token.important,.sd-code-wrapper .token.atrule,.sd-code-wrapper .token.keyword,.sd-code-wrapper .token.builtin{color:#cc99cd}.sd-code-wrapper .token.string,.sd-code-wrapper .token.char,.sd-code-wrapper .token.attr-value,.sd-code-wrapper .token.regex,.sd-code-wrapper .token.variable{color:#7ec699}.sd-code-wrapper .token.operator,.sd-code-wrapper .token.entity,.sd-code-wrapper .token.url{color:#67cdcc}.sd-code-wrapper .token.important,.sd-code-wrapper .token.bold{font-weight:700}.sd-code-wrapper .token.italic{font-style:italic}.sd-code-wrapper .token.entity{cursor:help}.sd-code-wrapper .token.inserted{color:green}\n"], dependencies: [{ kind: "ngmodule", type: CommonModule }, { kind: "ngmodule", type: MatIconModule }, { kind: "component", type: i1.MatIcon, selector: "mat-icon", inputs: ["color", "inline", "svgIcon", "fontSet", "fontIcon"], exportAs: ["matIcon"] }, { kind: "ngmodule", type: MatTooltipModule }, { kind: "directive", type: i2.MatTooltip, selector: "[matTooltip]", inputs: ["matTooltipPosition", "matTooltipPositionAtOrigin", "matTooltipDisabled", "matTooltipShowDelay", "matTooltipHideDelay", "matTooltipTouchGestures", "matTooltip", "matTooltipClass"], exportAs: ["matTooltip"] }], changeDetection: i0.ChangeDetectionStrategy.OnPush, encapsulation: i0.ViewEncapsulation.None });
118
116
  }
119
117
  i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.2.17", ngImport: i0, type: SdCodeEditor, decorators: [{
120
118
  type: Component,
121
- args: [{ selector: 'sd-code-editor', standalone: true, imports: [CommonModule, MatIconModule, MatTooltipModule, FormsModule], changeDetection: ChangeDetectionStrategy.OnPush, encapsulation: ViewEncapsulation.None, template: "<div class=\"sd-code-wrapper\" [class.is-editable]=\"!viewed()\">\r\n \r\n <div class=\"sd-code-header\">\r\n <div class=\"mac-dots\">\r\n <span class=\"dot red\"></span>\r\n <span class=\"dot yellow\"></span>\r\n <span class=\"dot green\"></span>\r\n </div>\r\n \r\n <div class=\"lang-badge\">\r\n {{ language().toUpperCase() }} \r\n <span style=\"opacity: 0.6; margin-left: 4px; font-weight: normal;\">\r\n {{ viewed() ? '(READ ONLY)' : '(EDITING)' }}\r\n </span>\r\n </div>\r\n \r\n <button class=\"copy-btn\" [matTooltip]=\"copied() ? '\u0110\u00E3 copy!' : 'Copy code'\" (click)=\"copyToClipboard()\">\r\n <mat-icon [class.text-success]=\"copied()\">{{ copied() ? 'check' : 'content_copy' }}</mat-icon>\r\n <span>{{ copied() ? 'Copied' : 'Copy' }}</span>\r\n </button>\r\n </div>\r\n\r\n <div class=\"sd-code-content\" [style.maxHeight]=\"maxHeight()\">\r\n <div class=\"editor-overlay-container\">\r\n \r\n @if (!viewed()) {\r\n <textarea \r\n class=\"code-textarea\"\r\n [ngModel]=\"textValue()\"\r\n (ngModelChange)=\"onTextChange($event)\"\r\n spellcheck=\"false\"\r\n autocomplete=\"off\"\r\n autocorrect=\"off\"\r\n autocapitalize=\"off\">\r\n </textarea>\r\n }\r\n \r\n <pre aria-hidden=\"true\" class=\"code-display\"><code [class]=\"'language-' + prismLang()\" [innerHTML]=\"highlightedCode()\"></code></pre>\r\n \r\n </div>\r\n </div>\r\n</div>", styles: ["@charset \"UTF-8\";.sd-code-wrapper{background-color:#1e1e1e;border-radius:8px;overflow:hidden;box-shadow:0 4px 12px #00000026;margin:16px 0;font-family:Fira Code,Consolas,Monaco,monospace}.sd-code-wrapper .sd-code-header{display:flex;align-items:center;justify-content:space-between;background-color:#2d2d2d;padding:8px 16px;border-bottom:1px solid #404040}.sd-code-wrapper .sd-code-header .mac-dots{display:flex;gap:6px}.sd-code-wrapper .sd-code-header .mac-dots .dot{width:12px;height:12px;border-radius:50%}.sd-code-wrapper .sd-code-header .mac-dots .dot.red{background-color:#ff5f56}.sd-code-wrapper .sd-code-header .mac-dots .dot.yellow{background-color:#ffbd2e}.sd-code-wrapper .sd-code-header .mac-dots .dot.green{background-color:#27c93f}.sd-code-wrapper .sd-code-header .lang-badge{color:#858585;font-size:12px;font-weight:600;letter-spacing:.5px}.sd-code-wrapper .sd-code-header .copy-btn{display:flex;align-items:center;gap:4px;background:none;border:none;color:#ccc;cursor:pointer;font-size:13px;padding:4px 8px;border-radius:4px;transition:all .2s ease}.sd-code-wrapper .sd-code-header .copy-btn mat-icon{font-size:16px;width:16px;height:16px}.sd-code-wrapper .sd-code-header .copy-btn:hover{background-color:#404040;color:#fff}.sd-code-wrapper .sd-code-header .copy-btn .text-success{color:#27c93f!important}.sd-code-wrapper .sd-code-content{overflow-y:auto;position:relative}.sd-code-wrapper .sd-code-content::-webkit-scrollbar{width:8px;height:8px}.sd-code-wrapper .sd-code-content::-webkit-scrollbar-thumb{background:#555;border-radius:4px}.sd-code-wrapper .sd-code-content::-webkit-scrollbar-thumb:hover{background:#777}.sd-code-wrapper .sd-code-content::-webkit-scrollbar-track{background:#1e1e1e}.sd-code-wrapper .sd-code-content .editor-overlay-container{position:relative;min-height:100px}.sd-code-wrapper .sd-code-content .code-textarea,.sd-code-wrapper .sd-code-content .code-display{margin:0;padding:16px;border:0;width:100%;min-height:100%;font-family:inherit;font-size:14px;line-height:1.5;white-space:pre-wrap;word-break:break-all;tab-size:2}.sd-code-wrapper .sd-code-content .code-textarea{position:absolute;top:0;left:0;z-index:2;background:transparent;color:transparent;caret-color:#fff;resize:none;outline:none;overflow:hidden}.sd-code-wrapper .sd-code-content .code-display{position:relative;z-index:1;pointer-events:none}.sd-code-wrapper .sd-code-content .code-display code{color:#d4d4d4;font-family:inherit}.sd-code-wrapper .token.comment,.sd-code-wrapper .token.block-comment,.sd-code-wrapper .token.prolog,.sd-code-wrapper .token.doctype,.sd-code-wrapper .token.cdata{color:#999}.sd-code-wrapper .token.punctuation{color:#ccc}.sd-code-wrapper .token.tag,.sd-code-wrapper .token.attr-name,.sd-code-wrapper .token.namespace,.sd-code-wrapper .token.deleted{color:#e2777a}.sd-code-wrapper .token.function-name{color:#6196cc}.sd-code-wrapper .token.boolean,.sd-code-wrapper .token.number,.sd-code-wrapper .token.function{color:#f08d49}.sd-code-wrapper .token.property,.sd-code-wrapper .token.class-name,.sd-code-wrapper .token.constant,.sd-code-wrapper .token.symbol{color:#f8c555}.sd-code-wrapper .token.selector,.sd-code-wrapper .token.important,.sd-code-wrapper .token.atrule,.sd-code-wrapper .token.keyword,.sd-code-wrapper .token.builtin{color:#cc99cd}.sd-code-wrapper .token.string,.sd-code-wrapper .token.char,.sd-code-wrapper .token.attr-value,.sd-code-wrapper .token.regex,.sd-code-wrapper .token.variable{color:#7ec699}.sd-code-wrapper .token.operator,.sd-code-wrapper .token.entity,.sd-code-wrapper .token.url{color:#67cdcc}.sd-code-wrapper .token.important,.sd-code-wrapper .token.bold{font-weight:700}.sd-code-wrapper .token.italic{font-style:italic}.sd-code-wrapper .token.entity{cursor:help}.sd-code-wrapper .token.inserted{color:green}\n"] }]
119
+ args: [{ selector: 'sd-code-editor', standalone: true, imports: [CommonModule, MatIconModule, MatTooltipModule], changeDetection: ChangeDetectionStrategy.OnPush, encapsulation: ViewEncapsulation.None, template: "<div class=\"sd-code-wrapper\" [class.is-editable]=\"!viewed()\">\r\n \r\n <div class=\"sd-code-header\">\r\n <div class=\"mac-dots\">\r\n <span class=\"dot red\"></span>\r\n <span class=\"dot yellow\"></span>\r\n <span class=\"dot green\"></span>\r\n </div>\r\n \r\n <div class=\"lang-badge\">\r\n {{ language().toUpperCase() }} \r\n <span style=\"opacity: 0.6; margin-left: 4px; font-weight: normal;\">\r\n {{ viewed() ? '(READ ONLY)' : '(EDITING)' }}\r\n </span>\r\n </div>\r\n \r\n <button class=\"copy-btn\" [matTooltip]=\"copied() ? '\u0110\u00E3 copy!' : 'Copy code'\" (click)=\"copyToClipboard()\">\r\n <mat-icon [class.text-success]=\"copied()\">{{ copied() ? 'check' : 'content_copy' }}</mat-icon>\r\n <span>{{ copied() ? 'Copied' : 'Copy' }}</span>\r\n </button>\r\n </div>\r\n\r\n <div class=\"sd-code-content\" [style.maxHeight]=\"maxHeight()\">\r\n <div class=\"editor-overlay-container\">\r\n \r\n @if (!viewed()) {\r\n <textarea\r\n class=\"code-textarea\"\r\n [value]=\"textValue()\"\r\n (input)=\"onTextChange($any($event.target).value)\"\r\n spellcheck=\"false\"\r\n autocomplete=\"off\"\r\n autocorrect=\"off\"\r\n autocapitalize=\"off\">\r\n </textarea>\r\n }\r\n \r\n <pre aria-hidden=\"true\" class=\"code-display\"><code [class]=\"'language-' + prismLang()\" [innerHTML]=\"highlightedCode()\"></code></pre>\r\n \r\n </div>\r\n </div>\r\n</div>", styles: ["@charset \"UTF-8\";.sd-code-wrapper{background-color:#1e1e1e;border-radius:8px;overflow:hidden;box-shadow:0 4px 12px #00000026;margin:16px 0;font-family:Fira Code,Consolas,Monaco,monospace}.sd-code-wrapper .sd-code-header{display:flex;align-items:center;justify-content:space-between;background-color:#2d2d2d;padding:8px 16px;border-bottom:1px solid #404040}.sd-code-wrapper .sd-code-header .mac-dots{display:flex;gap:6px}.sd-code-wrapper .sd-code-header .mac-dots .dot{width:12px;height:12px;border-radius:50%}.sd-code-wrapper .sd-code-header .mac-dots .dot.red{background-color:#ff5f56}.sd-code-wrapper .sd-code-header .mac-dots .dot.yellow{background-color:#ffbd2e}.sd-code-wrapper .sd-code-header .mac-dots .dot.green{background-color:#27c93f}.sd-code-wrapper .sd-code-header .lang-badge{color:#858585;font-size:12px;font-weight:600;letter-spacing:.5px}.sd-code-wrapper .sd-code-header .copy-btn{display:flex;align-items:center;gap:4px;background:none;border:none;color:#ccc;cursor:pointer;font-size:13px;padding:4px 8px;border-radius:4px;transition:all .2s ease}.sd-code-wrapper .sd-code-header .copy-btn mat-icon{font-size:16px;width:16px;height:16px}.sd-code-wrapper .sd-code-header .copy-btn:hover{background-color:#404040;color:#fff}.sd-code-wrapper .sd-code-header .copy-btn .text-success{color:#27c93f!important}.sd-code-wrapper .sd-code-content{overflow-y:auto;position:relative}.sd-code-wrapper .sd-code-content::-webkit-scrollbar{width:8px;height:8px}.sd-code-wrapper .sd-code-content::-webkit-scrollbar-thumb{background:#555;border-radius:4px}.sd-code-wrapper .sd-code-content::-webkit-scrollbar-thumb:hover{background:#777}.sd-code-wrapper .sd-code-content::-webkit-scrollbar-track{background:#1e1e1e}.sd-code-wrapper .sd-code-content .editor-overlay-container{position:relative;min-height:100px}.sd-code-wrapper .sd-code-content .code-textarea,.sd-code-wrapper .sd-code-content .code-display{margin:0;padding:16px;border:0;width:100%;min-height:100%;font-family:inherit;font-size:14px;line-height:1.5;white-space:pre-wrap;word-break:break-all;tab-size:2}.sd-code-wrapper .sd-code-content .code-textarea{position:absolute;top:0;left:0;z-index:2;background:transparent!important;color:transparent!important;-webkit-text-fill-color:transparent!important;caret-color:#fff;resize:none;outline:none;overflow:hidden}.sd-code-wrapper .sd-code-content .code-display{position:relative;z-index:1;pointer-events:none}.sd-code-wrapper .sd-code-content .code-display code{color:#d4d4d4;font-family:inherit}.sd-code-wrapper .token.comment,.sd-code-wrapper .token.block-comment,.sd-code-wrapper .token.prolog,.sd-code-wrapper .token.doctype,.sd-code-wrapper .token.cdata{color:#999}.sd-code-wrapper .token.punctuation{color:#ccc}.sd-code-wrapper .token.tag,.sd-code-wrapper .token.attr-name,.sd-code-wrapper .token.namespace,.sd-code-wrapper .token.deleted{color:#e2777a}.sd-code-wrapper .token.function-name{color:#6196cc}.sd-code-wrapper .token.boolean,.sd-code-wrapper .token.number,.sd-code-wrapper .token.function{color:#f08d49}.sd-code-wrapper .token.property,.sd-code-wrapper .token.class-name,.sd-code-wrapper .token.constant,.sd-code-wrapper .token.symbol{color:#f8c555}.sd-code-wrapper .token.selector,.sd-code-wrapper .token.important,.sd-code-wrapper .token.atrule,.sd-code-wrapper .token.keyword,.sd-code-wrapper .token.builtin{color:#cc99cd}.sd-code-wrapper .token.string,.sd-code-wrapper .token.char,.sd-code-wrapper .token.attr-value,.sd-code-wrapper .token.regex,.sd-code-wrapper .token.variable{color:#7ec699}.sd-code-wrapper .token.operator,.sd-code-wrapper .token.entity,.sd-code-wrapper .token.url{color:#67cdcc}.sd-code-wrapper .token.important,.sd-code-wrapper .token.bold{font-weight:700}.sd-code-wrapper .token.italic{font-style:italic}.sd-code-wrapper .token.entity{cursor:help}.sd-code-wrapper .token.inserted{color:green}\n"] }]
122
120
  }], ctorParameters: () => [] });
123
121
 
124
122
  /**
@@ -1 +1 @@
1
- {"version":3,"file":"sd-angular-core-components-code-editor.mjs","sources":["../../../projects/sd-angular/components/code-editor/src/code-editor.component.ts","../../../projects/sd-angular/components/code-editor/src/code-editor.component.html","../../../projects/sd-angular/components/code-editor/sd-angular-core-components-code-editor.ts"],"sourcesContent":["import { Clipboard } from '@angular/cdk/clipboard';\r\nimport { CommonModule } from '@angular/common';\r\nimport {\r\n ChangeDetectionStrategy,\r\n Component,\r\n computed,\r\n effect,\r\n inject,\r\n input,\r\n model,\r\n signal,\r\n untracked,\r\n ViewEncapsulation,\r\n booleanAttribute\r\n} from '@angular/core';\r\nimport { FormsModule } from '@angular/forms';\r\nimport { MatIconModule } from '@angular/material/icon';\r\nimport { MatTooltipModule } from '@angular/material/tooltip';\r\nimport { DomSanitizer, SafeHtml } from '@angular/platform-browser';\r\n\r\nimport * as Prism from 'prismjs';\r\nimport 'prismjs/components/prism-typescript';\r\nimport 'prismjs/components/prism-json';\r\nimport 'prismjs/components/prism-css';\r\nimport 'prismjs/components/prism-scss';\r\nimport 'prismjs/components/prism-markup'; // HTML\r\n\r\nexport type CodeLanguage = 'html' | 'typescript' | 'json' | 'css' | 'scss';\r\n\r\n@Component({\r\n selector: 'sd-code-editor',\r\n standalone: true,\r\n imports: [CommonModule, MatIconModule, MatTooltipModule, FormsModule],\r\n changeDetection: ChangeDetectionStrategy.OnPush,\r\n templateUrl: './code-editor.component.html',\r\n styleUrls: ['./code-editor.component.scss'],\r\n encapsulation: ViewEncapsulation.None, // Bắt buộc để nhận màu Prism\r\n})\r\nexport class SdCodeEditor {\r\n #clipboard = inject(Clipboard);\r\n #sanitizer = inject(DomSanitizer);\r\n\r\n // ==========================================\r\n // 1. SIGNAL INPUTS & MODEL\r\n // ==========================================\r\n // Nhận bất kỳ kiểu dữ liệu nào (string, array, object)\r\n valueModel = model<any>(undefined, { alias: 'model' });\r\n \r\n language = input<CodeLanguage>('typescript');\r\n maxHeight = input<string>('500px');\r\n \r\n // Trạng thái Viewed (true = Read Only, false = Editable)\r\n viewed = input(false, { transform: booleanAttribute });\r\n\r\n // ==========================================\r\n // 2. INTERNAL STATE\r\n // ==========================================\r\n copied = signal<boolean>(false);\r\n \r\n // Chuỗi text nội bộ dùng để map với thẻ <textarea>\r\n textValue = signal<string>('');\r\n \r\n prismLang = computed(() => this.language() === 'html' ? 'markup' : this.language());\r\n\r\n // Cờ lưu vết để chống Loop (Vòng lặp vô tận khi bắn 2 chiều)\r\n private _lastEmittedValue: any = undefined;\r\n\r\n constructor() {\r\n // ==========================================\r\n // EFFECT 1: Dữ liệu từ CHA truyền vào (Model -> TextValue)\r\n // ==========================================\r\n effect(() => {\r\n const extVal = this.valueModel();\r\n const lang = this.language();\r\n \r\n untracked(() => {\r\n // Nếu giá trị này do chính component bắn ra, bỏ qua để tránh loop\r\n if (extVal === this._lastEmittedValue) return;\r\n\r\n if (typeof extVal === 'string') {\r\n this.textValue.set(extVal);\r\n } else if (extVal !== undefined && extVal !== null) {\r\n // Tự động format Object -> String nếu là JSON\r\n if (lang === 'json') {\r\n try {\r\n this.textValue.set(JSON.stringify(extVal, null, 2));\r\n } catch {\r\n this.textValue.set('// Lỗi: Object có tham chiếu vòng (Circular Reference)');\r\n }\r\n } else {\r\n this.textValue.set(String(extVal));\r\n }\r\n } else {\r\n this.textValue.set('');\r\n }\r\n });\r\n });\r\n }\r\n\r\n // ==========================================\r\n // EFFECT 2: PrismJS render (TextValue -> HTML MÀU)\r\n // ==========================================\r\n highlightedCode = computed<SafeHtml>(() => {\r\n // Dùng khoảng trắng để giữ độ cao cho thẻ pre nếu rỗng\r\n const rawCode = this.textValue() || ' '; \r\n const langKey = this.prismLang();\r\n const grammar = Prism.languages[langKey] || Prism.languages['markup'];\r\n \r\n // Cộng thêm \\n ở cuối để chống lỗi con trỏ textarea ăn lẹm dòng cuối\r\n const highlightedString = Prism.highlight(rawCode, grammar, langKey) + '\\n';\r\n return this.#sanitizer.bypassSecurityTrustHtml(highlightedString);\r\n });\r\n\r\n // ==========================================\r\n // EVENTS\r\n // ==========================================\r\n \r\n // Khi người dùng gõ vào Textarea (TextValue -> Model)\r\n onTextChange(newText: string) {\r\n this.textValue.set(newText);\r\n \r\n let valToEmit: any = newText;\r\n \r\n // Nếu ngôn ngữ là JSON, cố gắng trả về Object thật\r\n if (this.language() === 'json') {\r\n try {\r\n valToEmit = JSON.parse(newText);\r\n } catch {\r\n // Nếu gõ dở ngoặc/sai cú pháp -> Trả về chuỗi String tạm\r\n valToEmit = newText; \r\n }\r\n }\r\n \r\n // Ghi sổ và bắn ra ngoài\r\n this._lastEmittedValue = valToEmit;\r\n this.valueModel.set(valToEmit);\r\n }\r\n\r\n copyToClipboard() {\r\n const rawCode = this.textValue();\r\n if (!rawCode) return;\r\n \r\n if (this.#clipboard.copy(rawCode)) {\r\n this.copied.set(true);\r\n setTimeout(() => this.copied.set(false), 2000);\r\n }\r\n }\r\n}","<div class=\"sd-code-wrapper\" [class.is-editable]=\"!viewed()\">\r\n \r\n <div class=\"sd-code-header\">\r\n <div class=\"mac-dots\">\r\n <span class=\"dot red\"></span>\r\n <span class=\"dot yellow\"></span>\r\n <span class=\"dot green\"></span>\r\n </div>\r\n \r\n <div class=\"lang-badge\">\r\n {{ language().toUpperCase() }} \r\n <span style=\"opacity: 0.6; margin-left: 4px; font-weight: normal;\">\r\n {{ viewed() ? '(READ ONLY)' : '(EDITING)' }}\r\n </span>\r\n </div>\r\n \r\n <button class=\"copy-btn\" [matTooltip]=\"copied() ? 'Đã copy!' : 'Copy code'\" (click)=\"copyToClipboard()\">\r\n <mat-icon [class.text-success]=\"copied()\">{{ copied() ? 'check' : 'content_copy' }}</mat-icon>\r\n <span>{{ copied() ? 'Copied' : 'Copy' }}</span>\r\n </button>\r\n </div>\r\n\r\n <div class=\"sd-code-content\" [style.maxHeight]=\"maxHeight()\">\r\n <div class=\"editor-overlay-container\">\r\n \r\n @if (!viewed()) {\r\n <textarea \r\n class=\"code-textarea\"\r\n [ngModel]=\"textValue()\"\r\n (ngModelChange)=\"onTextChange($event)\"\r\n spellcheck=\"false\"\r\n autocomplete=\"off\"\r\n autocorrect=\"off\"\r\n autocapitalize=\"off\">\r\n </textarea>\r\n }\r\n \r\n <pre aria-hidden=\"true\" class=\"code-display\"><code [class]=\"'language-' + prismLang()\" [innerHTML]=\"highlightedCode()\"></code></pre>\r\n \r\n </div>\r\n </div>\r\n</div>","/**\n * Generated bundle index. Do not edit.\n */\n\nexport * from './index';\n"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"sd-angular-core-components-code-editor.mjs","sources":["../../../projects/sd-angular/components/code-editor/src/code-editor.component.ts","../../../projects/sd-angular/components/code-editor/src/code-editor.component.html","../../../projects/sd-angular/components/code-editor/sd-angular-core-components-code-editor.ts"],"sourcesContent":["import { Clipboard } from '@angular/cdk/clipboard';\r\nimport { CommonModule } from '@angular/common';\r\nimport {\r\n ChangeDetectionStrategy,\r\n Component,\r\n computed,\r\n effect,\r\n inject,\r\n input,\r\n model,\r\n signal,\r\n untracked,\r\n ViewEncapsulation,\r\n booleanAttribute\r\n} from '@angular/core';\r\nimport { MatIconModule } from '@angular/material/icon';\r\nimport { MatTooltipModule } from '@angular/material/tooltip';\r\nimport { DomSanitizer, SafeHtml } from '@angular/platform-browser';\r\n\r\nimport * as Prism from 'prismjs';\r\nimport 'prismjs/components/prism-typescript';\r\nimport 'prismjs/components/prism-json';\r\nimport 'prismjs/components/prism-css';\r\nimport 'prismjs/components/prism-scss';\r\nimport 'prismjs/components/prism-markup'; // HTML\r\n\r\nexport type CodeLanguage = 'html' | 'typescript' | 'json' | 'css' | 'scss';\r\n\r\n@Component({\r\n selector: 'sd-code-editor',\r\n standalone: true,\r\n imports: [CommonModule, MatIconModule, MatTooltipModule],\r\n changeDetection: ChangeDetectionStrategy.OnPush,\r\n templateUrl: './code-editor.component.html',\r\n styleUrls: ['./code-editor.component.scss'],\r\n encapsulation: ViewEncapsulation.None, // Bắt buộc để nhận màu Prism\r\n})\r\nexport class SdCodeEditor {\r\n #clipboard = inject(Clipboard);\r\n #sanitizer = inject(DomSanitizer);\r\n\r\n // ==========================================\r\n // 1. SIGNAL INPUTS & MODEL\r\n // ==========================================\r\n // Nhận bất kỳ kiểu dữ liệu nào (string, array, object)\r\n valueModel = model<any>(undefined, { alias: 'model' });\r\n \r\n language = input<CodeLanguage>('typescript');\r\n maxHeight = input<string>('500px');\r\n \r\n // Trạng thái Viewed (true = Read Only, false = Editable)\r\n viewed = input(false, { transform: booleanAttribute });\r\n\r\n // ==========================================\r\n // 2. INTERNAL STATE\r\n // ==========================================\r\n copied = signal<boolean>(false);\r\n \r\n // Chuỗi text nội bộ dùng để map với thẻ <textarea>\r\n textValue = signal<string>('');\r\n \r\n prismLang = computed(() => this.language() === 'html' ? 'markup' : this.language());\r\n\r\n // Cờ lưu vết để chống Loop (Vòng lặp vô tận khi bắn 2 chiều)\r\n private _lastEmittedValue: any = undefined;\r\n\r\n constructor() {\r\n // ==========================================\r\n // EFFECT 1: Dữ liệu từ CHA truyền vào (Model -> TextValue)\r\n // ==========================================\r\n effect(() => {\r\n const extVal = this.valueModel();\r\n const lang = this.language();\r\n \r\n untracked(() => {\r\n // Nếu giá trị này do chính component bắn ra, bỏ qua để tránh loop\r\n if (extVal === this._lastEmittedValue) return;\r\n\r\n if (typeof extVal === 'string') {\r\n this.textValue.set(extVal);\r\n } else if (extVal !== undefined && extVal !== null) {\r\n // Tự động format Object -> String nếu là JSON\r\n if (lang === 'json') {\r\n try {\r\n this.textValue.set(JSON.stringify(extVal, null, 2));\r\n } catch {\r\n this.textValue.set('// Lỗi: Object có tham chiếu vòng (Circular Reference)');\r\n }\r\n } else {\r\n this.textValue.set(String(extVal));\r\n }\r\n } else {\r\n this.textValue.set('');\r\n }\r\n });\r\n });\r\n }\r\n\r\n // ==========================================\r\n // EFFECT 2: PrismJS render (TextValue -> HTML MÀU)\r\n // ==========================================\r\n highlightedCode = computed<SafeHtml>(() => {\r\n // Dùng khoảng trắng để giữ độ cao cho thẻ pre nếu rỗng\r\n const rawCode = this.textValue() || ' '; \r\n const langKey = this.prismLang();\r\n const grammar = Prism.languages[langKey] || Prism.languages['markup'];\r\n \r\n // Cộng thêm \\n ở cuối để chống lỗi con trỏ textarea ăn lẹm dòng cuối\r\n const highlightedString = Prism.highlight(rawCode, grammar, langKey) + '\\n';\r\n return this.#sanitizer.bypassSecurityTrustHtml(highlightedString);\r\n });\r\n\r\n // ==========================================\r\n // EVENTS\r\n // ==========================================\r\n \r\n // Khi người dùng gõ vào Textarea (TextValue -> Model)\r\n onTextChange(newText: string) {\r\n this.textValue.set(newText);\r\n \r\n let valToEmit: any = newText;\r\n \r\n // Nếu ngôn ngữ là JSON, cố gắng trả về Object thật\r\n if (this.language() === 'json') {\r\n try {\r\n valToEmit = JSON.parse(newText);\r\n } catch {\r\n // Nếu gõ dở ngoặc/sai cú pháp -> Trả về chuỗi String tạm\r\n valToEmit = newText; \r\n }\r\n }\r\n \r\n // Ghi sổ và bắn ra ngoài\r\n this._lastEmittedValue = valToEmit;\r\n this.valueModel.set(valToEmit);\r\n }\r\n\r\n copyToClipboard() {\r\n const rawCode = this.textValue();\r\n if (!rawCode) return;\r\n \r\n if (this.#clipboard.copy(rawCode)) {\r\n this.copied.set(true);\r\n setTimeout(() => this.copied.set(false), 2000);\r\n }\r\n }\r\n}","<div class=\"sd-code-wrapper\" [class.is-editable]=\"!viewed()\">\r\n \r\n <div class=\"sd-code-header\">\r\n <div class=\"mac-dots\">\r\n <span class=\"dot red\"></span>\r\n <span class=\"dot yellow\"></span>\r\n <span class=\"dot green\"></span>\r\n </div>\r\n \r\n <div class=\"lang-badge\">\r\n {{ language().toUpperCase() }} \r\n <span style=\"opacity: 0.6; margin-left: 4px; font-weight: normal;\">\r\n {{ viewed() ? '(READ ONLY)' : '(EDITING)' }}\r\n </span>\r\n </div>\r\n \r\n <button class=\"copy-btn\" [matTooltip]=\"copied() ? 'Đã copy!' : 'Copy code'\" (click)=\"copyToClipboard()\">\r\n <mat-icon [class.text-success]=\"copied()\">{{ copied() ? 'check' : 'content_copy' }}</mat-icon>\r\n <span>{{ copied() ? 'Copied' : 'Copy' }}</span>\r\n </button>\r\n </div>\r\n\r\n <div class=\"sd-code-content\" [style.maxHeight]=\"maxHeight()\">\r\n <div class=\"editor-overlay-container\">\r\n \r\n @if (!viewed()) {\r\n <textarea\r\n class=\"code-textarea\"\r\n [value]=\"textValue()\"\r\n (input)=\"onTextChange($any($event.target).value)\"\r\n spellcheck=\"false\"\r\n autocomplete=\"off\"\r\n autocorrect=\"off\"\r\n autocapitalize=\"off\">\r\n </textarea>\r\n }\r\n \r\n <pre aria-hidden=\"true\" class=\"code-display\"><code [class]=\"'language-' + prismLang()\" [innerHTML]=\"highlightedCode()\"></code></pre>\r\n \r\n </div>\r\n </div>\r\n</div>","/**\n * Generated bundle index. Do not edit.\n */\n\nexport * from './index';\n"],"names":[],"mappings":"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"}
@@ -376,6 +376,15 @@ class VariablePlugin extends Plugin {
376
376
  const schema = editor.model.schema;
377
377
  const conversion = editor.conversion;
378
378
  const editingView = editor.editing.view;
379
+ // Cờ đánh dấu đang trong quá trình xử lý paste
380
+ let isPasting = false;
381
+ this.listenTo(editingView.document, 'clipboardInput', () => {
382
+ isPasting = true;
383
+ // Reset cờ sau khi quá trình paste (ngay trong cùng event loop/tick) hoàn tất
384
+ setTimeout(() => {
385
+ isPasting = false;
386
+ }, 0);
387
+ }, { priority: 'highest' });
379
388
  // 1. Định nghĩa Schema (Model)
380
389
  schema.register('variable', {
381
390
  inheritAllFrom: '$inlineObject',
@@ -397,7 +406,6 @@ class VariablePlugin extends Plugin {
397
406
  const widgetElement = viewWriter.createContainerElement('span', {
398
407
  class: 'variable-widget',
399
408
  'data-id': id,
400
- 'data-uuid': uuid,
401
409
  'data-value': value,
402
410
  'data-display': display,
403
411
  'data-binding': 'false', // Luôn bắt đầu unbound — binding chỉ set qua bindValue()
@@ -439,7 +447,6 @@ class VariablePlugin extends Plugin {
439
447
  classes: 'variable-widget ck-widget',
440
448
  attributes: {
441
449
  'data-id': true,
442
- 'data-uuid': true,
443
450
  'data-value': true,
444
451
  'data-display': true,
445
452
  contenteditable: true,
@@ -459,7 +466,8 @@ class VariablePlugin extends Plugin {
459
466
  }
460
467
  return modelWriter.createElement('variable', {
461
468
  id: viewElement.getAttribute('data-id'),
462
- uuid: viewElement.getAttribute('data-uuid'),
469
+ // Fix trùng uuid: Nếu đang paste, TẠO MỚI uuid thay vì dùng uuid cũ từ HTML
470
+ uuid: isPasting ? v4() : (viewElement.getAttribute('data-uuid') ?? v4()),
463
471
  value: viewElement.getAttribute('data-value'),
464
472
  display: viewElement.getAttribute('data-display'),
465
473
  ...(bindingValue ? { bindingValue } : {}),
@@ -669,7 +677,8 @@ class VariablePlugin extends Plugin {
669
677
  this.listenTo(editor.editing.view.document, 'clipboardInput', async (evt, data) => {
670
678
  const dataTransfer = data.dataTransfer;
671
679
  // Nếu có HTML chứa variable-widget thì để CKEditor xử lý (upcast converter)
672
- const html = dataTransfer.getData('text/html');
680
+ // Việc chống trùng uuid (regenerate) đã được xử lý ở upcast converter dựa vào biến isPasting
681
+ let html = dataTransfer.getData('text/html');
673
682
  if (html && html.includes('variable-widget')) {
674
683
  return;
675
684
  }
@@ -761,7 +770,7 @@ class VariablePlugin extends Plugin {
761
770
  else if (fragment.type === 'variable' && fragment.variable) {
762
771
  const variableElem = writer.createElement('variable', {
763
772
  id: fragment.variable.id,
764
- uuid: fragment.variable.uuid ?? v4(),
773
+ uuid: v4(),
765
774
  value: fragment.variable.value,
766
775
  display: fragment.variable.display,
767
776
  });
@@ -772,7 +781,7 @@ class VariablePlugin extends Plugin {
772
781
  // Đặt con trỏ sau nội dung vừa paste
773
782
  writer.setSelection(currentPosition);
774
783
  });
775
- });
784
+ }, { priority: 'high' });
776
785
  }
777
786
  #isSdDocumentBuilderVariableResult = (obj) => {
778
787
  return (obj !== null &&
@@ -4928,11 +4937,11 @@ class SdDocumentBuilder {
4928
4937
  });
4929
4938
  };
4930
4939
  static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "19.2.17", ngImport: i0, type: SdDocumentBuilder, deps: [], target: i0.ɵɵFactoryTarget.Component });
4931
- static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "19.2.17", type: SdDocumentBuilder, isStandalone: true, selector: "sd-document-builder", inputs: { option: "option", _disabled: ["disabled", "_disabled"] }, outputs: { contentChange: "contentChange" }, ngImport: i0, template: "<div class=\"builder-container\">\n <ckeditor\n style=\"width: 100%\"\n [editor]=\"Editor\" \n [config]=\"config\" \n (ready)=\"onReady($event)\"\n [disabled]=\"disabled\">\n </ckeditor>\n</div>", styles: ["@charset \"UTF-8\";.builder-container{background-color:#f3f4f6;height:100%;overflow-y:auto;width:100%;display:flex;flex-direction:column;align-items:center}:host{display:inline-block}:host ::ng-deep .ck-editor{display:flex;flex-direction:column;align-items:center;width:100%;--ck-content-font-family: \"Times New Roman\", serif !important;--ck-content-font-size: 13pt;--ck-content-line-height: 1.15}:host ::ng-deep .ck-editor__top,:host ::ng-deep .ck-editor__main{border:none!important;box-shadow:none!important}:host ::ng-deep .ck-editor__top{position:sticky;top:0;z-index:100;width:100%;min-width:600px;margin-bottom:10px}:host ::ng-deep .ck-editor__top .ck-sticky-panel__content{border:none!important}:host ::ng-deep .ck-editor__top .ck-toolbar{background:#fff!important;box-shadow:0 4px 6px -1px #0000001a!important;padding:8px!important}:host ::ng-deep .ck-editor__top .ck-toolbar .ck-toolbar__items{display:flex;justify-content:center;flex-wrap:wrap;align-items:center}:host ::ng-deep .ck-content{background-color:#fff;width:210mm;min-height:1123px;padding:20mm!important;box-sizing:border-box!important;box-shadow:0 10px 15px -3px #0000001a}:host ::ng-deep .ck-content h1,:host ::ng-deep .ck-content h2,:host ::ng-deep .ck-content h3,:host ::ng-deep .ck-content h4,:host ::ng-deep .ck-content h5,:host ::ng-deep .ck-content h6{font-weight:400;font-size:inherit;line-height:inherit;margin-bottom:4px}:host ::ng-deep .ck-content.landscape{width:297mm}:host ::ng-deep .ck-content>*{max-width:100%!important;box-sizing:border-box!important}:host ::ng-deep .ck-content p{margin-bottom:4px;text-indent:0}:host ::ng-deep .ck-content ul,:host ::ng-deep .ck-content ol{padding-left:20px!important;margin-left:0!important;margin-bottom:4px}:host ::ng-deep .ck-content li{margin-bottom:0}:host ::ng-deep .ck-content table{margin-bottom:4px}\n", ":host ::ng-deep .ck-heading-highlight{background-color:#fef08a}\n", "@charset \"UTF-8\";::ng-deep .ck-clipboard-drop-target-line{display:none!important}:host ::ng-deep .variable-widget{display:inline-block;-webkit-user-select:none;user-select:none}:host ::ng-deep .variable-widget:not([data-binding=true]){background-color:#e3f2fd;color:#1976d2;border:1px solid #90caf9!important;border-radius:4px;padding:2px 6px;font-size:0;margin:0 2px;vertical-align:middle;font-weight:600;cursor:default}:host ::ng-deep .variable-widget:not([data-binding=true]):before{content:attr(data-display);font-size:10px;font-family:Segoe UI,Tahoma,Geneva,Verdana,sans-serif}:host ::ng-deep .variable-widget:not([data-binding=true]):hover{background-color:#bbdefb;box-shadow:0 1px 2px #0000001a}:host ::ng-deep .variable-widget:not([data-binding=true]).ck-widget_selected{outline:2px solid #2196f3;background-color:#bbdefb}:host ::ng-deep .variable-widget[data-binding=true]{background-color:#4caf501f;color:#2e7d32;border-bottom:2px solid #4caf50!important;border-radius:0;padding:0 1px;font-size:inherit;cursor:default}:host ::ng-deep .variable-widget[data-binding=true]:before{content:none}:host ::ng-deep .variable-widget[data-binding=true]:hover{background-color:#4caf5038}:host ::ng-deep .variable-widget[data-binding=true].ck-widget_selected{outline:2px solid #4caf50;background-color:#4caf5047}:host ::ng-deep .ck.ck-content .ck-widget,:host ::ng-deep .ck.ck-content .ck-widget:hover,:host ::ng-deep .ck.ck-content .ck-widget:focus,:host ::ng-deep .ck.ck-content .ck-widget.ck-widget_selected,:host ::ng-deep .ck.ck-content .ck-widget.ck-widget_selected:hover{outline:none!important;box-shadow:none!important}\n", ":host ::ng-deep .highlight-range{background-color:#ffeb3b80;border-bottom:2px solid #fbc02d;transition:background-color .2s;cursor:pointer}\n", ":host ::ng-deep .ck-comment-marker{background-color:var(--comment-bg, rgba(59, 130, 246, .3));border-bottom:2px solid rgb(59,130,246);cursor:pointer;transition:all .2s ease}:host ::ng-deep .ck-comment-marker:hover{opacity:.8}:host ::ng-deep .ck-comment-marker.ck-comment-pending{background-color:var(--comment-pending-bg, rgba(245, 158, 11, .4));border-bottom-color:#f59e0b}:host ::ng-deep .ck-comment-marker.ck-comment-normal{background-color:var(--comment-bg, rgba(59, 130, 246, .2));border-bottom-color:#3b82f6}:host ::ng-deep .ck-comment-marker.ck-comment-selected{background-color:var(--comment-selected-bg, 59, 130, 246, .5);border-bottom-color:#3b82f6}:host ::ng-deep .ck-comment-marker.ck-comment-modified{background-color:var(--comment-modified-bg, rgba(249, 115, 22, .3));border-bottom-color:#f97316}:host ::ng-deep .ck-comment-marker.ck-comment-broken{background-color:var(--comment-broken-bg, rgba(239, 68, 68, .3));border-bottom-color:#ef4444;text-decoration:line-through;text-decoration-color:#ef4444}:host ::ng-deep .ck-balloon-panel .ck-button.ck-on:hover,:host ::ng-deep .ck-balloon-panel .ck-button.ck-off:hover{background:var(--ck-color-button-default-hover-background)}\n"], dependencies: [{ kind: "ngmodule", type: CommonModule }, { kind: "ngmodule", type: CKEditorModule }, { kind: "component", type: i1.CKEditorComponent, selector: "ckeditor", inputs: ["editor", "config", "data", "tagName", "watchdog", "editorWatchdogConfig", "disableWatchdog", "disableTwoWayDataBinding", "disabled"], outputs: ["ready", "change", "blur", "focus", "error"] }] });
4940
+ static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "19.2.17", type: SdDocumentBuilder, isStandalone: true, selector: "sd-document-builder", inputs: { option: "option", _disabled: ["disabled", "_disabled"] }, outputs: { contentChange: "contentChange" }, ngImport: i0, template: "<div class=\"builder-container\">\r\n <ckeditor class=\"w-full\" [editor]=\"Editor\" [config]=\"config\" (ready)=\"onReady($event)\" [disabled]=\"disabled\"> </ckeditor>\r\n</div>\r\n", styles: ["@charset \"UTF-8\";.builder-container{height:100%;overflow-y:auto;width:100%;display:flex;flex-direction:column;align-items:center}:host{display:inline-block}:host ::ng-deep .ck-editor{display:flex;flex-direction:column;align-items:center;width:100%;--ck-content-font-family: \"Times New Roman\", serif !important;--ck-content-font-size: 13pt;--ck-content-line-height: 1.15}:host ::ng-deep .ck-editor__top,:host ::ng-deep .ck-editor__main{border:none!important;box-shadow:none!important}:host ::ng-deep .ck-editor__top{position:sticky;top:0;z-index:100;width:100%;min-width:600px;margin-bottom:10px}:host ::ng-deep .ck-editor__top .ck-sticky-panel__content{border:none!important}:host ::ng-deep .ck-editor__top .ck-toolbar{background:#fff!important;box-shadow:none!important;border-radius:8px;padding:8px!important}:host ::ng-deep .ck-editor__top .ck-toolbar .ck-toolbar__items{display:flex;justify-content:center;flex-wrap:wrap;align-items:center}:host ::ng-deep .ck-content{background-color:#fff;width:210mm;min-height:1123px;padding:20mm!important;box-sizing:border-box!important;box-shadow:0 10px 15px -3px #0000001a}:host ::ng-deep .ck-content h1,:host ::ng-deep .ck-content h2,:host ::ng-deep .ck-content h3,:host ::ng-deep .ck-content h4,:host ::ng-deep .ck-content h5,:host ::ng-deep .ck-content h6{font-weight:400;font-size:inherit;line-height:inherit;margin-bottom:4px}:host ::ng-deep .ck-content.landscape{width:297mm}:host ::ng-deep .ck-content>*{max-width:100%!important;box-sizing:border-box!important}:host ::ng-deep .ck-content p{margin-bottom:4px;text-indent:0}:host ::ng-deep .ck-content ul,:host ::ng-deep .ck-content ol{padding-left:20px!important;margin-left:0!important;margin-bottom:4px}:host ::ng-deep .ck-content li{margin-bottom:0}:host ::ng-deep .ck-content table{margin-bottom:4px}\n", ":host ::ng-deep .ck-heading-highlight{background-color:#fef08a}\n", "@charset \"UTF-8\";::ng-deep .ck-clipboard-drop-target-line{display:none!important}:host ::ng-deep .variable-widget{display:inline-block;-webkit-user-select:none;user-select:none}:host ::ng-deep .variable-widget:not([data-binding=true]){background-color:#e3f2fd;color:#1976d2;border:1px solid #90caf9!important;border-radius:4px;padding:2px 6px;font-size:0;margin:0 2px;vertical-align:middle;font-weight:600;cursor:default}:host ::ng-deep .variable-widget:not([data-binding=true]):before{content:attr(data-display);font-size:10px;font-family:Segoe UI,Tahoma,Geneva,Verdana,sans-serif}:host ::ng-deep .variable-widget:not([data-binding=true]):hover{background-color:#bbdefb;box-shadow:0 1px 2px #0000001a}:host ::ng-deep .variable-widget:not([data-binding=true]).ck-widget_selected{outline:2px solid #2196f3;background-color:#bbdefb}:host ::ng-deep .variable-widget[data-binding=true]{background-color:#4caf501f;color:#2e7d32;border-bottom:2px solid #4caf50!important;border-radius:0;padding:0 1px;font-size:inherit;cursor:default}:host ::ng-deep .variable-widget[data-binding=true]:before{content:none}:host ::ng-deep .variable-widget[data-binding=true]:hover{background-color:#4caf5038}:host ::ng-deep .variable-widget[data-binding=true].ck-widget_selected{outline:2px solid #4caf50;background-color:#4caf5047}:host ::ng-deep .ck.ck-content .ck-widget,:host ::ng-deep .ck.ck-content .ck-widget:hover,:host ::ng-deep .ck.ck-content .ck-widget:focus,:host ::ng-deep .ck.ck-content .ck-widget.ck-widget_selected,:host ::ng-deep .ck.ck-content .ck-widget.ck-widget_selected:hover{outline:none!important;box-shadow:none!important}\n", ":host ::ng-deep .highlight-range{background-color:#ffeb3b80;border-bottom:2px solid #fbc02d;transition:background-color .2s;cursor:pointer}\n", ":host ::ng-deep .ck-comment-marker{background-color:var(--comment-bg, rgba(59, 130, 246, .3));border-bottom:2px solid rgb(59,130,246);cursor:pointer;transition:all .2s ease}:host ::ng-deep .ck-comment-marker:hover{opacity:.8}:host ::ng-deep .ck-comment-marker.ck-comment-pending{background-color:var(--comment-pending-bg, rgba(245, 158, 11, .4));border-bottom-color:#f59e0b}:host ::ng-deep .ck-comment-marker.ck-comment-normal{background-color:var(--comment-bg, rgba(59, 130, 246, .2));border-bottom-color:#3b82f6}:host ::ng-deep .ck-comment-marker.ck-comment-selected{background-color:var(--comment-selected-bg, 59, 130, 246, .5);border-bottom-color:#3b82f6}:host ::ng-deep .ck-comment-marker.ck-comment-modified{background-color:var(--comment-modified-bg, rgba(249, 115, 22, .3));border-bottom-color:#f97316}:host ::ng-deep .ck-comment-marker.ck-comment-broken{background-color:var(--comment-broken-bg, rgba(239, 68, 68, .3));border-bottom-color:#ef4444;text-decoration:line-through;text-decoration-color:#ef4444}:host ::ng-deep .ck-balloon-panel .ck-button.ck-on:hover,:host ::ng-deep .ck-balloon-panel .ck-button.ck-off:hover{background:var(--ck-color-button-default-hover-background)}\n"], dependencies: [{ kind: "ngmodule", type: CommonModule }, { kind: "ngmodule", type: CKEditorModule }, { kind: "component", type: i1.CKEditorComponent, selector: "ckeditor", inputs: ["editor", "config", "data", "tagName", "watchdog", "editorWatchdogConfig", "disableWatchdog", "disableTwoWayDataBinding", "disabled"], outputs: ["ready", "change", "blur", "focus", "error"] }] });
4932
4941
  }
4933
4942
  i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.2.17", ngImport: i0, type: SdDocumentBuilder, decorators: [{
4934
4943
  type: Component,
4935
- args: [{ selector: 'sd-document-builder', standalone: true, imports: [CommonModule, CKEditorModule], template: "<div class=\"builder-container\">\n <ckeditor\n style=\"width: 100%\"\n [editor]=\"Editor\" \n [config]=\"config\" \n (ready)=\"onReady($event)\"\n [disabled]=\"disabled\">\n </ckeditor>\n</div>", styles: ["@charset \"UTF-8\";.builder-container{background-color:#f3f4f6;height:100%;overflow-y:auto;width:100%;display:flex;flex-direction:column;align-items:center}:host{display:inline-block}:host ::ng-deep .ck-editor{display:flex;flex-direction:column;align-items:center;width:100%;--ck-content-font-family: \"Times New Roman\", serif !important;--ck-content-font-size: 13pt;--ck-content-line-height: 1.15}:host ::ng-deep .ck-editor__top,:host ::ng-deep .ck-editor__main{border:none!important;box-shadow:none!important}:host ::ng-deep .ck-editor__top{position:sticky;top:0;z-index:100;width:100%;min-width:600px;margin-bottom:10px}:host ::ng-deep .ck-editor__top .ck-sticky-panel__content{border:none!important}:host ::ng-deep .ck-editor__top .ck-toolbar{background:#fff!important;box-shadow:0 4px 6px -1px #0000001a!important;padding:8px!important}:host ::ng-deep .ck-editor__top .ck-toolbar .ck-toolbar__items{display:flex;justify-content:center;flex-wrap:wrap;align-items:center}:host ::ng-deep .ck-content{background-color:#fff;width:210mm;min-height:1123px;padding:20mm!important;box-sizing:border-box!important;box-shadow:0 10px 15px -3px #0000001a}:host ::ng-deep .ck-content h1,:host ::ng-deep .ck-content h2,:host ::ng-deep .ck-content h3,:host ::ng-deep .ck-content h4,:host ::ng-deep .ck-content h5,:host ::ng-deep .ck-content h6{font-weight:400;font-size:inherit;line-height:inherit;margin-bottom:4px}:host ::ng-deep .ck-content.landscape{width:297mm}:host ::ng-deep .ck-content>*{max-width:100%!important;box-sizing:border-box!important}:host ::ng-deep .ck-content p{margin-bottom:4px;text-indent:0}:host ::ng-deep .ck-content ul,:host ::ng-deep .ck-content ol{padding-left:20px!important;margin-left:0!important;margin-bottom:4px}:host ::ng-deep .ck-content li{margin-bottom:0}:host ::ng-deep .ck-content table{margin-bottom:4px}\n", ":host ::ng-deep .ck-heading-highlight{background-color:#fef08a}\n", "@charset \"UTF-8\";::ng-deep .ck-clipboard-drop-target-line{display:none!important}:host ::ng-deep .variable-widget{display:inline-block;-webkit-user-select:none;user-select:none}:host ::ng-deep .variable-widget:not([data-binding=true]){background-color:#e3f2fd;color:#1976d2;border:1px solid #90caf9!important;border-radius:4px;padding:2px 6px;font-size:0;margin:0 2px;vertical-align:middle;font-weight:600;cursor:default}:host ::ng-deep .variable-widget:not([data-binding=true]):before{content:attr(data-display);font-size:10px;font-family:Segoe UI,Tahoma,Geneva,Verdana,sans-serif}:host ::ng-deep .variable-widget:not([data-binding=true]):hover{background-color:#bbdefb;box-shadow:0 1px 2px #0000001a}:host ::ng-deep .variable-widget:not([data-binding=true]).ck-widget_selected{outline:2px solid #2196f3;background-color:#bbdefb}:host ::ng-deep .variable-widget[data-binding=true]{background-color:#4caf501f;color:#2e7d32;border-bottom:2px solid #4caf50!important;border-radius:0;padding:0 1px;font-size:inherit;cursor:default}:host ::ng-deep .variable-widget[data-binding=true]:before{content:none}:host ::ng-deep .variable-widget[data-binding=true]:hover{background-color:#4caf5038}:host ::ng-deep .variable-widget[data-binding=true].ck-widget_selected{outline:2px solid #4caf50;background-color:#4caf5047}:host ::ng-deep .ck.ck-content .ck-widget,:host ::ng-deep .ck.ck-content .ck-widget:hover,:host ::ng-deep .ck.ck-content .ck-widget:focus,:host ::ng-deep .ck.ck-content .ck-widget.ck-widget_selected,:host ::ng-deep .ck.ck-content .ck-widget.ck-widget_selected:hover{outline:none!important;box-shadow:none!important}\n", ":host ::ng-deep .highlight-range{background-color:#ffeb3b80;border-bottom:2px solid #fbc02d;transition:background-color .2s;cursor:pointer}\n", ":host ::ng-deep .ck-comment-marker{background-color:var(--comment-bg, rgba(59, 130, 246, .3));border-bottom:2px solid rgb(59,130,246);cursor:pointer;transition:all .2s ease}:host ::ng-deep .ck-comment-marker:hover{opacity:.8}:host ::ng-deep .ck-comment-marker.ck-comment-pending{background-color:var(--comment-pending-bg, rgba(245, 158, 11, .4));border-bottom-color:#f59e0b}:host ::ng-deep .ck-comment-marker.ck-comment-normal{background-color:var(--comment-bg, rgba(59, 130, 246, .2));border-bottom-color:#3b82f6}:host ::ng-deep .ck-comment-marker.ck-comment-selected{background-color:var(--comment-selected-bg, 59, 130, 246, .5);border-bottom-color:#3b82f6}:host ::ng-deep .ck-comment-marker.ck-comment-modified{background-color:var(--comment-modified-bg, rgba(249, 115, 22, .3));border-bottom-color:#f97316}:host ::ng-deep .ck-comment-marker.ck-comment-broken{background-color:var(--comment-broken-bg, rgba(239, 68, 68, .3));border-bottom-color:#ef4444;text-decoration:line-through;text-decoration-color:#ef4444}:host ::ng-deep .ck-balloon-panel .ck-button.ck-on:hover,:host ::ng-deep .ck-balloon-panel .ck-button.ck-off:hover{background:var(--ck-color-button-default-hover-background)}\n"] }]
4944
+ args: [{ selector: 'sd-document-builder', standalone: true, imports: [CommonModule, CKEditorModule], template: "<div class=\"builder-container\">\r\n <ckeditor class=\"w-full\" [editor]=\"Editor\" [config]=\"config\" (ready)=\"onReady($event)\" [disabled]=\"disabled\"> </ckeditor>\r\n</div>\r\n", styles: ["@charset \"UTF-8\";.builder-container{height:100%;overflow-y:auto;width:100%;display:flex;flex-direction:column;align-items:center}:host{display:inline-block}:host ::ng-deep .ck-editor{display:flex;flex-direction:column;align-items:center;width:100%;--ck-content-font-family: \"Times New Roman\", serif !important;--ck-content-font-size: 13pt;--ck-content-line-height: 1.15}:host ::ng-deep .ck-editor__top,:host ::ng-deep .ck-editor__main{border:none!important;box-shadow:none!important}:host ::ng-deep .ck-editor__top{position:sticky;top:0;z-index:100;width:100%;min-width:600px;margin-bottom:10px}:host ::ng-deep .ck-editor__top .ck-sticky-panel__content{border:none!important}:host ::ng-deep .ck-editor__top .ck-toolbar{background:#fff!important;box-shadow:none!important;border-radius:8px;padding:8px!important}:host ::ng-deep .ck-editor__top .ck-toolbar .ck-toolbar__items{display:flex;justify-content:center;flex-wrap:wrap;align-items:center}:host ::ng-deep .ck-content{background-color:#fff;width:210mm;min-height:1123px;padding:20mm!important;box-sizing:border-box!important;box-shadow:0 10px 15px -3px #0000001a}:host ::ng-deep .ck-content h1,:host ::ng-deep .ck-content h2,:host ::ng-deep .ck-content h3,:host ::ng-deep .ck-content h4,:host ::ng-deep .ck-content h5,:host ::ng-deep .ck-content h6{font-weight:400;font-size:inherit;line-height:inherit;margin-bottom:4px}:host ::ng-deep .ck-content.landscape{width:297mm}:host ::ng-deep .ck-content>*{max-width:100%!important;box-sizing:border-box!important}:host ::ng-deep .ck-content p{margin-bottom:4px;text-indent:0}:host ::ng-deep .ck-content ul,:host ::ng-deep .ck-content ol{padding-left:20px!important;margin-left:0!important;margin-bottom:4px}:host ::ng-deep .ck-content li{margin-bottom:0}:host ::ng-deep .ck-content table{margin-bottom:4px}\n", ":host ::ng-deep .ck-heading-highlight{background-color:#fef08a}\n", "@charset \"UTF-8\";::ng-deep .ck-clipboard-drop-target-line{display:none!important}:host ::ng-deep .variable-widget{display:inline-block;-webkit-user-select:none;user-select:none}:host ::ng-deep .variable-widget:not([data-binding=true]){background-color:#e3f2fd;color:#1976d2;border:1px solid #90caf9!important;border-radius:4px;padding:2px 6px;font-size:0;margin:0 2px;vertical-align:middle;font-weight:600;cursor:default}:host ::ng-deep .variable-widget:not([data-binding=true]):before{content:attr(data-display);font-size:10px;font-family:Segoe UI,Tahoma,Geneva,Verdana,sans-serif}:host ::ng-deep .variable-widget:not([data-binding=true]):hover{background-color:#bbdefb;box-shadow:0 1px 2px #0000001a}:host ::ng-deep .variable-widget:not([data-binding=true]).ck-widget_selected{outline:2px solid #2196f3;background-color:#bbdefb}:host ::ng-deep .variable-widget[data-binding=true]{background-color:#4caf501f;color:#2e7d32;border-bottom:2px solid #4caf50!important;border-radius:0;padding:0 1px;font-size:inherit;cursor:default}:host ::ng-deep .variable-widget[data-binding=true]:before{content:none}:host ::ng-deep .variable-widget[data-binding=true]:hover{background-color:#4caf5038}:host ::ng-deep .variable-widget[data-binding=true].ck-widget_selected{outline:2px solid #4caf50;background-color:#4caf5047}:host ::ng-deep .ck.ck-content .ck-widget,:host ::ng-deep .ck.ck-content .ck-widget:hover,:host ::ng-deep .ck.ck-content .ck-widget:focus,:host ::ng-deep .ck.ck-content .ck-widget.ck-widget_selected,:host ::ng-deep .ck.ck-content .ck-widget.ck-widget_selected:hover{outline:none!important;box-shadow:none!important}\n", ":host ::ng-deep .highlight-range{background-color:#ffeb3b80;border-bottom:2px solid #fbc02d;transition:background-color .2s;cursor:pointer}\n", ":host ::ng-deep .ck-comment-marker{background-color:var(--comment-bg, rgba(59, 130, 246, .3));border-bottom:2px solid rgb(59,130,246);cursor:pointer;transition:all .2s ease}:host ::ng-deep .ck-comment-marker:hover{opacity:.8}:host ::ng-deep .ck-comment-marker.ck-comment-pending{background-color:var(--comment-pending-bg, rgba(245, 158, 11, .4));border-bottom-color:#f59e0b}:host ::ng-deep .ck-comment-marker.ck-comment-normal{background-color:var(--comment-bg, rgba(59, 130, 246, .2));border-bottom-color:#3b82f6}:host ::ng-deep .ck-comment-marker.ck-comment-selected{background-color:var(--comment-selected-bg, 59, 130, 246, .5);border-bottom-color:#3b82f6}:host ::ng-deep .ck-comment-marker.ck-comment-modified{background-color:var(--comment-modified-bg, rgba(249, 115, 22, .3));border-bottom-color:#f97316}:host ::ng-deep .ck-comment-marker.ck-comment-broken{background-color:var(--comment-broken-bg, rgba(239, 68, 68, .3));border-bottom-color:#ef4444;text-decoration:line-through;text-decoration-color:#ef4444}:host ::ng-deep .ck-balloon-panel .ck-button.ck-on:hover,:host ::ng-deep .ck-balloon-panel .ck-button.ck-off:hover{background:var(--ck-color-button-default-hover-background)}\n"] }]
4936
4945
  }], propDecorators: { option: [{
4937
4946
  type: Input,
4938
4947
  args: [{ required: true }]