@foxeltech/angular-ui 0.7.83 → 0.7.101
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/components.css +40 -1
- package/fesm2022/foxeltech-angular-ui-chart.mjs +33 -3
- package/fesm2022/foxeltech-angular-ui-chart.mjs.map +1 -1
- package/fesm2022/foxeltech-angular-ui-flow.mjs +42 -5
- package/fesm2022/foxeltech-angular-ui-flow.mjs.map +1 -1
- package/fesm2022/foxeltech-angular-ui.mjs +559 -42
- package/fesm2022/foxeltech-angular-ui.mjs.map +1 -1
- package/package.json +3 -2
- package/src/lib/styles/components.css +40 -1
- package/src/lib/styles/utilities.css +2 -1
- package/src/lib/ui/components/breadcrumb/breadcrumb.component.css +262 -0
- package/src/lib/ui/components/breadcrumb/breadcrumb.component.html +91 -0
- package/src/lib/ui/components/button/button.component.html +1 -0
- package/src/lib/ui/components/filter-pills/filter-pills.component.html +1 -1
- package/src/lib/ui/components/load-status/load-status.component.css +96 -0
- package/src/lib/ui/components/load-status/load-status.component.html +20 -0
- package/src/lib/ui/components/master-detail/master-detail.component.css +63 -11
- package/src/lib/ui/components/master-detail/master-detail.component.html +71 -42
- package/src/lib/ui/components/route-skeleton/route-skeleton.component.css +1 -1
- package/src/lib/ui/components/segmented/segmented.component.html +3 -1
- package/src/lib/ui/components/severity-badges/severity-badges.component.html +1 -1
- package/src/lib/ui/components/stat-cards/stat-cards.component.css +18 -0
- package/src/lib/ui/components/stat-cards/stat-cards.component.html +3 -3
- package/types/foxeltech-angular-ui-chart.d.ts +18 -1
- package/types/foxeltech-angular-ui-flow.d.ts +7 -0
- package/types/foxeltech-angular-ui.d.ts +309 -8
- package/utilities.css +2 -1
package/components.css
CHANGED
|
@@ -361,6 +361,14 @@ input[type='password'] {
|
|
|
361
361
|
inset 0 0 0 1px rgb(0 0 0 / 0.08),
|
|
362
362
|
0 1px 2px rgb(0 0 0 / 0.12);
|
|
363
363
|
}
|
|
364
|
+
/* Icon-only button (no label): square h-8 × w-8, no side padding, so the
|
|
365
|
+
glyph sits dead-centre (anh Tú 04/09). Consumers may still size it with
|
|
366
|
+
utilities (`w-9 h-9`) — those win in the utilities layer. */
|
|
367
|
+
.fx-btn--icon {
|
|
368
|
+
width: 2rem;
|
|
369
|
+
padding-left: 0;
|
|
370
|
+
padding-right: 0;
|
|
371
|
+
}
|
|
364
372
|
/* Nút hành động chính theo demo (`.bi-newbtn`): màu cố định, không phải accent. */
|
|
365
373
|
/* ---- Tông severity theo ĐÚNG mô hình demo (đo 03/09) -----------------
|
|
366
374
|
Demo KHÔNG tô badge bằng màu rực. Nó dùng token semantic, và bậc nặng
|
|
@@ -755,6 +763,17 @@ input[type='password'] {
|
|
|
755
763
|
max-height: calc(100vh - 315px);
|
|
756
764
|
overflow: auto;
|
|
757
765
|
}
|
|
766
|
+
/* Phones: a data table must not squeeze its columns to a few px per cell —
|
|
767
|
+
give it a floor and let .table-page-container scroll it sideways
|
|
768
|
+
(anh Tú 04/09 mobile audit: Name column collapsed to one character/line). */
|
|
769
|
+
@media (max-width: 719px) {
|
|
770
|
+
/* !important like the other .mat-mdc-table overrides above: this file is
|
|
771
|
+
imported into a cascade @layer, so an unlayered Material rule
|
|
772
|
+
(`.mat-mdc-table{min-width:100%}`) beats it whatever the specificity. */
|
|
773
|
+
.mat-mdc-table {
|
|
774
|
+
min-width: 640px !important;
|
|
775
|
+
}
|
|
776
|
+
}
|
|
758
777
|
.table-cell-padding {
|
|
759
778
|
padding-top: 8px !important;
|
|
760
779
|
padding-bottom: 8px !important;
|
|
@@ -790,8 +809,28 @@ input[type='password'] {
|
|
|
790
809
|
rgb(var(--gradient-primary-end))
|
|
791
810
|
) border-box;
|
|
792
811
|
}
|
|
812
|
+
/* Skeleton block = the design's `.bi-sk` shimmer ("Loading States", 04/09):
|
|
813
|
+
text at 7% → 13% → 7% sweeping left→right over 1.15 s, 6px radius. One
|
|
814
|
+
rule for every skeleton in the product — route skeleton, table cells,
|
|
815
|
+
dashboard cards — so the boot splash, route and in-panel states match. */
|
|
793
816
|
.skeleton-load {
|
|
794
|
-
|
|
817
|
+
display: block;
|
|
818
|
+
border-radius: 6px;
|
|
819
|
+
background: linear-gradient(
|
|
820
|
+
90deg,
|
|
821
|
+
rgb(var(--og-text) / 0.07) 0px,
|
|
822
|
+
rgb(var(--og-text) / 0.13) 90px,
|
|
823
|
+
rgb(var(--og-text) / 0.07) 180px
|
|
824
|
+
);
|
|
825
|
+
background-size: 400px 100%;
|
|
826
|
+
animation: fx-shimmer 1.15s linear infinite;
|
|
827
|
+
}
|
|
828
|
+
@keyframes fx-shimmer {
|
|
829
|
+
0% { background-position: -260px 0; }
|
|
830
|
+
100% { background-position: 260px 0; }
|
|
831
|
+
}
|
|
832
|
+
@media (prefers-reduced-motion: reduce) {
|
|
833
|
+
.skeleton-load { animation: none; background: rgb(var(--og-text) / 0.08); }
|
|
795
834
|
}
|
|
796
835
|
|
|
797
836
|
/* ============================================================================
|
|
@@ -41,6 +41,8 @@ class ChartComponent {
|
|
|
41
41
|
* dom.". Chỉ dựng directive khi đã có options thật ⇒ đúng một lần init.
|
|
42
42
|
*/
|
|
43
43
|
hasOptions = false;
|
|
44
|
+
/** Heights (%) of the pre-init placeholder bars — a fixed, calm silhouette. */
|
|
45
|
+
placeholderBars = [34, 52, 44, 66, 58, 78, 70, 88, 62, 74];
|
|
44
46
|
labelFontSize = 12;
|
|
45
47
|
chartInstance;
|
|
46
48
|
resizeObserver;
|
|
@@ -715,19 +717,47 @@ class ChartComponent {
|
|
|
715
717
|
});
|
|
716
718
|
}
|
|
717
719
|
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.20", ngImport: i0, type: ChartComponent, deps: [{ token: i0.ElementRef }, { token: i0.ChangeDetectorRef }], target: i0.ɵɵFactoryTarget.Component });
|
|
718
|
-
static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "21.2.20", type: ChartComponent, isStandalone: true, selector: "fx-ui-chart", inputs: { type: { classPropertyName: "type", publicName: "type", isSignal: true, isRequired: false, transformFunction: null }, data: { classPropertyName: "data", publicName: "data", isSignal: true, isRequired: false, transformFunction: null }, options: { classPropertyName: "options", publicName: "options", isSignal: true, isRequired: false, transformFunction: null }, palette: { classPropertyName: "palette", publicName: "palette", isSignal: true, isRequired: false, transformFunction: null }, height: { classPropertyName: "height", publicName: "height", isSignal: true, isRequired: false, transformFunction: null }, loading: { classPropertyName: "loading", publicName: "loading", isSignal: true, isRequired: false, transformFunction: null }, pieLegendAlign: { classPropertyName: "pieLegendAlign", publicName: "pieLegendAlign", isSignal: true, isRequired: false, transformFunction: null }, pieLegendPosition: { classPropertyName: "pieLegendPosition", publicName: "pieLegendPosition", isSignal: true, isRequired: false, transformFunction: null }, showPieLabel: { classPropertyName: "showPieLabel", publicName: "showPieLabel", isSignal: true, isRequired: false, transformFunction: null }, showPieLegend: { classPropertyName: "showPieLegend", publicName: "showPieLegend", isSignal: true, isRequired: false, transformFunction: null }, pieCenterLabel: { classPropertyName: "pieCenterLabel", publicName: "pieCenterLabel", isSignal: true, isRequired: false, transformFunction: null }, mobileWidth: { classPropertyName: "mobileWidth", publicName: "mobileWidth", isSignal: true, isRequired: false, transformFunction: null }, labelFontFamily: { classPropertyName: "labelFontFamily", publicName: "labelFontFamily", isSignal: true, isRequired: false, transformFunction: null }, emptyText: { classPropertyName: "emptyText", publicName: "emptyText", isSignal: true, isRequired: false, transformFunction: null } }, outputs: { chartClick: "chartClick", chartInit: "chartInit" }, host: { listeners: { "window:theme-changed": "onThemeChange()" } }, providers: [provideEchartsCore({ echarts: () => import('echarts') })], usesOnChanges: true, ngImport: i0, template: "<div class=\"chart-wrapper\" [style.height]=\"height()\">\n @if (isEmpty) {\n <div class=\"chart-empty\">\n <svg xmlns=\"http://www.w3.org/2000/svg\" fill=\"none\" viewBox=\"0 0 24 24\" stroke-width=\"1.5\" stroke=\"currentColor\" class=\"chart-empty-icon\">\n <path stroke-linecap=\"round\" stroke-linejoin=\"round\" d=\"M3 13.125C3 12.504 3.504 12 4.125 12h2.25c.621 0 1.125.504 1.125 1.125v6.75C7.5 20.496 6.996 21 6.375 21h-2.25A1.125 1.125 0 0 1 3 19.875v-6.75ZM9.75 8.625c0-.621.504-1.125 1.125-1.125h2.25c.621 0 1.125.504 1.125 1.125v11.25c0 .621-.504 1.125-1.125 1.125h-2.25a1.125 1.125 0 0 1-1.125-1.125V8.625ZM16.5 4.125c0-.621.504-1.125 1.125-1.125h2.25C20.496 3 21 3.504 21 4.125v15.75c0 .621-.504 1.125-1.125 1.125h-2.25a1.125 1.125 0 0 1-1.125-1.125V4.125Z\" />\n </svg>\n <span class=\"chart-empty-text\">{{ emptyText() }}</span>\n </div>\n } @else if (hasOptions) {\n <div\n echarts\n [options]=\"chartOptions\"\n [loading]=\"loading()\"\n (chartInit)=\"onChartInit($event)\"\n (chartClick)=\"onChartClick($event)\"\n class=\"fx-chart\"\n [style.height]=\"height()\"\n ></div>\n }\n</div>\n", styles: ["
|
|
720
|
+
static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "21.2.20", type: ChartComponent, isStandalone: true, selector: "fx-ui-chart", inputs: { type: { classPropertyName: "type", publicName: "type", isSignal: true, isRequired: false, transformFunction: null }, data: { classPropertyName: "data", publicName: "data", isSignal: true, isRequired: false, transformFunction: null }, options: { classPropertyName: "options", publicName: "options", isSignal: true, isRequired: false, transformFunction: null }, palette: { classPropertyName: "palette", publicName: "palette", isSignal: true, isRequired: false, transformFunction: null }, height: { classPropertyName: "height", publicName: "height", isSignal: true, isRequired: false, transformFunction: null }, loading: { classPropertyName: "loading", publicName: "loading", isSignal: true, isRequired: false, transformFunction: null }, pieLegendAlign: { classPropertyName: "pieLegendAlign", publicName: "pieLegendAlign", isSignal: true, isRequired: false, transformFunction: null }, pieLegendPosition: { classPropertyName: "pieLegendPosition", publicName: "pieLegendPosition", isSignal: true, isRequired: false, transformFunction: null }, showPieLabel: { classPropertyName: "showPieLabel", publicName: "showPieLabel", isSignal: true, isRequired: false, transformFunction: null }, showPieLegend: { classPropertyName: "showPieLegend", publicName: "showPieLegend", isSignal: true, isRequired: false, transformFunction: null }, pieCenterLabel: { classPropertyName: "pieCenterLabel", publicName: "pieCenterLabel", isSignal: true, isRequired: false, transformFunction: null }, mobileWidth: { classPropertyName: "mobileWidth", publicName: "mobileWidth", isSignal: true, isRequired: false, transformFunction: null }, labelFontFamily: { classPropertyName: "labelFontFamily", publicName: "labelFontFamily", isSignal: true, isRequired: false, transformFunction: null }, emptyText: { classPropertyName: "emptyText", publicName: "emptyText", isSignal: true, isRequired: false, transformFunction: null } }, outputs: { chartClick: "chartClick", chartInit: "chartInit" }, host: { listeners: { "window:theme-changed": "onThemeChange()" } }, providers: [provideEchartsCore({ echarts: () => import('echarts') })], usesOnChanges: true, ngImport: i0, template: "<div class=\"chart-wrapper\" [style.height]=\"height()\">\n @if (isEmpty) {\n <div class=\"chart-empty\">\n <svg xmlns=\"http://www.w3.org/2000/svg\" fill=\"none\" viewBox=\"0 0 24 24\" stroke-width=\"1.5\" stroke=\"currentColor\" class=\"chart-empty-icon\">\n <path stroke-linecap=\"round\" stroke-linejoin=\"round\" d=\"M3 13.125C3 12.504 3.504 12 4.125 12h2.25c.621 0 1.125.504 1.125 1.125v6.75C7.5 20.496 6.996 21 6.375 21h-2.25A1.125 1.125 0 0 1 3 19.875v-6.75ZM9.75 8.625c0-.621.504-1.125 1.125-1.125h2.25c.621 0 1.125.504 1.125 1.125v11.25c0 .621-.504 1.125-1.125 1.125h-2.25a1.125 1.125 0 0 1-1.125-1.125V8.625ZM16.5 4.125c0-.621.504-1.125 1.125-1.125h2.25C20.496 3 21 3.504 21 4.125v15.75c0 .621-.504 1.125-1.125 1.125h-2.25a1.125 1.125 0 0 1-1.125-1.125V4.125Z\" />\n </svg>\n <span class=\"chart-empty-text\">{{ emptyText() }}</span>\n </div>\n } @else if (hasOptions) {\n <div\n echarts\n [options]=\"chartOptions\"\n [loading]=\"loading()\"\n (chartInit)=\"onChartInit($event)\"\n (chartClick)=\"onChartClick($event)\"\n class=\"fx-chart\"\n [style.height]=\"height()\"\n ></div>\n } @else {\n <!-- Until echarts is loaded + initialised (or the element scrolls into view)\n the panel keeps the chart's footprint with a quiet pulsing sketch\n instead of an empty box (anh T\u00FA 04/09: \"the page is too blank\"). -->\n <div class=\"chart-placeholder\" aria-hidden=\"true\">\n @for (h of placeholderBars; track $index) {\n <span class=\"chart-placeholder__bar\" [style.height.%]=\"h\"></span>\n }\n </div>\n }\n</div>\n", styles: ["@charset \"UTF-8\";:host{display:block;width:100%}.chart-wrapper{position:relative;width:100%;height:100%}.chart-container{width:100%;height:100%}.chart-loader{position:absolute;inset:0;display:flex;align-items:center;justify-content:center;background:rgba(var(--bg-primary-hover)/.6);font-weight:500;font-size:1.1rem;z-index:2;border-radius:4px}.chart-empty{display:flex;flex-direction:column;align-items:center;justify-content:center;height:100%;gap:12px;color:rgba(var(--text-secondary)/1)}.chart-empty-icon{width:48px;height:48px;opacity:.4}.chart-empty-text{font-size:14px;font-weight:500}.chart-placeholder{position:absolute;inset:0;display:flex;align-items:flex-end;gap:6px;padding:12px 8px 22px;animation:chart-placeholder-pulse 1.6s ease-in-out infinite}.chart-placeholder__bar{flex:1;border-radius:3px 3px 0 0;background:rgb(var(--og-track))}@keyframes chart-placeholder-pulse{0%,to{opacity:1}50%{opacity:.45}}@media(prefers-reduced-motion:reduce){.chart-placeholder{animation:none}}\n"], dependencies: [{ kind: "directive", type: NgxEchartsDirective, selector: "echarts, [echarts]", inputs: ["options", "theme", "initOpts", "merge", "autoResize", "loading", "loadingType", "loadingOpts"], outputs: ["chartInit", "optionsError", "chartClick", "chartDblClick", "chartMouseDown", "chartMouseMove", "chartMouseUp", "chartMouseOver", "chartMouseOut", "chartGlobalOut", "chartContextMenu", "chartHighlight", "chartDownplay", "chartSelectChanged", "chartLegendSelectChanged", "chartLegendSelected", "chartLegendUnselected", "chartLegendLegendSelectAll", "chartLegendLegendInverseSelect", "chartLegendScroll", "chartDataZoom", "chartDataRangeSelected", "chartGraphRoam", "chartGeoRoam", "chartTreeRoam", "chartTimelineChanged", "chartTimelinePlayChanged", "chartRestore", "chartDataViewChanged", "chartMagicTypeChanged", "chartGeoSelectChanged", "chartGeoSelected", "chartGeoUnselected", "chartAxisAreaSelected", "chartBrush", "chartBrushEnd", "chartBrushSelected", "chartGlobalCursorTaken", "chartRendered", "chartFinished"], exportAs: ["echarts"] }], changeDetection: i0.ChangeDetectionStrategy.OnPush });
|
|
719
721
|
}
|
|
720
722
|
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.20", ngImport: i0, type: ChartComponent, decorators: [{
|
|
721
723
|
type: Component,
|
|
722
|
-
args: [{ selector: 'fx-ui-chart', changeDetection: ChangeDetectionStrategy.OnPush, imports: [NgxEchartsDirective, InputComponent], providers: [provideEchartsCore({ echarts: () => import('echarts') })], template: "<div class=\"chart-wrapper\" [style.height]=\"height()\">\n @if (isEmpty) {\n <div class=\"chart-empty\">\n <svg xmlns=\"http://www.w3.org/2000/svg\" fill=\"none\" viewBox=\"0 0 24 24\" stroke-width=\"1.5\" stroke=\"currentColor\" class=\"chart-empty-icon\">\n <path stroke-linecap=\"round\" stroke-linejoin=\"round\" d=\"M3 13.125C3 12.504 3.504 12 4.125 12h2.25c.621 0 1.125.504 1.125 1.125v6.75C7.5 20.496 6.996 21 6.375 21h-2.25A1.125 1.125 0 0 1 3 19.875v-6.75ZM9.75 8.625c0-.621.504-1.125 1.125-1.125h2.25c.621 0 1.125.504 1.125 1.125v11.25c0 .621-.504 1.125-1.125 1.125h-2.25a1.125 1.125 0 0 1-1.125-1.125V8.625ZM16.5 4.125c0-.621.504-1.125 1.125-1.125h2.25C20.496 3 21 3.504 21 4.125v15.75c0 .621-.504 1.125-1.125 1.125h-2.25a1.125 1.125 0 0 1-1.125-1.125V4.125Z\" />\n </svg>\n <span class=\"chart-empty-text\">{{ emptyText() }}</span>\n </div>\n } @else if (hasOptions) {\n <div\n echarts\n [options]=\"chartOptions\"\n [loading]=\"loading()\"\n (chartInit)=\"onChartInit($event)\"\n (chartClick)=\"onChartClick($event)\"\n class=\"fx-chart\"\n [style.height]=\"height()\"\n ></div>\n }\n</div>\n", styles: ["
|
|
724
|
+
args: [{ selector: 'fx-ui-chart', changeDetection: ChangeDetectionStrategy.OnPush, imports: [NgxEchartsDirective, InputComponent], providers: [provideEchartsCore({ echarts: () => import('echarts') })], template: "<div class=\"chart-wrapper\" [style.height]=\"height()\">\n @if (isEmpty) {\n <div class=\"chart-empty\">\n <svg xmlns=\"http://www.w3.org/2000/svg\" fill=\"none\" viewBox=\"0 0 24 24\" stroke-width=\"1.5\" stroke=\"currentColor\" class=\"chart-empty-icon\">\n <path stroke-linecap=\"round\" stroke-linejoin=\"round\" d=\"M3 13.125C3 12.504 3.504 12 4.125 12h2.25c.621 0 1.125.504 1.125 1.125v6.75C7.5 20.496 6.996 21 6.375 21h-2.25A1.125 1.125 0 0 1 3 19.875v-6.75ZM9.75 8.625c0-.621.504-1.125 1.125-1.125h2.25c.621 0 1.125.504 1.125 1.125v11.25c0 .621-.504 1.125-1.125 1.125h-2.25a1.125 1.125 0 0 1-1.125-1.125V8.625ZM16.5 4.125c0-.621.504-1.125 1.125-1.125h2.25C20.496 3 21 3.504 21 4.125v15.75c0 .621-.504 1.125-1.125 1.125h-2.25a1.125 1.125 0 0 1-1.125-1.125V4.125Z\" />\n </svg>\n <span class=\"chart-empty-text\">{{ emptyText() }}</span>\n </div>\n } @else if (hasOptions) {\n <div\n echarts\n [options]=\"chartOptions\"\n [loading]=\"loading()\"\n (chartInit)=\"onChartInit($event)\"\n (chartClick)=\"onChartClick($event)\"\n class=\"fx-chart\"\n [style.height]=\"height()\"\n ></div>\n } @else {\n <!-- Until echarts is loaded + initialised (or the element scrolls into view)\n the panel keeps the chart's footprint with a quiet pulsing sketch\n instead of an empty box (anh T\u00FA 04/09: \"the page is too blank\"). -->\n <div class=\"chart-placeholder\" aria-hidden=\"true\">\n @for (h of placeholderBars; track $index) {\n <span class=\"chart-placeholder__bar\" [style.height.%]=\"h\"></span>\n }\n </div>\n }\n</div>\n", styles: ["@charset \"UTF-8\";:host{display:block;width:100%}.chart-wrapper{position:relative;width:100%;height:100%}.chart-container{width:100%;height:100%}.chart-loader{position:absolute;inset:0;display:flex;align-items:center;justify-content:center;background:rgba(var(--bg-primary-hover)/.6);font-weight:500;font-size:1.1rem;z-index:2;border-radius:4px}.chart-empty{display:flex;flex-direction:column;align-items:center;justify-content:center;height:100%;gap:12px;color:rgba(var(--text-secondary)/1)}.chart-empty-icon{width:48px;height:48px;opacity:.4}.chart-empty-text{font-size:14px;font-weight:500}.chart-placeholder{position:absolute;inset:0;display:flex;align-items:flex-end;gap:6px;padding:12px 8px 22px;animation:chart-placeholder-pulse 1.6s ease-in-out infinite}.chart-placeholder__bar{flex:1;border-radius:3px 3px 0 0;background:rgb(var(--og-track))}@keyframes chart-placeholder-pulse{0%,to{opacity:1}50%{opacity:.45}}@media(prefers-reduced-motion:reduce){.chart-placeholder{animation:none}}\n"] }]
|
|
723
725
|
}], ctorParameters: () => [{ type: i0.ElementRef }, { type: i0.ChangeDetectorRef }], propDecorators: { type: [{ type: i0.Input, args: [{ isSignal: true, alias: "type", required: false }] }], data: [{ type: i0.Input, args: [{ isSignal: true, alias: "data", required: false }] }], options: [{ type: i0.Input, args: [{ isSignal: true, alias: "options", required: false }] }], palette: [{ type: i0.Input, args: [{ isSignal: true, alias: "palette", required: false }] }], height: [{ type: i0.Input, args: [{ isSignal: true, alias: "height", required: false }] }], loading: [{ type: i0.Input, args: [{ isSignal: true, alias: "loading", required: false }] }], pieLegendAlign: [{ type: i0.Input, args: [{ isSignal: true, alias: "pieLegendAlign", required: false }] }], pieLegendPosition: [{ type: i0.Input, args: [{ isSignal: true, alias: "pieLegendPosition", required: false }] }], showPieLabel: [{ type: i0.Input, args: [{ isSignal: true, alias: "showPieLabel", required: false }] }], showPieLegend: [{ type: i0.Input, args: [{ isSignal: true, alias: "showPieLegend", required: false }] }], pieCenterLabel: [{ type: i0.Input, args: [{ isSignal: true, alias: "pieCenterLabel", required: false }] }], mobileWidth: [{ type: i0.Input, args: [{ isSignal: true, alias: "mobileWidth", required: false }] }], labelFontFamily: [{ type: i0.Input, args: [{ isSignal: true, alias: "labelFontFamily", required: false }] }], emptyText: [{ type: i0.Input, args: [{ isSignal: true, alias: "emptyText", required: false }] }], chartClick: [{ type: i0.Output, args: ["chartClick"] }], chartInit: [{ type: i0.Output, args: ["chartInit"] }], onThemeChange: [{
|
|
724
726
|
type: HostListener,
|
|
725
727
|
args: ['window:theme-changed']
|
|
726
728
|
}] } });
|
|
727
729
|
|
|
730
|
+
let pending;
|
|
731
|
+
/**
|
|
732
|
+
* Warm the echarts chunk before any chart is on screen.
|
|
733
|
+
*
|
|
734
|
+
* `fx-ui-chart` loads echarts lazily (`provideEchartsCore({ echarts: () =>
|
|
735
|
+
* import('echarts') })`), so the FIRST chart of a session pays the chunk
|
|
736
|
+
* download right when the user is looking at an empty panel. Call this once
|
|
737
|
+
* from an idle callback when the app's env injector is created (e.g. a
|
|
738
|
+
* `provideEnvironmentInitializer` in the remote's root route) and the dashboard
|
|
739
|
+
* charts appear on the frame they mount. Same module URL as the directive's
|
|
740
|
+
* import ⇒ one shared instance, no double load.
|
|
741
|
+
*/
|
|
742
|
+
function preloadEcharts() {
|
|
743
|
+
return (pending ??= import('echarts'));
|
|
744
|
+
}
|
|
745
|
+
/** Schedule `preloadEcharts()` when the main thread is idle (SSR/tests: no-op). */
|
|
746
|
+
function preloadEchartsWhenIdle(timeoutMs = 3000) {
|
|
747
|
+
if (typeof window === 'undefined')
|
|
748
|
+
return;
|
|
749
|
+
const w = window;
|
|
750
|
+
if (typeof w.requestIdleCallback === 'function') {
|
|
751
|
+
w.requestIdleCallback(() => void preloadEcharts(), { timeout: timeoutMs });
|
|
752
|
+
}
|
|
753
|
+
else {
|
|
754
|
+
setTimeout(() => void preloadEcharts(), 1500);
|
|
755
|
+
}
|
|
756
|
+
}
|
|
757
|
+
|
|
728
758
|
/**
|
|
729
759
|
* Generated bundle index. Do not edit.
|
|
730
760
|
*/
|
|
731
761
|
|
|
732
|
-
export { ChartComponent };
|
|
762
|
+
export { ChartComponent, preloadEcharts, preloadEchartsWhenIdle };
|
|
733
763
|
//# sourceMappingURL=foxeltech-angular-ui-chart.mjs.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"foxeltech-angular-ui-chart.mjs","sources":["../../../projects/ui/chart/src/chart/chart.component.ts","../../../projects/ui/chart/src/chart/chart.component.html","../../../projects/ui/chart/src/foxeltech-angular-ui-chart.ts"],"sourcesContent":["import {\n AfterViewInit,\n ChangeDetectorRef,\n Component,\n ElementRef,\n HostListener,\n OnChanges,\n OnDestroy,\n ChangeDetectionStrategy,\n input,\n output\n} from '@angular/core';\nimport { ECharts, EChartsOption } from 'echarts';\nimport { FxUtils, InputComponent } from '@foxeltech/angular-ui';\nimport { NgxEchartsDirective, provideEchartsCore } from 'ngx-echarts';\n\n\n// 'radar' was advertised here but has no builder in the registry — it\n// silently rendered an empty chart. Re-add when implemented.\n// V2 presets: 'line' (risk score by release), 'area-trend' (weekly trend with\n// accent fill + gray comparison line). Both need an explicit [type] — 'auto'\n// cannot tell them apart from 'bar'.\nexport type IChartType = 'bar' | 'pie' | 'sunburst' | 'line' | 'area-trend' | 'auto';\n\n@Component({\n selector: 'fx-ui-chart',\n templateUrl: './chart.component.html',\n styleUrl: './chart.component.scss',\n changeDetection: ChangeDetectionStrategy.OnPush,\n imports: [NgxEchartsDirective, InputComponent],\n // Self-contained: echarts is provided (and lazy-loaded) right here, so\n // consumers just import ChartComponent — no forRoot wiring in the app.\n providers: [provideEchartsCore({ echarts: () => import('echarts') })],\n})\nexport class ChartComponent implements OnChanges, AfterViewInit, OnDestroy {\n /* ================= INPUTS ================= */\n\n readonly type = input<IChartType>('auto');\n readonly data = input<any>();\n readonly options = input<EChartsOption>();\n readonly palette = input<string[]>();\n readonly height = input('400px');\n readonly loading = input(false);\n\n // pie controls\n readonly pieLegendAlign = input<string | number>('10%');\n readonly pieLegendPosition = input<string | number>('middle');\n readonly showPieLabel = input(true);\n /** Hide the built-in legend (panels that render their own legend beside the\n donut); the donut then centres in the container. */\n readonly showPieLegend = input(true);\n /** Caption under the donut's centre total (design: \"42 / confirmed\"). */\n readonly pieCenterLabel = input('');\n readonly mobileWidth = input(350);\n /** Override font for canvas text; empty = follow the theme's --og-font-figure. */\n readonly labelFontFamily = input('');\n readonly emptyText = input('No data available');\n\n /* ================= OUTPUTS ================= */\n\n readonly chartClick = output<any>();\n readonly chartInit = output<ECharts>();\n\n /* ================= INTERNAL ================= */\n\n chartOptions: EChartsOption = {};\n isEmpty = false;\n /**\n * ⚠️ Cổng cho `<div echarts>` trong template. Trước đây div render NGAY với\n * `chartOptions = {}`, nên NgxEchartsDirective khởi tạo chart bằng options\n * RỖNG; options thật gán vào giữa lúc `await createChart()` của lần đó ⇒\n * onOptionsChange() thấy `chart == null` và createChart() LẦN HAI trên cùng\n * DOM node ⇒ \"[ECharts] There is a chart instance already initialized on the\n * dom.\". Chỉ dựng directive khi đã có options thật ⇒ đúng một lần init.\n */\n hasOptions = false;\n labelFontSize = 12;\n\n private chartInstance?: ECharts;\n private resizeObserver?: ResizeObserver;\n private intersectionObserver?: IntersectionObserver;\n\n private canInit = false;\n private destroyed = false;\n /**\n * ⚠️ Đang chờ init đầu tiên của directive hoàn tất?\n *\n * NgxEchartsDirective đăng ký `changeFilter.notFirstAndEmpty('options', …)`:\n * lần gán `options` ĐẦU bị bỏ qua (ngAfterViewInit lo), lần gán THỨ HAI gọi\n * onOptionsChange(). Mà onOptionsChange() chỉ createChart() khi `this.chart`\n * còn null — và nó null suốt thời gian `await createChart()` của lần đầu.\n * Nên nếu ta gán `chartOptions` (object mới) trong khoảng await đó thì\n * init() chạy HAI LẦN trên cùng DOM node ⇒\n * \"[ECharts] There is a chart instance already initialized on the dom.\"\n *\n * Cách chặn: trong khoảng chờ, giữ options ở `deferredOptions` chứ không đụng\n * vào property đang bind; init xong thì áp một lần qua instance.\n */\n private awaitingFirstInit = false;\n private deferredOptions?: EChartsOption;\n private pendingFrames = new Set<number>();\n private isMobile = false;\n private containerWidth = 0;\n\n constructor(\n private ref: ElementRef<HTMLElement>,\n private cdr: ChangeDetectorRef,\n ) {}\n\n /* ================= LIFECYCLE ================= */\n\n ngAfterViewInit(): void {\n // Only initialize when visible (tab-safe)\n this.intersectionObserver = new IntersectionObserver(\n ([entry]) => {\n if (entry.isIntersecting && !this.canInit && !this.destroyed) {\n this.canInit = true;\n this.updateResponsiveState();\n this.rebuildChart();\n this.cdr.detectChanges();\n }\n },\n { threshold: 0.1 },\n );\n\n this.intersectionObserver.observe(this.ref.nativeElement);\n\n // Resize-safe (tabs, flex, async layout)\n this.resizeObserver = new ResizeObserver(() => {\n if (!this.canInit || this.destroyed) return;\n // forceMediaRecalc tự đo lại và chỉ dựng lại khi kích thước đổi.\n this.forceMediaRecalc();\n });\n\n this.resizeObserver.observe(this.ref.nativeElement);\n }\n\n ngOnChanges(): void {\n if (this.canInit && !this.destroyed) {\n this.updateResponsiveState();\n this.rebuildChart();\n }\n }\n\n ngOnDestroy(): void {\n // NgxEchartsDirective tự dispose instance của nó, nên KHÔNG dispose ở đây\n // (sẽ dispose trùng). Việc phải làm là ngắt mọi đường còn chạm được vào\n // instance sau khi nó đã bị dispose: callback rAF đang chờ + tham chiếu\n // `chartInstance` mà forceMediaRecalc/rebuildChart vẫn dùng.\n this.destroyed = true;\n\n for (const id of this.pendingFrames) cancelAnimationFrame(id);\n this.pendingFrames.clear();\n\n this.resizeObserver?.disconnect();\n this.intersectionObserver?.disconnect();\n this.resizeObserver = undefined;\n this.intersectionObserver = undefined;\n\n this.chartInstance = undefined;\n this.awaitingFirstInit = false;\n this.deferredOptions = undefined;\n this.sweepOrphanInstance();\n }\n\n /**\n * ⚠️ RACE TRONG NGX-ECHARTS v20 — nguồn của\n * \"[ECharts] There is a chart instance already initialized on the dom.\"\n *\n * NgxEchartsDirective.onOptionsChange() làm:\n * this.chart = await this.createChart(); // ← destroy có thể rơi vào đây\n * this.chart$.next(this.chart);\n * this.chartInit.emit(this.chart);\n *\n * Destroy đúng lúc đang await thì ngOnDestroy → dispose() thấy `this.chart == null`\n * nên KHÔNG dispose gì. Sau đó await resolve, gán một instance ECharts còn sống cho\n * directive đã chết → instance MỒ CÔI, vẫn nằm trong registry của echarts gắn với\n * DOM node đó. Angular tái dùng node ⇒ init() lần sau báo \"already initialized\".\n *\n * Không thể bắt qua (chartInit): Angular v20 TỪ CHỐI emit trên OutputRef đã destroy\n * (chỉ log NG0953, listener không hề được gọi). Nên đường duy nhất là hỏi thẳng\n * echarts xem node còn instance nào không, ở các macrotask SAU destroy.\n */\n private sweepOrphanInstance(): void {\n const host = this.ref.nativeElement.querySelector<HTMLElement>('.fx-chart');\n if (!host) return;\n\n // Chỉ nạp echarts nếu nó đã ở trong module cache — không tự kéo bundle về\n // chỉ để đi dọn.\n let attempt = 0;\n const sweep = () => {\n import('echarts').then(({ getInstanceByDom }) => {\n const orphan = getInstanceByDom(host);\n if (orphan) {\n if (!orphan.isDisposed()) orphan.dispose();\n return;\n }\n // createChart() phải chờ dynamic import nên instance mồ côi có thể xuất\n // hiện muộn hơn một macrotask; thử lại vài nhịp rồi dừng.\n if (++attempt < 5) setTimeout(sweep, 50 * attempt);\n });\n };\n\n setTimeout(sweep);\n }\n\n /** rAF có thể huỷ được khi destroy — tránh chạm instance đã dispose. */\n private schedule(fn: () => void): void {\n if (this.destroyed) return;\n const id = requestAnimationFrame(() => {\n this.pendingFrames.delete(id);\n if (this.destroyed) return;\n fn();\n });\n this.pendingFrames.add(id);\n }\n\n /** Instance còn dùng được? (đã dispose thì mọi API echarts đều ném lỗi) */\n private get liveChart(): ECharts | undefined {\n const chart = this.chartInstance;\n if (!chart || this.destroyed || chart.isDisposed()) return undefined;\n return chart;\n }\n\n @HostListener('window:theme-changed')\n onThemeChange(): void {\n if (!this.canInit || this.destroyed) return;\n this.schedule(() => this.rebuildChart());\n }\n\n /* ================= EVENTS ================= */\n\n onChartClick(event: any) {\n this.chartClick.emit(event);\n }\n\n // ⚠️ Phải để `any`: NgxEchartsDirective emit `EChartsType` từ\n // 'echarts/types/dist/shared', TS coi nó KHÔNG tương thích với `ECharts`\n // của 'echarts' (private `_ssr` khai báo riêng) → template typecheck fail.\n onChartInit(raw: any) {\n const chart = raw as ECharts;\n // Phòng thân: bình thường Angular đã chặn emit sau destroy (NG0953) nên\n // nhánh này không tới; nhưng nếu tới thì tuyệt đối không được gán lại\n // `chartInstance` sau ngOnDestroy. Việc thu dọn instance mồ côi do\n // sweepOrphanInstance() lo — xem ghi chú ở đó.\n if (this.destroyed) {\n if (!chart.isDisposed()) chart.dispose();\n return;\n }\n\n this.chartInstance = chart;\n this.awaitingFirstInit = false;\n\n if (this.deferredOptions) {\n const options = this.deferredOptions;\n this.deferredOptions = undefined;\n this.chartOptions = options;\n if (!chart.isDisposed()) {\n chart.clear();\n chart.setOption(options, true);\n }\n }\n\n this.chartInit.emit(chart);\n\n this.schedule(() => this.forceMediaRecalc());\n }\n\n /* ================= CORE FIX ================= */\n\n /**\n * @returns true nếu trạng thái responsive THỰC SỰ đổi (nên dựng lại options).\n *\n * Trả về boolean là điều then chốt cho animation lúc chart xuất hiện — xem\n * ghi chú ở `forceMediaRecalc`.\n */\n private updateResponsiveState(): boolean {\n const { width } = this.ref.nativeElement.getBoundingClientRect();\n if (width <= 0) return false;\n\n const isMobile = width < this.mobileWidth();\n const changed = width !== this.containerWidth || isMobile !== this.isMobile;\n this.containerWidth = width;\n this.isMobile = isMobile;\n return changed;\n }\n\n /**\n * ⚠️ CHỈ dựng lại options khi kích thước thật sự đổi — nếu không thì\n * **animation lúc chart xuất hiện bị giết**.\n *\n * Đường đi: `onChartInit` → schedule(forceMediaRecalc) → chạy ở frame KẾ\n * TIẾP. Nếu chỗ này vô điều kiện `rebuildChart()` (clear + setOption notMerge)\n * thì nó xoá sạch và vẽ lại từ đầu ~16ms sau lần vẽ đầu, trong khi animation\n * xuất hiện dài ~1000ms ⇒ người dùng thấy chart hiện ra đứng im.\n *\n * Đo được: lần xuất hiện đầu 1/12 frame khác nhau (đứng yên) trong khi vẽ lại\n * bằng `theme-changed` cho 9/12 → animation của ECharts vẫn bật, chỉ lần đầu\n * bị cắt.\n *\n * Trước Pha 0 lỗi này bị che: lần init đầu dùng `chartOptions = {}` nên\n * animation xuất hiện xảy ra ở lần cập nhật SAU, tức sau khi forceMediaRecalc\n * đã chạy xong. Cổng `hasOptions` đưa options thật về ngay lần init nên lộ ra.\n *\n * `resize()` thì luôn gọi được — nó không cắt animation.\n */\n private forceMediaRecalc(retry = 0) {\n if (!this.liveChart) return;\n\n const { width, height } = this.ref.nativeElement.getBoundingClientRect();\n\n if ((width === 0 || height === 0) && retry < 10) {\n this.schedule(() => this.forceMediaRecalc(retry + 1));\n return;\n }\n\n // ⚠️ `resize()` cũng phải CÓ ĐIỀU KIỆN. ECharts nhảy thẳng tới trạng thái\n // cuối khi resize, nên gọi nó ở frame ngay sau init sẽ CẮT animation lúc\n // chart xuất hiện — đo được: 3 lần đổi khung trong 200ms rồi đứng im, dù\n // đã đặt animationDuration 3000ms.\n // Không cần resize ở lần đầu: ECharts tự lấy kích thước khi init, và vòng\n // retry ở trên đã lo ca width/height = 0.\n if (!this.updateResponsiveState()) return;\n\n this.rebuildChart();\n this.liveChart?.resize();\n }\n\n private rebuildChart(): void {\n if (this.destroyed) return;\n\n this.isEmpty = this.checkEmpty();\n\n if (this.isEmpty) {\n this.liveChart?.clear();\n return;\n }\n\n const options = this.buildOptions();\n const chart = this.liveChart;\n\n if (!chart) {\n if (this.awaitingFirstInit) {\n // Đang trong khoảng await của lần init đầu — KHÔNG gán vào property\n // đang bind, xem ghi chú ở `awaitingFirstInit`.\n this.deferredOptions = options;\n return;\n }\n this.awaitingFirstInit = true;\n this.chartOptions = options;\n this.hasOptions = true;\n return;\n }\n\n this.chartOptions = options;\n this.hasOptions = true;\n chart.clear();\n chart.setOption(options, true);\n }\n\n private checkEmpty(): boolean {\n const type = this.detectType();\n\n if (type === 'bar') {\n const data = this.data();\n const categories = data?.categories;\n const values = data?.values;\n return !categories?.length || !values?.length;\n }\n\n if (type === 'line') {\n const data = this.data();\n return !data?.categories?.length || !data?.values?.length;\n }\n\n if (type === 'area-trend') {\n const data = this.data();\n return !data?.categories?.length || !data?.current?.length;\n }\n\n if (type === 'pie') {\n const data = this.data();\n if (!Array.isArray(data) || data.length === 0) return true;\n const total = data.reduce((sum: number, d: any) => sum + (d.value || 0), 0);\n return total === 0;\n }\n\n return false;\n }\n\n /* ================= REGISTRY ================= */\n\n private registry: Record<string, (data: any, palette: string[]) => EChartsOption> = {\n bar: (data, colors) => ({\n color: colors,\n tooltip: { trigger: 'axis' },\n grid: { left: '5%', right: '5%', bottom: '10%', containLabel: true },\n xAxis: {\n type: 'category',\n data: data?.categories || [],\n axisLabel: {\n interval: 0,\n width: 80,\n overflow: 'truncate',\n ellipsis: '…',\n fontFamily: this.resolvedFontFamily(),\n fontSize: this.labelFontSize,\n color: FxUtils.convertColorFromVariable('--text-secondary'),\n },\n axisLine: {\n lineStyle: {\n color: FxUtils.convertColorFromVariable('--border-strong'),\n },\n },\n },\n yAxis: {\n type: 'value',\n axisLabel: {\n fontFamily: this.resolvedFontFamily(),\n fontSize: this.labelFontSize,\n color: FxUtils.convertColorFromVariable('--text-secondary'),\n },\n axisLine: {\n lineStyle: {\n color: FxUtils.convertColorFromVariable('--border-strong'),\n },\n },\n splitLine: {\n lineStyle: {\n color: FxUtils.convertColorFromVariable('--border-default'),\n },\n },\n },\n series: [\n {\n type: 'bar',\n data: data?.values || [],\n barMaxWidth: 70,\n itemStyle: {\n color: (p: any) => colors[p.dataIndex % colors.length],\n },\n label: {\n show: true,\n position: 'top',\n fontFamily: this.resolvedFontFamily(),\n fontSize: this.labelFontSize,\n color: FxUtils.convertColorFromVariable('--text-primary'),\n },\n },\n ],\n }),\n\n pie: (data, colors) => {\n const total = data.reduce((sum: number, d: any) => sum + d.value, 0);\n const layout = this.calcPieLayout(data);\n\n return {\n color: colors,\n tooltip: { trigger: 'item' },\n\n legend: {\n show: this.showPieLegend(),\n type: 'scroll' as const,\n orient: layout.legendOrient,\n icon: 'circle',\n itemGap: 12,\n\n right: layout.legendRight,\n top: layout.legendTop,\n left: layout.legendLeft,\n bottom: layout.legendBottom,\n width: layout.legendWidth,\n\n formatter: (name: string) => {\n const item = data.find((d: any) => d.name === name);\n return item ? `${name}: ${item.value}` : name;\n },\n\n textStyle: {\n fontFamily: this.resolvedFontFamily(),\n fontSize: 13,\n fontWeight: 500,\n color: FxUtils.convertColorFromVariable('--text-primary'),\n overflow: 'truncate',\n },\n },\n\n series: [\n {\n type: 'pie',\n radius: ['40%', '70%'],\n center: layout.pieCenter,\n data,\n\n label: {\n show: this.showPieLabel(),\n position: 'outside',\n formatter: '{d}%',\n fontSize: this.labelFontSize,\n fontFamily: this.resolvedFontFamily(),\n color: FxUtils.convertColorFromVariable('--text-primary'),\n textBorderWidth: 0,\n textBorderColor: 'transparent',\n },\n\n labelLine: {\n show: this.showPieLabel(),\n length: 7,\n length2: 7,\n },\n },\n ],\n\n // Centre figure: positioned by x/y in pixels — graphic left/top\n // percentages place the element's bounding-box EDGE, which shifted the\n // total right/down by half its own size (mis-centred, caption clipped).\n graphic: (() => {\n const cx = (this.containerWidth || 400) * (parseFloat(layout.pieCenter[0]) / 100);\n const ch = this.ref.nativeElement.clientHeight || 300;\n const cy = ch * (parseFloat(layout.pieCenter[1]) / 100);\n return [\n {\n type: 'text' as const,\n // Shift the total up when a caption sits under it.\n x: cx,\n y: cy + (this.pieCenterLabel() ? -9 : 0),\n style: {\n text: total.toString(),\n fontSize: 24,\n fontWeight: 600,\n fontFamily: this.resolvedFontFamily(),\n fill: FxUtils.convertColorFromVariable('--text-primary'),\n align: 'center' as const,\n verticalAlign: 'middle' as const,\n },\n },\n ...(this.pieCenterLabel()\n ? [\n {\n type: 'text' as const,\n x: cx,\n y: cy + 12,\n style: {\n text: this.pieCenterLabel(),\n fontSize: 11,\n fontFamily: this.resolvedFontFamily(),\n fill: FxUtils.convertColorFromVariable('--text-secondary'),\n align: 'center' as const,\n verticalAlign: 'middle' as const,\n },\n },\n ]\n : []),\n ];\n })(),\n };\n },\n // V2 preset: single line, accent-coloured — \"risk score by release\".\n line: (data) => ({\n tooltip: { trigger: 'axis' },\n grid: { left: '3%', right: '4%', bottom: '8%', top: '8%', containLabel: true },\n xAxis: this.categoryAxis(data?.categories || []),\n yAxis: this.valueAxis(),\n series: [\n {\n type: 'line',\n data: data?.values || [],\n smooth: false,\n symbol: 'circle',\n symbolSize: 7,\n lineStyle: { width: 2, color: FxUtils.convertColorFromVariable('--og-accent', 1, { legacyCommaSyntax: true }) },\n itemStyle: { color: FxUtils.convertColorFromVariable('--og-accent', 1, { legacyCommaSyntax: true }) },\n label: {\n show: true,\n position: 'top',\n fontFamily: this.resolvedFontFamily(),\n fontSize: this.labelFontSize,\n color: FxUtils.convertColorFromVariable('--text-primary'),\n },\n },\n ],\n }),\n\n // V2 preset: weekly trend — accent gradient fill + gray comparison line.\n // data: { categories: string[], current: number[], previous?: number[] }\n 'area-trend': (data) => {\n // legacyCommaSyntax: zrender's colour parser chokes on CSS4 space syntax.\n const accent = FxUtils.convertColorFromVariable('--og-accent', 1, { legacyCommaSyntax: true });\n const accentSoft = FxUtils.convertColorFromVariable('--og-accent', 0.25, { legacyCommaSyntax: true });\n const accentFade = FxUtils.convertColorFromVariable('--og-accent', 0.02, { legacyCommaSyntax: true });\n const series: any[] = [\n {\n type: 'line',\n name: data?.currentLabel || 'Current',\n data: data?.current || [],\n smooth: true,\n symbol: 'none',\n lineStyle: { width: 2, color: accent },\n itemStyle: { color: accent },\n areaStyle: {\n color: {\n type: 'linear',\n x: 0, y: 0, x2: 0, y2: 1,\n colorStops: [\n { offset: 0, color: accentSoft },\n { offset: 1, color: accentFade },\n ],\n },\n },\n },\n ];\n if (data?.previous?.length) {\n series.push({\n type: 'line',\n name: data?.previousLabel || 'Previous',\n data: data.previous,\n smooth: true,\n symbol: 'none',\n lineStyle: {\n width: 1.5,\n type: 'dashed',\n color: FxUtils.convertColorFromVariable('--text-placeholder', 1, { legacyCommaSyntax: true }),\n },\n itemStyle: { color: FxUtils.convertColorFromVariable('--text-placeholder', 1, { legacyCommaSyntax: true }) },\n });\n }\n return {\n tooltip: { trigger: 'axis' },\n grid: { left: '3%', right: '4%', bottom: '8%', top: '10%', containLabel: true },\n xAxis: { ...this.categoryAxis(data?.categories || []), boundaryGap: false },\n yAxis: this.valueAxis(),\n series,\n };\n },\n\n sunburst: (data, colors) => ({\n color: colors,\n series: [\n {\n type: 'sunburst',\n data,\n radius: ['15%', '90%'],\n itemStyle: {\n borderWidth: 1,\n borderColor: FxUtils.convertColorFromVariable('--border-default'),\n },\n label: {\n rotate: 'tangential',\n fontSize: this.labelFontSize,\n fontFamily: this.resolvedFontFamily(),\n color: FxUtils.convertColorFromVariable('--text-primary'),\n textBorderWidth: 0,\n textBorderColor: 'transparent',\n },\n },\n ],\n }),\n };\n\n /* ================= PIE LAYOUT ================= */\n\n private calcPieLayout(data: any[]) {\n const cw = this.containerWidth || 400;\n\n if (!this.showPieLegend()) {\n return {\n legendOrient: 'vertical' as const,\n legendLeft: undefined as string | undefined,\n legendRight: undefined as string | undefined,\n legendTop: undefined as string | undefined,\n legendBottom: undefined as number | undefined,\n legendWidth: undefined as number | undefined,\n pieCenter: ['50%', '50%'],\n graphicLeft: '50%',\n graphicTop: '50%',\n };\n }\n\n if (this.isMobile) {\n return {\n legendOrient: 'horizontal' as const,\n legendLeft: 'center' as string | undefined,\n legendRight: undefined as string | undefined,\n legendTop: undefined as string | undefined,\n legendBottom: 0 as number | undefined,\n legendWidth: undefined as number | undefined,\n pieCenter: ['50%', '40%'],\n graphicLeft: '50%',\n graphicTop: '40%',\n };\n }\n\n // Estimate legend pixel width from longest formatted label\n const CHAR_WIDTH = 7.5; // approx px per char at fontSize 13\n const ICON_GAP = 30; // legend icon + padding\n const longestLabel = data.reduce((max: number, d: any) => {\n return Math.max(max, `${d.name}: ${d.value}`.length);\n }, 0);\n const rawLegendPx = longestLabel * CHAR_WIDTH + ICON_GAP;\n\n // Clamp: min 100px, max 45% of container\n const legendPx = Math.max(100, Math.min(rawLegendPx, cw * 0.45));\n const legendPct = (legendPx / cw) * 100;\n\n // Pie center: middle of the remaining space after legend\n const pieCenterX = Math.round((100 - legendPct) / 2);\n\n return {\n legendOrient: 'vertical' as const,\n legendLeft: undefined,\n legendRight: '2%',\n legendTop: 'middle' as string | undefined,\n legendBottom: undefined,\n legendWidth: Math.round(legendPx),\n pieCenter: [`${pieCenterX}%`, '50%'],\n graphicLeft: `${pieCenterX}%`,\n graphicTop: '50%',\n };\n }\n\n /* ================= BUILD ================= */\n\n private detectType(): string {\n const type = this.type();\n if (type !== 'auto') return type;\n const data = this.data();\n if (data?.children) return 'sunburst';\n if (data?.categories && data?.values) return 'bar';\n if (Array.isArray(data)) return 'pie';\n return 'bar';\n }\n\n private buildOptions(): EChartsOption {\n const type = this.detectType();\n const palette = this.resolvePalette();\n const base = this.registry[type]?.(this.data(), palette) || {};\n\n return {\n ...base,\n ...this.options(),\n };\n }\n\n private categoryAxis(categories: string[]) {\n return {\n type: 'category' as const,\n data: categories,\n axisLabel: {\n fontFamily: this.resolvedFontFamily(),\n fontSize: this.labelFontSize,\n color: FxUtils.convertColorFromVariable('--text-secondary'),\n },\n axisLine: {\n lineStyle: { color: FxUtils.convertColorFromVariable('--border-strong') },\n },\n };\n }\n\n private valueAxis() {\n return {\n type: 'value' as const,\n axisLabel: {\n fontFamily: this.resolvedFontFamily(),\n fontSize: this.labelFontSize,\n color: FxUtils.convertColorFromVariable('--text-secondary'),\n },\n splitLine: {\n lineStyle: { color: FxUtils.convertColorFromVariable('--border-default') },\n },\n };\n }\n\n /** Canvas không ăn var() — resolve font stack thật tại render; chart đã\n rebuild theo event theme-changed nên tự đổi font khi đổi theme\n (blueprint/terminal dùng mono qua --og-font-figure). */\n private resolvedFontFamily(): string {\n const override = this.labelFontFamily();\n if (override) return override;\n // Dev-mode CSS pretty-printer bẻ dòng giá trị dài — normalize whitespace\n // trước khi chuỗi này vào ctx.font của canvas.\n const figure = getComputedStyle(document.body)\n .getPropertyValue('--og-font-figure')\n .replace(/\\s+/g, ' ')\n .trim();\n return figure || 'Archivo, system-ui, sans-serif';\n }\n\n private resolvePalette(): string[] {\n const defaults = [\n 'rgba(var(--success) / 1)',\n 'rgba(var(--information) / 1)',\n 'rgba(var(--critical) / 1)',\n 'rgba(var(--danger) / 1)',\n 'rgba(var(--warning) / 1)',\n 'rgba(var(--discovery) / 1)',\n ];\n\n const paletteValue = this.palette();\n const palette = paletteValue?.length ? paletteValue : defaults;\n\n return palette.map((raw) => {\n if (!raw.includes('var(')) return raw;\n\n const cssVar = raw.match(/var\\((.*?)\\)/)?.[1];\n const rgb = getComputedStyle(document.body)\n .getPropertyValue(cssVar || '')\n .trim()\n .replace(/\\s+/g, ',');\n return `rgba(${rgb},1)`;\n });\n }\n}\n","<div class=\"chart-wrapper\" [style.height]=\"height()\">\n @if (isEmpty) {\n <div class=\"chart-empty\">\n <svg xmlns=\"http://www.w3.org/2000/svg\" fill=\"none\" viewBox=\"0 0 24 24\" stroke-width=\"1.5\" stroke=\"currentColor\" class=\"chart-empty-icon\">\n <path stroke-linecap=\"round\" stroke-linejoin=\"round\" d=\"M3 13.125C3 12.504 3.504 12 4.125 12h2.25c.621 0 1.125.504 1.125 1.125v6.75C7.5 20.496 6.996 21 6.375 21h-2.25A1.125 1.125 0 0 1 3 19.875v-6.75ZM9.75 8.625c0-.621.504-1.125 1.125-1.125h2.25c.621 0 1.125.504 1.125 1.125v11.25c0 .621-.504 1.125-1.125 1.125h-2.25a1.125 1.125 0 0 1-1.125-1.125V8.625ZM16.5 4.125c0-.621.504-1.125 1.125-1.125h2.25C20.496 3 21 3.504 21 4.125v15.75c0 .621-.504 1.125-1.125 1.125h-2.25a1.125 1.125 0 0 1-1.125-1.125V4.125Z\" />\n </svg>\n <span class=\"chart-empty-text\">{{ emptyText() }}</span>\n </div>\n } @else if (hasOptions) {\n <div\n echarts\n [options]=\"chartOptions\"\n [loading]=\"loading()\"\n (chartInit)=\"onChartInit($event)\"\n (chartClick)=\"onChartClick($event)\"\n class=\"fx-chart\"\n [style.height]=\"height()\"\n ></div>\n }\n</div>\n","/**\n * Generated bundle index. Do not edit.\n */\n\nexport * from './public-api';\n"],"names":[],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"foxeltech-angular-ui-chart.mjs","sources":["../../../projects/ui/chart/src/chart/chart.component.ts","../../../projects/ui/chart/src/chart/chart.component.html","../../../projects/ui/chart/src/preload-echarts.ts","../../../projects/ui/chart/src/foxeltech-angular-ui-chart.ts"],"sourcesContent":["import {\n AfterViewInit,\n ChangeDetectorRef,\n Component,\n ElementRef,\n HostListener,\n OnChanges,\n OnDestroy,\n ChangeDetectionStrategy,\n input,\n output\n} from '@angular/core';\nimport { ECharts, EChartsOption } from 'echarts';\nimport { FxUtils, InputComponent } from '@foxeltech/angular-ui';\nimport { NgxEchartsDirective, provideEchartsCore } from 'ngx-echarts';\n\n\n// 'radar' was advertised here but has no builder in the registry — it\n// silently rendered an empty chart. Re-add when implemented.\n// V2 presets: 'line' (risk score by release), 'area-trend' (weekly trend with\n// accent fill + gray comparison line). Both need an explicit [type] — 'auto'\n// cannot tell them apart from 'bar'.\nexport type IChartType = 'bar' | 'pie' | 'sunburst' | 'line' | 'area-trend' | 'auto';\n\n@Component({\n selector: 'fx-ui-chart',\n templateUrl: './chart.component.html',\n styleUrl: './chart.component.scss',\n changeDetection: ChangeDetectionStrategy.OnPush,\n imports: [NgxEchartsDirective, InputComponent],\n // Self-contained: echarts is provided (and lazy-loaded) right here, so\n // consumers just import ChartComponent — no forRoot wiring in the app.\n providers: [provideEchartsCore({ echarts: () => import('echarts') })],\n})\nexport class ChartComponent implements OnChanges, AfterViewInit, OnDestroy {\n /* ================= INPUTS ================= */\n\n readonly type = input<IChartType>('auto');\n readonly data = input<any>();\n readonly options = input<EChartsOption>();\n readonly palette = input<string[]>();\n readonly height = input('400px');\n readonly loading = input(false);\n\n // pie controls\n readonly pieLegendAlign = input<string | number>('10%');\n readonly pieLegendPosition = input<string | number>('middle');\n readonly showPieLabel = input(true);\n /** Hide the built-in legend (panels that render their own legend beside the\n donut); the donut then centres in the container. */\n readonly showPieLegend = input(true);\n /** Caption under the donut's centre total (design: \"42 / confirmed\"). */\n readonly pieCenterLabel = input('');\n readonly mobileWidth = input(350);\n /** Override font for canvas text; empty = follow the theme's --og-font-figure. */\n readonly labelFontFamily = input('');\n readonly emptyText = input('No data available');\n\n /* ================= OUTPUTS ================= */\n\n readonly chartClick = output<any>();\n readonly chartInit = output<ECharts>();\n\n /* ================= INTERNAL ================= */\n\n chartOptions: EChartsOption = {};\n isEmpty = false;\n /**\n * ⚠️ Cổng cho `<div echarts>` trong template. Trước đây div render NGAY với\n * `chartOptions = {}`, nên NgxEchartsDirective khởi tạo chart bằng options\n * RỖNG; options thật gán vào giữa lúc `await createChart()` của lần đó ⇒\n * onOptionsChange() thấy `chart == null` và createChart() LẦN HAI trên cùng\n * DOM node ⇒ \"[ECharts] There is a chart instance already initialized on the\n * dom.\". Chỉ dựng directive khi đã có options thật ⇒ đúng một lần init.\n */\n hasOptions = false;\n /** Heights (%) of the pre-init placeholder bars — a fixed, calm silhouette. */\n readonly placeholderBars = [34, 52, 44, 66, 58, 78, 70, 88, 62, 74];\n labelFontSize = 12;\n\n private chartInstance?: ECharts;\n private resizeObserver?: ResizeObserver;\n private intersectionObserver?: IntersectionObserver;\n\n private canInit = false;\n private destroyed = false;\n /**\n * ⚠️ Đang chờ init đầu tiên của directive hoàn tất?\n *\n * NgxEchartsDirective đăng ký `changeFilter.notFirstAndEmpty('options', …)`:\n * lần gán `options` ĐẦU bị bỏ qua (ngAfterViewInit lo), lần gán THỨ HAI gọi\n * onOptionsChange(). Mà onOptionsChange() chỉ createChart() khi `this.chart`\n * còn null — và nó null suốt thời gian `await createChart()` của lần đầu.\n * Nên nếu ta gán `chartOptions` (object mới) trong khoảng await đó thì\n * init() chạy HAI LẦN trên cùng DOM node ⇒\n * \"[ECharts] There is a chart instance already initialized on the dom.\"\n *\n * Cách chặn: trong khoảng chờ, giữ options ở `deferredOptions` chứ không đụng\n * vào property đang bind; init xong thì áp một lần qua instance.\n */\n private awaitingFirstInit = false;\n private deferredOptions?: EChartsOption;\n private pendingFrames = new Set<number>();\n private isMobile = false;\n private containerWidth = 0;\n\n constructor(\n private ref: ElementRef<HTMLElement>,\n private cdr: ChangeDetectorRef,\n ) {}\n\n /* ================= LIFECYCLE ================= */\n\n ngAfterViewInit(): void {\n // Only initialize when visible (tab-safe)\n this.intersectionObserver = new IntersectionObserver(\n ([entry]) => {\n if (entry.isIntersecting && !this.canInit && !this.destroyed) {\n this.canInit = true;\n this.updateResponsiveState();\n this.rebuildChart();\n this.cdr.detectChanges();\n }\n },\n { threshold: 0.1 },\n );\n\n this.intersectionObserver.observe(this.ref.nativeElement);\n\n // Resize-safe (tabs, flex, async layout)\n this.resizeObserver = new ResizeObserver(() => {\n if (!this.canInit || this.destroyed) return;\n // forceMediaRecalc tự đo lại và chỉ dựng lại khi kích thước đổi.\n this.forceMediaRecalc();\n });\n\n this.resizeObserver.observe(this.ref.nativeElement);\n }\n\n ngOnChanges(): void {\n if (this.canInit && !this.destroyed) {\n this.updateResponsiveState();\n this.rebuildChart();\n }\n }\n\n ngOnDestroy(): void {\n // NgxEchartsDirective tự dispose instance của nó, nên KHÔNG dispose ở đây\n // (sẽ dispose trùng). Việc phải làm là ngắt mọi đường còn chạm được vào\n // instance sau khi nó đã bị dispose: callback rAF đang chờ + tham chiếu\n // `chartInstance` mà forceMediaRecalc/rebuildChart vẫn dùng.\n this.destroyed = true;\n\n for (const id of this.pendingFrames) cancelAnimationFrame(id);\n this.pendingFrames.clear();\n\n this.resizeObserver?.disconnect();\n this.intersectionObserver?.disconnect();\n this.resizeObserver = undefined;\n this.intersectionObserver = undefined;\n\n this.chartInstance = undefined;\n this.awaitingFirstInit = false;\n this.deferredOptions = undefined;\n this.sweepOrphanInstance();\n }\n\n /**\n * ⚠️ RACE TRONG NGX-ECHARTS v20 — nguồn của\n * \"[ECharts] There is a chart instance already initialized on the dom.\"\n *\n * NgxEchartsDirective.onOptionsChange() làm:\n * this.chart = await this.createChart(); // ← destroy có thể rơi vào đây\n * this.chart$.next(this.chart);\n * this.chartInit.emit(this.chart);\n *\n * Destroy đúng lúc đang await thì ngOnDestroy → dispose() thấy `this.chart == null`\n * nên KHÔNG dispose gì. Sau đó await resolve, gán một instance ECharts còn sống cho\n * directive đã chết → instance MỒ CÔI, vẫn nằm trong registry của echarts gắn với\n * DOM node đó. Angular tái dùng node ⇒ init() lần sau báo \"already initialized\".\n *\n * Không thể bắt qua (chartInit): Angular v20 TỪ CHỐI emit trên OutputRef đã destroy\n * (chỉ log NG0953, listener không hề được gọi). Nên đường duy nhất là hỏi thẳng\n * echarts xem node còn instance nào không, ở các macrotask SAU destroy.\n */\n private sweepOrphanInstance(): void {\n const host = this.ref.nativeElement.querySelector<HTMLElement>('.fx-chart');\n if (!host) return;\n\n // Chỉ nạp echarts nếu nó đã ở trong module cache — không tự kéo bundle về\n // chỉ để đi dọn.\n let attempt = 0;\n const sweep = () => {\n import('echarts').then(({ getInstanceByDom }) => {\n const orphan = getInstanceByDom(host);\n if (orphan) {\n if (!orphan.isDisposed()) orphan.dispose();\n return;\n }\n // createChart() phải chờ dynamic import nên instance mồ côi có thể xuất\n // hiện muộn hơn một macrotask; thử lại vài nhịp rồi dừng.\n if (++attempt < 5) setTimeout(sweep, 50 * attempt);\n });\n };\n\n setTimeout(sweep);\n }\n\n /** rAF có thể huỷ được khi destroy — tránh chạm instance đã dispose. */\n private schedule(fn: () => void): void {\n if (this.destroyed) return;\n const id = requestAnimationFrame(() => {\n this.pendingFrames.delete(id);\n if (this.destroyed) return;\n fn();\n });\n this.pendingFrames.add(id);\n }\n\n /** Instance còn dùng được? (đã dispose thì mọi API echarts đều ném lỗi) */\n private get liveChart(): ECharts | undefined {\n const chart = this.chartInstance;\n if (!chart || this.destroyed || chart.isDisposed()) return undefined;\n return chart;\n }\n\n @HostListener('window:theme-changed')\n onThemeChange(): void {\n if (!this.canInit || this.destroyed) return;\n this.schedule(() => this.rebuildChart());\n }\n\n /* ================= EVENTS ================= */\n\n onChartClick(event: any) {\n this.chartClick.emit(event);\n }\n\n // ⚠️ Phải để `any`: NgxEchartsDirective emit `EChartsType` từ\n // 'echarts/types/dist/shared', TS coi nó KHÔNG tương thích với `ECharts`\n // của 'echarts' (private `_ssr` khai báo riêng) → template typecheck fail.\n onChartInit(raw: any) {\n const chart = raw as ECharts;\n // Phòng thân: bình thường Angular đã chặn emit sau destroy (NG0953) nên\n // nhánh này không tới; nhưng nếu tới thì tuyệt đối không được gán lại\n // `chartInstance` sau ngOnDestroy. Việc thu dọn instance mồ côi do\n // sweepOrphanInstance() lo — xem ghi chú ở đó.\n if (this.destroyed) {\n if (!chart.isDisposed()) chart.dispose();\n return;\n }\n\n this.chartInstance = chart;\n this.awaitingFirstInit = false;\n\n if (this.deferredOptions) {\n const options = this.deferredOptions;\n this.deferredOptions = undefined;\n this.chartOptions = options;\n if (!chart.isDisposed()) {\n chart.clear();\n chart.setOption(options, true);\n }\n }\n\n this.chartInit.emit(chart);\n\n this.schedule(() => this.forceMediaRecalc());\n }\n\n /* ================= CORE FIX ================= */\n\n /**\n * @returns true nếu trạng thái responsive THỰC SỰ đổi (nên dựng lại options).\n *\n * Trả về boolean là điều then chốt cho animation lúc chart xuất hiện — xem\n * ghi chú ở `forceMediaRecalc`.\n */\n private updateResponsiveState(): boolean {\n const { width } = this.ref.nativeElement.getBoundingClientRect();\n if (width <= 0) return false;\n\n const isMobile = width < this.mobileWidth();\n const changed = width !== this.containerWidth || isMobile !== this.isMobile;\n this.containerWidth = width;\n this.isMobile = isMobile;\n return changed;\n }\n\n /**\n * ⚠️ CHỈ dựng lại options khi kích thước thật sự đổi — nếu không thì\n * **animation lúc chart xuất hiện bị giết**.\n *\n * Đường đi: `onChartInit` → schedule(forceMediaRecalc) → chạy ở frame KẾ\n * TIẾP. Nếu chỗ này vô điều kiện `rebuildChart()` (clear + setOption notMerge)\n * thì nó xoá sạch và vẽ lại từ đầu ~16ms sau lần vẽ đầu, trong khi animation\n * xuất hiện dài ~1000ms ⇒ người dùng thấy chart hiện ra đứng im.\n *\n * Đo được: lần xuất hiện đầu 1/12 frame khác nhau (đứng yên) trong khi vẽ lại\n * bằng `theme-changed` cho 9/12 → animation của ECharts vẫn bật, chỉ lần đầu\n * bị cắt.\n *\n * Trước Pha 0 lỗi này bị che: lần init đầu dùng `chartOptions = {}` nên\n * animation xuất hiện xảy ra ở lần cập nhật SAU, tức sau khi forceMediaRecalc\n * đã chạy xong. Cổng `hasOptions` đưa options thật về ngay lần init nên lộ ra.\n *\n * `resize()` thì luôn gọi được — nó không cắt animation.\n */\n private forceMediaRecalc(retry = 0) {\n if (!this.liveChart) return;\n\n const { width, height } = this.ref.nativeElement.getBoundingClientRect();\n\n if ((width === 0 || height === 0) && retry < 10) {\n this.schedule(() => this.forceMediaRecalc(retry + 1));\n return;\n }\n\n // ⚠️ `resize()` cũng phải CÓ ĐIỀU KIỆN. ECharts nhảy thẳng tới trạng thái\n // cuối khi resize, nên gọi nó ở frame ngay sau init sẽ CẮT animation lúc\n // chart xuất hiện — đo được: 3 lần đổi khung trong 200ms rồi đứng im, dù\n // đã đặt animationDuration 3000ms.\n // Không cần resize ở lần đầu: ECharts tự lấy kích thước khi init, và vòng\n // retry ở trên đã lo ca width/height = 0.\n if (!this.updateResponsiveState()) return;\n\n this.rebuildChart();\n this.liveChart?.resize();\n }\n\n private rebuildChart(): void {\n if (this.destroyed) return;\n\n this.isEmpty = this.checkEmpty();\n\n if (this.isEmpty) {\n this.liveChart?.clear();\n return;\n }\n\n const options = this.buildOptions();\n const chart = this.liveChart;\n\n if (!chart) {\n if (this.awaitingFirstInit) {\n // Đang trong khoảng await của lần init đầu — KHÔNG gán vào property\n // đang bind, xem ghi chú ở `awaitingFirstInit`.\n this.deferredOptions = options;\n return;\n }\n this.awaitingFirstInit = true;\n this.chartOptions = options;\n this.hasOptions = true;\n return;\n }\n\n this.chartOptions = options;\n this.hasOptions = true;\n chart.clear();\n chart.setOption(options, true);\n }\n\n private checkEmpty(): boolean {\n const type = this.detectType();\n\n if (type === 'bar') {\n const data = this.data();\n const categories = data?.categories;\n const values = data?.values;\n return !categories?.length || !values?.length;\n }\n\n if (type === 'line') {\n const data = this.data();\n return !data?.categories?.length || !data?.values?.length;\n }\n\n if (type === 'area-trend') {\n const data = this.data();\n return !data?.categories?.length || !data?.current?.length;\n }\n\n if (type === 'pie') {\n const data = this.data();\n if (!Array.isArray(data) || data.length === 0) return true;\n const total = data.reduce((sum: number, d: any) => sum + (d.value || 0), 0);\n return total === 0;\n }\n\n return false;\n }\n\n /* ================= REGISTRY ================= */\n\n private registry: Record<string, (data: any, palette: string[]) => EChartsOption> = {\n bar: (data, colors) => ({\n color: colors,\n tooltip: { trigger: 'axis' },\n grid: { left: '5%', right: '5%', bottom: '10%', containLabel: true },\n xAxis: {\n type: 'category',\n data: data?.categories || [],\n axisLabel: {\n interval: 0,\n width: 80,\n overflow: 'truncate',\n ellipsis: '…',\n fontFamily: this.resolvedFontFamily(),\n fontSize: this.labelFontSize,\n color: FxUtils.convertColorFromVariable('--text-secondary'),\n },\n axisLine: {\n lineStyle: {\n color: FxUtils.convertColorFromVariable('--border-strong'),\n },\n },\n },\n yAxis: {\n type: 'value',\n axisLabel: {\n fontFamily: this.resolvedFontFamily(),\n fontSize: this.labelFontSize,\n color: FxUtils.convertColorFromVariable('--text-secondary'),\n },\n axisLine: {\n lineStyle: {\n color: FxUtils.convertColorFromVariable('--border-strong'),\n },\n },\n splitLine: {\n lineStyle: {\n color: FxUtils.convertColorFromVariable('--border-default'),\n },\n },\n },\n series: [\n {\n type: 'bar',\n data: data?.values || [],\n barMaxWidth: 70,\n itemStyle: {\n color: (p: any) => colors[p.dataIndex % colors.length],\n },\n label: {\n show: true,\n position: 'top',\n fontFamily: this.resolvedFontFamily(),\n fontSize: this.labelFontSize,\n color: FxUtils.convertColorFromVariable('--text-primary'),\n },\n },\n ],\n }),\n\n pie: (data, colors) => {\n const total = data.reduce((sum: number, d: any) => sum + d.value, 0);\n const layout = this.calcPieLayout(data);\n\n return {\n color: colors,\n tooltip: { trigger: 'item' },\n\n legend: {\n show: this.showPieLegend(),\n type: 'scroll' as const,\n orient: layout.legendOrient,\n icon: 'circle',\n itemGap: 12,\n\n right: layout.legendRight,\n top: layout.legendTop,\n left: layout.legendLeft,\n bottom: layout.legendBottom,\n width: layout.legendWidth,\n\n formatter: (name: string) => {\n const item = data.find((d: any) => d.name === name);\n return item ? `${name}: ${item.value}` : name;\n },\n\n textStyle: {\n fontFamily: this.resolvedFontFamily(),\n fontSize: 13,\n fontWeight: 500,\n color: FxUtils.convertColorFromVariable('--text-primary'),\n overflow: 'truncate',\n },\n },\n\n series: [\n {\n type: 'pie',\n radius: ['40%', '70%'],\n center: layout.pieCenter,\n data,\n\n label: {\n show: this.showPieLabel(),\n position: 'outside',\n formatter: '{d}%',\n fontSize: this.labelFontSize,\n fontFamily: this.resolvedFontFamily(),\n color: FxUtils.convertColorFromVariable('--text-primary'),\n textBorderWidth: 0,\n textBorderColor: 'transparent',\n },\n\n labelLine: {\n show: this.showPieLabel(),\n length: 7,\n length2: 7,\n },\n },\n ],\n\n // Centre figure: positioned by x/y in pixels — graphic left/top\n // percentages place the element's bounding-box EDGE, which shifted the\n // total right/down by half its own size (mis-centred, caption clipped).\n graphic: (() => {\n const cx = (this.containerWidth || 400) * (parseFloat(layout.pieCenter[0]) / 100);\n const ch = this.ref.nativeElement.clientHeight || 300;\n const cy = ch * (parseFloat(layout.pieCenter[1]) / 100);\n return [\n {\n type: 'text' as const,\n // Shift the total up when a caption sits under it.\n x: cx,\n y: cy + (this.pieCenterLabel() ? -9 : 0),\n style: {\n text: total.toString(),\n fontSize: 24,\n fontWeight: 600,\n fontFamily: this.resolvedFontFamily(),\n fill: FxUtils.convertColorFromVariable('--text-primary'),\n align: 'center' as const,\n verticalAlign: 'middle' as const,\n },\n },\n ...(this.pieCenterLabel()\n ? [\n {\n type: 'text' as const,\n x: cx,\n y: cy + 12,\n style: {\n text: this.pieCenterLabel(),\n fontSize: 11,\n fontFamily: this.resolvedFontFamily(),\n fill: FxUtils.convertColorFromVariable('--text-secondary'),\n align: 'center' as const,\n verticalAlign: 'middle' as const,\n },\n },\n ]\n : []),\n ];\n })(),\n };\n },\n // V2 preset: single line, accent-coloured — \"risk score by release\".\n line: (data) => ({\n tooltip: { trigger: 'axis' },\n grid: { left: '3%', right: '4%', bottom: '8%', top: '8%', containLabel: true },\n xAxis: this.categoryAxis(data?.categories || []),\n yAxis: this.valueAxis(),\n series: [\n {\n type: 'line',\n data: data?.values || [],\n smooth: false,\n symbol: 'circle',\n symbolSize: 7,\n lineStyle: { width: 2, color: FxUtils.convertColorFromVariable('--og-accent', 1, { legacyCommaSyntax: true }) },\n itemStyle: { color: FxUtils.convertColorFromVariable('--og-accent', 1, { legacyCommaSyntax: true }) },\n label: {\n show: true,\n position: 'top',\n fontFamily: this.resolvedFontFamily(),\n fontSize: this.labelFontSize,\n color: FxUtils.convertColorFromVariable('--text-primary'),\n },\n },\n ],\n }),\n\n // V2 preset: weekly trend — accent gradient fill + gray comparison line.\n // data: { categories: string[], current: number[], previous?: number[] }\n 'area-trend': (data) => {\n // legacyCommaSyntax: zrender's colour parser chokes on CSS4 space syntax.\n const accent = FxUtils.convertColorFromVariable('--og-accent', 1, { legacyCommaSyntax: true });\n const accentSoft = FxUtils.convertColorFromVariable('--og-accent', 0.25, { legacyCommaSyntax: true });\n const accentFade = FxUtils.convertColorFromVariable('--og-accent', 0.02, { legacyCommaSyntax: true });\n const series: any[] = [\n {\n type: 'line',\n name: data?.currentLabel || 'Current',\n data: data?.current || [],\n smooth: true,\n symbol: 'none',\n lineStyle: { width: 2, color: accent },\n itemStyle: { color: accent },\n areaStyle: {\n color: {\n type: 'linear',\n x: 0, y: 0, x2: 0, y2: 1,\n colorStops: [\n { offset: 0, color: accentSoft },\n { offset: 1, color: accentFade },\n ],\n },\n },\n },\n ];\n if (data?.previous?.length) {\n series.push({\n type: 'line',\n name: data?.previousLabel || 'Previous',\n data: data.previous,\n smooth: true,\n symbol: 'none',\n lineStyle: {\n width: 1.5,\n type: 'dashed',\n color: FxUtils.convertColorFromVariable('--text-placeholder', 1, { legacyCommaSyntax: true }),\n },\n itemStyle: { color: FxUtils.convertColorFromVariable('--text-placeholder', 1, { legacyCommaSyntax: true }) },\n });\n }\n return {\n tooltip: { trigger: 'axis' },\n grid: { left: '3%', right: '4%', bottom: '8%', top: '10%', containLabel: true },\n xAxis: { ...this.categoryAxis(data?.categories || []), boundaryGap: false },\n yAxis: this.valueAxis(),\n series,\n };\n },\n\n sunburst: (data, colors) => ({\n color: colors,\n series: [\n {\n type: 'sunburst',\n data,\n radius: ['15%', '90%'],\n itemStyle: {\n borderWidth: 1,\n borderColor: FxUtils.convertColorFromVariable('--border-default'),\n },\n label: {\n rotate: 'tangential',\n fontSize: this.labelFontSize,\n fontFamily: this.resolvedFontFamily(),\n color: FxUtils.convertColorFromVariable('--text-primary'),\n textBorderWidth: 0,\n textBorderColor: 'transparent',\n },\n },\n ],\n }),\n };\n\n /* ================= PIE LAYOUT ================= */\n\n private calcPieLayout(data: any[]) {\n const cw = this.containerWidth || 400;\n\n if (!this.showPieLegend()) {\n return {\n legendOrient: 'vertical' as const,\n legendLeft: undefined as string | undefined,\n legendRight: undefined as string | undefined,\n legendTop: undefined as string | undefined,\n legendBottom: undefined as number | undefined,\n legendWidth: undefined as number | undefined,\n pieCenter: ['50%', '50%'],\n graphicLeft: '50%',\n graphicTop: '50%',\n };\n }\n\n if (this.isMobile) {\n return {\n legendOrient: 'horizontal' as const,\n legendLeft: 'center' as string | undefined,\n legendRight: undefined as string | undefined,\n legendTop: undefined as string | undefined,\n legendBottom: 0 as number | undefined,\n legendWidth: undefined as number | undefined,\n pieCenter: ['50%', '40%'],\n graphicLeft: '50%',\n graphicTop: '40%',\n };\n }\n\n // Estimate legend pixel width from longest formatted label\n const CHAR_WIDTH = 7.5; // approx px per char at fontSize 13\n const ICON_GAP = 30; // legend icon + padding\n const longestLabel = data.reduce((max: number, d: any) => {\n return Math.max(max, `${d.name}: ${d.value}`.length);\n }, 0);\n const rawLegendPx = longestLabel * CHAR_WIDTH + ICON_GAP;\n\n // Clamp: min 100px, max 45% of container\n const legendPx = Math.max(100, Math.min(rawLegendPx, cw * 0.45));\n const legendPct = (legendPx / cw) * 100;\n\n // Pie center: middle of the remaining space after legend\n const pieCenterX = Math.round((100 - legendPct) / 2);\n\n return {\n legendOrient: 'vertical' as const,\n legendLeft: undefined,\n legendRight: '2%',\n legendTop: 'middle' as string | undefined,\n legendBottom: undefined,\n legendWidth: Math.round(legendPx),\n pieCenter: [`${pieCenterX}%`, '50%'],\n graphicLeft: `${pieCenterX}%`,\n graphicTop: '50%',\n };\n }\n\n /* ================= BUILD ================= */\n\n private detectType(): string {\n const type = this.type();\n if (type !== 'auto') return type;\n const data = this.data();\n if (data?.children) return 'sunburst';\n if (data?.categories && data?.values) return 'bar';\n if (Array.isArray(data)) return 'pie';\n return 'bar';\n }\n\n private buildOptions(): EChartsOption {\n const type = this.detectType();\n const palette = this.resolvePalette();\n const base = this.registry[type]?.(this.data(), palette) || {};\n\n return {\n ...base,\n ...this.options(),\n };\n }\n\n private categoryAxis(categories: string[]) {\n return {\n type: 'category' as const,\n data: categories,\n axisLabel: {\n fontFamily: this.resolvedFontFamily(),\n fontSize: this.labelFontSize,\n color: FxUtils.convertColorFromVariable('--text-secondary'),\n },\n axisLine: {\n lineStyle: { color: FxUtils.convertColorFromVariable('--border-strong') },\n },\n };\n }\n\n private valueAxis() {\n return {\n type: 'value' as const,\n axisLabel: {\n fontFamily: this.resolvedFontFamily(),\n fontSize: this.labelFontSize,\n color: FxUtils.convertColorFromVariable('--text-secondary'),\n },\n splitLine: {\n lineStyle: { color: FxUtils.convertColorFromVariable('--border-default') },\n },\n };\n }\n\n /** Canvas không ăn var() — resolve font stack thật tại render; chart đã\n rebuild theo event theme-changed nên tự đổi font khi đổi theme\n (blueprint/terminal dùng mono qua --og-font-figure). */\n private resolvedFontFamily(): string {\n const override = this.labelFontFamily();\n if (override) return override;\n // Dev-mode CSS pretty-printer bẻ dòng giá trị dài — normalize whitespace\n // trước khi chuỗi này vào ctx.font của canvas.\n const figure = getComputedStyle(document.body)\n .getPropertyValue('--og-font-figure')\n .replace(/\\s+/g, ' ')\n .trim();\n return figure || 'Archivo, system-ui, sans-serif';\n }\n\n private resolvePalette(): string[] {\n const defaults = [\n 'rgba(var(--success) / 1)',\n 'rgba(var(--information) / 1)',\n 'rgba(var(--critical) / 1)',\n 'rgba(var(--danger) / 1)',\n 'rgba(var(--warning) / 1)',\n 'rgba(var(--discovery) / 1)',\n ];\n\n const paletteValue = this.palette();\n const palette = paletteValue?.length ? paletteValue : defaults;\n\n return palette.map((raw) => {\n if (!raw.includes('var(')) return raw;\n\n const cssVar = raw.match(/var\\((.*?)\\)/)?.[1];\n const rgb = getComputedStyle(document.body)\n .getPropertyValue(cssVar || '')\n .trim()\n .replace(/\\s+/g, ',');\n return `rgba(${rgb},1)`;\n });\n }\n}\n","<div class=\"chart-wrapper\" [style.height]=\"height()\">\n @if (isEmpty) {\n <div class=\"chart-empty\">\n <svg xmlns=\"http://www.w3.org/2000/svg\" fill=\"none\" viewBox=\"0 0 24 24\" stroke-width=\"1.5\" stroke=\"currentColor\" class=\"chart-empty-icon\">\n <path stroke-linecap=\"round\" stroke-linejoin=\"round\" d=\"M3 13.125C3 12.504 3.504 12 4.125 12h2.25c.621 0 1.125.504 1.125 1.125v6.75C7.5 20.496 6.996 21 6.375 21h-2.25A1.125 1.125 0 0 1 3 19.875v-6.75ZM9.75 8.625c0-.621.504-1.125 1.125-1.125h2.25c.621 0 1.125.504 1.125 1.125v11.25c0 .621-.504 1.125-1.125 1.125h-2.25a1.125 1.125 0 0 1-1.125-1.125V8.625ZM16.5 4.125c0-.621.504-1.125 1.125-1.125h2.25C20.496 3 21 3.504 21 4.125v15.75c0 .621-.504 1.125-1.125 1.125h-2.25a1.125 1.125 0 0 1-1.125-1.125V4.125Z\" />\n </svg>\n <span class=\"chart-empty-text\">{{ emptyText() }}</span>\n </div>\n } @else if (hasOptions) {\n <div\n echarts\n [options]=\"chartOptions\"\n [loading]=\"loading()\"\n (chartInit)=\"onChartInit($event)\"\n (chartClick)=\"onChartClick($event)\"\n class=\"fx-chart\"\n [style.height]=\"height()\"\n ></div>\n } @else {\n <!-- Until echarts is loaded + initialised (or the element scrolls into view)\n the panel keeps the chart's footprint with a quiet pulsing sketch\n instead of an empty box (anh Tú 04/09: \"the page is too blank\"). -->\n <div class=\"chart-placeholder\" aria-hidden=\"true\">\n @for (h of placeholderBars; track $index) {\n <span class=\"chart-placeholder__bar\" [style.height.%]=\"h\"></span>\n }\n </div>\n }\n</div>\n","let pending: Promise<unknown> | undefined;\n\n/**\n * Warm the echarts chunk before any chart is on screen.\n *\n * `fx-ui-chart` loads echarts lazily (`provideEchartsCore({ echarts: () =>\n * import('echarts') })`), so the FIRST chart of a session pays the chunk\n * download right when the user is looking at an empty panel. Call this once\n * from an idle callback when the app's env injector is created (e.g. a\n * `provideEnvironmentInitializer` in the remote's root route) and the dashboard\n * charts appear on the frame they mount. Same module URL as the directive's\n * import ⇒ one shared instance, no double load.\n */\nexport function preloadEcharts(): Promise<unknown> {\n return (pending ??= import('echarts'));\n}\n\n/** Schedule `preloadEcharts()` when the main thread is idle (SSR/tests: no-op). */\nexport function preloadEchartsWhenIdle(timeoutMs = 3000): void {\n if (typeof window === 'undefined') return;\n const w = window as Window & { requestIdleCallback?: (cb: () => void, o?: { timeout: number }) => number };\n if (typeof w.requestIdleCallback === 'function') {\n w.requestIdleCallback(() => void preloadEcharts(), { timeout: timeoutMs });\n } else {\n setTimeout(() => void preloadEcharts(), 1500);\n }\n}\n","/**\n * Generated bundle index. Do not edit.\n */\n\nexport * from './public-api';\n"],"names":[],"mappings":"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"}
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import * as i0 from '@angular/core';
|
|
2
|
-
import { input, output, computed, ChangeDetectionStrategy, Component, Input } from '@angular/core';
|
|
2
|
+
import { input, output, viewChild, inject, ElementRef, DestroyRef, afterRenderEffect, untracked, computed, ChangeDetectionStrategy, Component, Input } from '@angular/core';
|
|
3
3
|
import { NgClass } from '@angular/common';
|
|
4
4
|
import { VflowComponent, NodeHtmlTemplateDirective, EdgeTemplateDirective, HandleComponent, ConnectionControllerDirective, ChangesControllerDirective } from 'ngx-vflow';
|
|
5
5
|
|
|
@@ -40,6 +40,42 @@ class FlowCanvasComponent {
|
|
|
40
40
|
/** Caller-translated hint shown when the graph is empty. */
|
|
41
41
|
emptyText = input('No chain data available', ...(ngDevMode ? [{ debugName: "emptyText" }] : /* istanbul ignore next */ []));
|
|
42
42
|
nodeClick = output();
|
|
43
|
+
flow = viewChild(VflowComponent, ...(ngDevMode ? [{ debugName: "flow" }] : /* istanbul ignore next */ []));
|
|
44
|
+
host = inject(ElementRef);
|
|
45
|
+
destroyRef = inject(DestroyRef);
|
|
46
|
+
constructor() {
|
|
47
|
+
// `view="auto"` only sizes vflow's viewport to the wrapper — it does not
|
|
48
|
+
// frame the graph, so a taller canvas left the chain pinned top-left and
|
|
49
|
+
// clipped (anh Tú 04/09). Fit whenever the graph or the box changes.
|
|
50
|
+
afterRenderEffect(() => {
|
|
51
|
+
const flow = this.flow();
|
|
52
|
+
this.flowNodes();
|
|
53
|
+
this.resolvedHeight();
|
|
54
|
+
if (!flow)
|
|
55
|
+
return;
|
|
56
|
+
untracked(() => this.scheduleFit());
|
|
57
|
+
});
|
|
58
|
+
if (typeof ResizeObserver !== 'undefined') {
|
|
59
|
+
const ro = new ResizeObserver(() => this.scheduleFit());
|
|
60
|
+
ro.observe(this.host.nativeElement);
|
|
61
|
+
this.destroyRef.onDestroy(() => ro.disconnect());
|
|
62
|
+
}
|
|
63
|
+
}
|
|
64
|
+
fitHandle = null;
|
|
65
|
+
/** Coalesces fit requests into one frame after vflow has measured its nodes. */
|
|
66
|
+
scheduleFit() {
|
|
67
|
+
if (this.fitHandle !== null)
|
|
68
|
+
return;
|
|
69
|
+
this.fitHandle = requestAnimationFrame(() => {
|
|
70
|
+
this.fitHandle = null;
|
|
71
|
+
const flow = this.flow();
|
|
72
|
+
if (!flow || this.isEmpty())
|
|
73
|
+
return;
|
|
74
|
+
// Design 04: cards fill the width with a little air (0.18 left them at
|
|
75
|
+
// ~0.74×, visibly smaller than the mock — measured 04/09).
|
|
76
|
+
flow.fitView({ padding: 0.1, duration: 0 });
|
|
77
|
+
});
|
|
78
|
+
}
|
|
43
79
|
/** Column index per node: pinned value, else longest path from a source. */
|
|
44
80
|
columns = computed(() => {
|
|
45
81
|
const nodes = this.nodes();
|
|
@@ -136,7 +172,8 @@ class FlowCanvasComponent {
|
|
|
136
172
|
counts[c] = (counts[c] ?? 0) + 1;
|
|
137
173
|
});
|
|
138
174
|
const rows = Math.max(1, ...Object.values(counts));
|
|
139
|
-
|
|
175
|
+
// Floor at 300px: a one-row chain in a 152px band read too small (04/09).
|
|
176
|
+
return `${Math.max(300, 48 + rows * ROW_GAP)}px`;
|
|
140
177
|
}, ...(ngDevMode ? [{ debugName: "resolvedHeight" }] : /* istanbul ignore next */ []));
|
|
141
178
|
kindTone(kind) {
|
|
142
179
|
return FX_CHAIN_KIND_TONE[kind] ?? 'information';
|
|
@@ -162,7 +199,7 @@ class FlowCanvasComponent {
|
|
|
162
199
|
return this.activeId() != null && !this.isEdgeActive(edge);
|
|
163
200
|
}
|
|
164
201
|
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.20", ngImport: i0, type: FlowCanvasComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
|
|
165
|
-
static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "21.2.20", type: FlowCanvasComponent, isStandalone: true, selector: "fx-ui-flow-canvas", inputs: { nodes: { classPropertyName: "nodes", publicName: "nodes", isSignal: true, isRequired: false, transformFunction: null }, edges: { classPropertyName: "edges", publicName: "edges", isSignal: true, isRequired: false, transformFunction: null }, activeId: { classPropertyName: "activeId", publicName: "activeId", isSignal: true, isRequired: false, transformFunction: null }, height: { classPropertyName: "height", publicName: "height", isSignal: true, isRequired: false, transformFunction: null }, emptyText: { classPropertyName: "emptyText", publicName: "emptyText", isSignal: true, isRequired: false, transformFunction: null } }, outputs: { nodeClick: "nodeClick" }, ngImport: i0, template: "<ng-template #blankHandle></ng-template>\n\n@if (isEmpty()) {\n <div\n class=\"flex items-center justify-center rounded-card border border-border bg-surface-sunken txt-body-01 text-text-placeholder\"\n [style.height]=\"resolvedHeight()\"\n >\n {{ emptyText() }}\n </div>\n} @else {\n <!-- view=\"auto\" sizes the flow from this wrapper, so the height input is the\n single source of truth for the canvas box. -->\n <div class=\"fx-chain-canvas rounded-card border border-border overflow-hidden\" [style.height]=\"resolvedHeight()\">\n <vflow\n view=\"auto\"\n [nodes]=\"flowNodes()\"\n [edges]=\"flowEdges()\"\n [minZoom]=\"0.4\"\n [maxZoom]=\"1.
|
|
202
|
+
static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "21.2.20", type: FlowCanvasComponent, isStandalone: true, selector: "fx-ui-flow-canvas", inputs: { nodes: { classPropertyName: "nodes", publicName: "nodes", isSignal: true, isRequired: false, transformFunction: null }, edges: { classPropertyName: "edges", publicName: "edges", isSignal: true, isRequired: false, transformFunction: null }, activeId: { classPropertyName: "activeId", publicName: "activeId", isSignal: true, isRequired: false, transformFunction: null }, height: { classPropertyName: "height", publicName: "height", isSignal: true, isRequired: false, transformFunction: null }, emptyText: { classPropertyName: "emptyText", publicName: "emptyText", isSignal: true, isRequired: false, transformFunction: null } }, outputs: { nodeClick: "nodeClick" }, viewQueries: [{ propertyName: "flow", first: true, predicate: VflowComponent, descendants: true, isSignal: true }], ngImport: i0, template: "<ng-template #blankHandle></ng-template>\n\n@if (isEmpty()) {\n <div\n class=\"flex items-center justify-center rounded-card border border-border bg-surface-sunken txt-body-01 text-text-placeholder\"\n [style.height]=\"resolvedHeight()\"\n >\n {{ emptyText() }}\n </div>\n} @else {\n <!-- view=\"auto\" sizes the flow from this wrapper, so the height input is the\n single source of truth for the canvas box. -->\n <div class=\"fx-chain-canvas rounded-card border border-border overflow-hidden\" [style.height]=\"resolvedHeight()\">\n <vflow\n view=\"auto\"\n [nodes]=\"flowNodes()\"\n [edges]=\"flowEdges()\"\n [minZoom]=\"0.4\"\n [maxZoom]=\"1.35\"\n [entitiesSelectable]=\"false\"\n background=\"rgba(var(--og-surface-sunken) / 1)\"\n >\n <ng-template let-ctx nodeHtml>\n <!-- Handles are what edges anchor to: without them vflow renders the\n cards but draws no connections. The graph is read-only here, so an\n empty template replaces vflow's default handle dot (it only draws\n one when the template is null) while keeping the anchor point. -->\n <handle type=\"target\" position=\"left\" [template]=\"blankHandle\" />\n <handle type=\"source\" position=\"right\" [template]=\"blankHandle\" />\n <button\n type=\"button\"\n class=\"fx-chain-node\"\n [ngClass]=\"{\n 'fx-chain-node--active': isActive(ctx.node.data),\n 'fx-chain-node--related': isRelated(ctx.node.data),\n 'fx-chain-node--dim': isDimmed(ctx.node.data),\n }\"\n (click)=\"nodeClick.emit(ctx.node.data.id)\"\n >\n <span class=\"fx-chain-node__eyebrow\">\n <span class=\"fx-chain-node__dot\" [ngClass]=\"'bg-' + kindTone(ctx.node.data.kind)\"></span>\n <span [ngClass]=\"'text-' + kindTone(ctx.node.data.kind)\">{{ ctx.node.data.kindLabel || ctx.node.data.kind }}</span>\n @if (ctx.node.data.verified !== null && ctx.node.data.verified !== undefined) {\n <span\n class=\"fx-chain-node__check\"\n [ngClass]=\"ctx.node.data.verified ? 'bg-success/20 text-success' : 'bg-bg-hover text-text-placeholder'\"\n >\n {{ ctx.node.data.verified ? '\u2713' : '\u25CB' }}\n </span>\n }\n </span>\n <span class=\"fx-chain-node__label\">{{ ctx.node.data.label }}</span>\n @if (ctx.node.data.caption) {\n <span class=\"fx-chain-node__caption\">{{ ctx.node.data.caption }}</span>\n }\n </button>\n </ng-template>\n\n <!-- Edge state is read from activeId here rather than baked into the edge\n objects, so selecting a stage restyles without re-creating them.\n The arrowhead only shows on the selected step (design 04). -->\n <ng-template let-ctx edge>\n <svg:path\n class=\"fx-chain-edge\"\n [class.fx-chain-edge--active]=\"isEdgeActive(ctx.edge)\"\n [class.fx-chain-edge--dim]=\"isEdgeDimmed(ctx.edge)\"\n [attr.d]=\"ctx.path()\"\n [attr.marker-end]=\"isEdgeActive(ctx.edge) ? ctx.markerEnd() : null\"\n />\n </ng-template>\n </vflow>\n </div>\n}\n", styles: ["@charset \"UTF-8\";@layer properties;:host{display:block;width:100%}.fx-chain-canvas{background:rgba(var(--og-surface-sunken)/1)}.fx-chain-node{display:flex;cursor:pointer;flex-direction:column;justify-content:center;gap:.125rem;border-radius:var(--og-radius-control);border-style:var(--tw-border-style);border-width:1px;border-color:rgb(var(--og-border));background-color:rgb(var(--og-surface));padding-inline:.5rem;padding-block:.25rem;text-align:left;transition-property:all;transition-timing-function:var(--tw-ease, var(--default-transition-timing-function, cubic-bezier(.4, 0, .2, 1)));transition-duration:var(--tw-duration, var(--default-transition-duration, .15s));--tw-duration: .15s;transition-duration:.15s;width:176px;height:66px}.fx-chain-node:hover:not(.fx-chain-node--active){border-color:rgb(var(--border-strong))}.fx-chain-node--active{border-color:rgb(var(--og-accent));--tw-shadow: 0 4px 6px -1px var(--tw-shadow-color, rgb(var(--shadow-color) / .1)), 0 2px 4px -2px var(--tw-shadow-color, rgb(var(--shadow-color) / .1));box-shadow:var(--tw-inset-shadow),var(--tw-inset-ring-shadow),var(--tw-ring-offset-shadow),var(--tw-ring-shadow),var(--tw-shadow);border-width:2px}.fx-chain-node--related{border-color:rgb(var(--og-accent));border-color:rgba(var(--og-accent)/.45)}.fx-chain-node--dim{opacity:.55}.fx-chain-edge{fill:none;stroke:rgba(var(--og-border-strong)/1);stroke-width:1.5;transition:stroke .15s ease,stroke-width .15s ease,opacity .15s ease}.fx-chain-edge--active{stroke:rgba(var(--og-accent)/1);stroke-width:2.5}.fx-chain-edge--dim{opacity:.35}.fx-chain-node__eyebrow{display:flex;align-items:center;gap:.125rem;overflow:hidden;white-space:nowrap;font-size:9px;line-height:1.2;letter-spacing:var(--og-tracking-label);text-transform:uppercase;font-weight:700}.fx-chain-node__dot{flex-shrink:0;border-radius:calc(infinity * 1px);width:5px;height:5px}.fx-chain-node__check{margin-left:auto;display:flex;flex-shrink:0;align-items:center;justify-content:center;border-radius:calc(infinity * 1px);width:13px;height:13px;font-size:9px}.fx-chain-node__label{overflow:hidden;text-overflow:ellipsis;white-space:nowrap;color:rgb(var(--og-text));font-family:var(--og-font-mono);font-size:12px;font-weight:600}.fx-chain-node__caption{overflow:hidden;text-overflow:ellipsis;white-space:nowrap;color:rgb(var(--og-text-muted));font-size:10px;line-height:1.3}@property --tw-border-style{syntax: \"*\"; inherits: false; initial-value: solid;}@property --tw-duration{syntax: \"*\"; inherits: false;}@property --tw-shadow{syntax: \"*\"; inherits: false; initial-value: 0 0 #0000;}@property --tw-shadow-color{syntax: \"*\"; inherits: false;}@property --tw-shadow-alpha{syntax: \"<percentage>\"; inherits: false; initial-value: 100%;}@property --tw-inset-shadow{syntax: \"*\"; inherits: false; initial-value: 0 0 #0000;}@property --tw-inset-shadow-color{syntax: \"*\"; inherits: false;}@property --tw-inset-shadow-alpha{syntax: \"<percentage>\"; inherits: false; initial-value: 100%;}@property --tw-ring-color{syntax: \"*\"; inherits: false;}@property --tw-ring-shadow{syntax: \"*\"; inherits: false; initial-value: 0 0 #0000;}@property --tw-inset-ring-color{syntax: \"*\"; inherits: false;}@property --tw-inset-ring-shadow{syntax: \"*\"; inherits: false; initial-value: 0 0 #0000;}@property --tw-ring-inset{syntax: \"*\"; inherits: false;}@property --tw-ring-offset-width{syntax: \"<length>\"; inherits: false; initial-value: 0px;}@property --tw-ring-offset-color{syntax: \"*\"; inherits: false; initial-value: #fff;}@property --tw-ring-offset-shadow{syntax: \"*\"; inherits: false; initial-value: 0 0 #0000;}@layer properties{@supports ((-webkit-hyphens: none) and (not (margin-trim: inline))) or ((-moz-orient: inline) and (not (color:rgb(from red r g b)))){*,:before,:after,::backdrop{--tw-border-style: solid;--tw-duration: initial;--tw-shadow: 0 0 #0000;--tw-shadow-color: initial;--tw-shadow-alpha: 100%;--tw-inset-shadow: 0 0 #0000;--tw-inset-shadow-color: initial;--tw-inset-shadow-alpha: 100%;--tw-ring-color: initial;--tw-ring-shadow: 0 0 #0000;--tw-inset-ring-color: initial;--tw-inset-ring-shadow: 0 0 #0000;--tw-ring-inset: initial;--tw-ring-offset-width: 0px;--tw-ring-offset-color: #fff;--tw-ring-offset-shadow: 0 0 #0000}}}\n/*! tailwindcss v4.3.3 | MIT License | https://tailwindcss.com */\n"], dependencies: [{ kind: "directive", type: NgClass, selector: "[ngClass]", inputs: ["class", "ngClass"] }, { kind: "component", type: VflowComponent, selector: "vflow", inputs: ["view", "minZoom", "maxZoom", "background", "optimization", "entitiesSelectable", "keyboardShortcuts", "connection", "snapGrid", "elevateNodesOnSelect", "elevateEdgesOnSelect", "nodes", "alignmentHelper", "edges"], outputs: ["onComponentNodeEvent"] }, { kind: "directive", type: NodeHtmlTemplateDirective, selector: "ng-template[nodeHtml]" }, { kind: "directive", type: EdgeTemplateDirective, selector: "ng-template[edge]" }, { kind: "component", type: HandleComponent, selector: "handle", inputs: ["position", "type", "id", "template", "offsetX", "offsetY"] }], changeDetection: i0.ChangeDetectionStrategy.OnPush });
|
|
166
203
|
}
|
|
167
204
|
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.20", ngImport: i0, type: FlowCanvasComponent, decorators: [{
|
|
168
205
|
type: Component,
|
|
@@ -172,8 +209,8 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.20", ngImpo
|
|
|
172
209
|
NodeHtmlTemplateDirective,
|
|
173
210
|
EdgeTemplateDirective,
|
|
174
211
|
HandleComponent,
|
|
175
|
-
], template: "<ng-template #blankHandle></ng-template>\n\n@if (isEmpty()) {\n <div\n class=\"flex items-center justify-center rounded-card border border-border bg-surface-sunken txt-body-01 text-text-placeholder\"\n [style.height]=\"resolvedHeight()\"\n >\n {{ emptyText() }}\n </div>\n} @else {\n <!-- view=\"auto\" sizes the flow from this wrapper, so the height input is the\n single source of truth for the canvas box. -->\n <div class=\"fx-chain-canvas rounded-card border border-border overflow-hidden\" [style.height]=\"resolvedHeight()\">\n <vflow\n view=\"auto\"\n [nodes]=\"flowNodes()\"\n [edges]=\"flowEdges()\"\n [minZoom]=\"0.4\"\n [maxZoom]=\"1.
|
|
176
|
-
}], propDecorators: { nodes: [{ type: i0.Input, args: [{ isSignal: true, alias: "nodes", required: false }] }], edges: [{ type: i0.Input, args: [{ isSignal: true, alias: "edges", required: false }] }], activeId: [{ type: i0.Input, args: [{ isSignal: true, alias: "activeId", required: false }] }], height: [{ type: i0.Input, args: [{ isSignal: true, alias: "height", required: false }] }], emptyText: [{ type: i0.Input, args: [{ isSignal: true, alias: "emptyText", required: false }] }], nodeClick: [{ type: i0.Output, args: ["nodeClick"] }] } });
|
|
212
|
+
], template: "<ng-template #blankHandle></ng-template>\n\n@if (isEmpty()) {\n <div\n class=\"flex items-center justify-center rounded-card border border-border bg-surface-sunken txt-body-01 text-text-placeholder\"\n [style.height]=\"resolvedHeight()\"\n >\n {{ emptyText() }}\n </div>\n} @else {\n <!-- view=\"auto\" sizes the flow from this wrapper, so the height input is the\n single source of truth for the canvas box. -->\n <div class=\"fx-chain-canvas rounded-card border border-border overflow-hidden\" [style.height]=\"resolvedHeight()\">\n <vflow\n view=\"auto\"\n [nodes]=\"flowNodes()\"\n [edges]=\"flowEdges()\"\n [minZoom]=\"0.4\"\n [maxZoom]=\"1.35\"\n [entitiesSelectable]=\"false\"\n background=\"rgba(var(--og-surface-sunken) / 1)\"\n >\n <ng-template let-ctx nodeHtml>\n <!-- Handles are what edges anchor to: without them vflow renders the\n cards but draws no connections. The graph is read-only here, so an\n empty template replaces vflow's default handle dot (it only draws\n one when the template is null) while keeping the anchor point. -->\n <handle type=\"target\" position=\"left\" [template]=\"blankHandle\" />\n <handle type=\"source\" position=\"right\" [template]=\"blankHandle\" />\n <button\n type=\"button\"\n class=\"fx-chain-node\"\n [ngClass]=\"{\n 'fx-chain-node--active': isActive(ctx.node.data),\n 'fx-chain-node--related': isRelated(ctx.node.data),\n 'fx-chain-node--dim': isDimmed(ctx.node.data),\n }\"\n (click)=\"nodeClick.emit(ctx.node.data.id)\"\n >\n <span class=\"fx-chain-node__eyebrow\">\n <span class=\"fx-chain-node__dot\" [ngClass]=\"'bg-' + kindTone(ctx.node.data.kind)\"></span>\n <span [ngClass]=\"'text-' + kindTone(ctx.node.data.kind)\">{{ ctx.node.data.kindLabel || ctx.node.data.kind }}</span>\n @if (ctx.node.data.verified !== null && ctx.node.data.verified !== undefined) {\n <span\n class=\"fx-chain-node__check\"\n [ngClass]=\"ctx.node.data.verified ? 'bg-success/20 text-success' : 'bg-bg-hover text-text-placeholder'\"\n >\n {{ ctx.node.data.verified ? '\u2713' : '\u25CB' }}\n </span>\n }\n </span>\n <span class=\"fx-chain-node__label\">{{ ctx.node.data.label }}</span>\n @if (ctx.node.data.caption) {\n <span class=\"fx-chain-node__caption\">{{ ctx.node.data.caption }}</span>\n }\n </button>\n </ng-template>\n\n <!-- Edge state is read from activeId here rather than baked into the edge\n objects, so selecting a stage restyles without re-creating them.\n The arrowhead only shows on the selected step (design 04). -->\n <ng-template let-ctx edge>\n <svg:path\n class=\"fx-chain-edge\"\n [class.fx-chain-edge--active]=\"isEdgeActive(ctx.edge)\"\n [class.fx-chain-edge--dim]=\"isEdgeDimmed(ctx.edge)\"\n [attr.d]=\"ctx.path()\"\n [attr.marker-end]=\"isEdgeActive(ctx.edge) ? ctx.markerEnd() : null\"\n />\n </ng-template>\n </vflow>\n </div>\n}\n", styles: ["@charset \"UTF-8\";@layer properties;:host{display:block;width:100%}.fx-chain-canvas{background:rgba(var(--og-surface-sunken)/1)}.fx-chain-node{display:flex;cursor:pointer;flex-direction:column;justify-content:center;gap:.125rem;border-radius:var(--og-radius-control);border-style:var(--tw-border-style);border-width:1px;border-color:rgb(var(--og-border));background-color:rgb(var(--og-surface));padding-inline:.5rem;padding-block:.25rem;text-align:left;transition-property:all;transition-timing-function:var(--tw-ease, var(--default-transition-timing-function, cubic-bezier(.4, 0, .2, 1)));transition-duration:var(--tw-duration, var(--default-transition-duration, .15s));--tw-duration: .15s;transition-duration:.15s;width:176px;height:66px}.fx-chain-node:hover:not(.fx-chain-node--active){border-color:rgb(var(--border-strong))}.fx-chain-node--active{border-color:rgb(var(--og-accent));--tw-shadow: 0 4px 6px -1px var(--tw-shadow-color, rgb(var(--shadow-color) / .1)), 0 2px 4px -2px var(--tw-shadow-color, rgb(var(--shadow-color) / .1));box-shadow:var(--tw-inset-shadow),var(--tw-inset-ring-shadow),var(--tw-ring-offset-shadow),var(--tw-ring-shadow),var(--tw-shadow);border-width:2px}.fx-chain-node--related{border-color:rgb(var(--og-accent));border-color:rgba(var(--og-accent)/.45)}.fx-chain-node--dim{opacity:.55}.fx-chain-edge{fill:none;stroke:rgba(var(--og-border-strong)/1);stroke-width:1.5;transition:stroke .15s ease,stroke-width .15s ease,opacity .15s ease}.fx-chain-edge--active{stroke:rgba(var(--og-accent)/1);stroke-width:2.5}.fx-chain-edge--dim{opacity:.35}.fx-chain-node__eyebrow{display:flex;align-items:center;gap:.125rem;overflow:hidden;white-space:nowrap;font-size:9px;line-height:1.2;letter-spacing:var(--og-tracking-label);text-transform:uppercase;font-weight:700}.fx-chain-node__dot{flex-shrink:0;border-radius:calc(infinity * 1px);width:5px;height:5px}.fx-chain-node__check{margin-left:auto;display:flex;flex-shrink:0;align-items:center;justify-content:center;border-radius:calc(infinity * 1px);width:13px;height:13px;font-size:9px}.fx-chain-node__label{overflow:hidden;text-overflow:ellipsis;white-space:nowrap;color:rgb(var(--og-text));font-family:var(--og-font-mono);font-size:12px;font-weight:600}.fx-chain-node__caption{overflow:hidden;text-overflow:ellipsis;white-space:nowrap;color:rgb(var(--og-text-muted));font-size:10px;line-height:1.3}@property --tw-border-style{syntax: \"*\"; inherits: false; initial-value: solid;}@property --tw-duration{syntax: \"*\"; inherits: false;}@property --tw-shadow{syntax: \"*\"; inherits: false; initial-value: 0 0 #0000;}@property --tw-shadow-color{syntax: \"*\"; inherits: false;}@property --tw-shadow-alpha{syntax: \"<percentage>\"; inherits: false; initial-value: 100%;}@property --tw-inset-shadow{syntax: \"*\"; inherits: false; initial-value: 0 0 #0000;}@property --tw-inset-shadow-color{syntax: \"*\"; inherits: false;}@property --tw-inset-shadow-alpha{syntax: \"<percentage>\"; inherits: false; initial-value: 100%;}@property --tw-ring-color{syntax: \"*\"; inherits: false;}@property --tw-ring-shadow{syntax: \"*\"; inherits: false; initial-value: 0 0 #0000;}@property --tw-inset-ring-color{syntax: \"*\"; inherits: false;}@property --tw-inset-ring-shadow{syntax: \"*\"; inherits: false; initial-value: 0 0 #0000;}@property --tw-ring-inset{syntax: \"*\"; inherits: false;}@property --tw-ring-offset-width{syntax: \"<length>\"; inherits: false; initial-value: 0px;}@property --tw-ring-offset-color{syntax: \"*\"; inherits: false; initial-value: #fff;}@property --tw-ring-offset-shadow{syntax: \"*\"; inherits: false; initial-value: 0 0 #0000;}@layer properties{@supports ((-webkit-hyphens: none) and (not (margin-trim: inline))) or ((-moz-orient: inline) and (not (color:rgb(from red r g b)))){*,:before,:after,::backdrop{--tw-border-style: solid;--tw-duration: initial;--tw-shadow: 0 0 #0000;--tw-shadow-color: initial;--tw-shadow-alpha: 100%;--tw-inset-shadow: 0 0 #0000;--tw-inset-shadow-color: initial;--tw-inset-shadow-alpha: 100%;--tw-ring-color: initial;--tw-ring-shadow: 0 0 #0000;--tw-inset-ring-color: initial;--tw-inset-ring-shadow: 0 0 #0000;--tw-ring-inset: initial;--tw-ring-offset-width: 0px;--tw-ring-offset-color: #fff;--tw-ring-offset-shadow: 0 0 #0000}}}\n/*! tailwindcss v4.3.3 | MIT License | https://tailwindcss.com */\n"] }]
|
|
213
|
+
}], ctorParameters: () => [], propDecorators: { nodes: [{ type: i0.Input, args: [{ isSignal: true, alias: "nodes", required: false }] }], edges: [{ type: i0.Input, args: [{ isSignal: true, alias: "edges", required: false }] }], activeId: [{ type: i0.Input, args: [{ isSignal: true, alias: "activeId", required: false }] }], height: [{ type: i0.Input, args: [{ isSignal: true, alias: "height", required: false }] }], emptyText: [{ type: i0.Input, args: [{ isSignal: true, alias: "emptyText", required: false }] }], nodeClick: [{ type: i0.Output, args: ["nodeClick"] }], flow: [{ type: i0.ViewChild, args: [i0.forwardRef(() => VflowComponent), { isSignal: true }] }] } });
|
|
177
214
|
|
|
178
215
|
class FlowConnection {
|
|
179
216
|
nodes = input([], ...(ngDevMode ? [{ debugName: "nodes" }] : /* istanbul ignore next */ []));
|