@foxeltech/angular-ui 0.4.0 → 0.7.44
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/archivo/archivo-400-latin-ext.woff2 +0 -0
- package/archivo/archivo-400-latin.woff2 +0 -0
- package/archivo/archivo-400-vietnamese.woff2 +0 -0
- package/archivo/archivo-500-latin-ext.woff2 +0 -0
- package/archivo/archivo-500-latin.woff2 +0 -0
- package/archivo/archivo-500-vietnamese.woff2 +0 -0
- package/archivo/archivo-600-latin-ext.woff2 +0 -0
- package/archivo/archivo-600-latin.woff2 +0 -0
- package/archivo/archivo-600-vietnamese.woff2 +0 -0
- package/archivo/archivo-700-latin-ext.woff2 +0 -0
- package/archivo/archivo-700-latin.woff2 +0 -0
- package/archivo/archivo-700-vietnamese.woff2 +0 -0
- package/components.css +12 -12
- package/dialogs.css +2 -2
- package/fesm2022/foxeltech-angular-ui-chart.mjs +185 -17
- package/fesm2022/foxeltech-angular-ui-chart.mjs.map +1 -1
- package/fesm2022/foxeltech-angular-ui-flow.mjs +176 -3
- package/fesm2022/foxeltech-angular-ui-flow.mjs.map +1 -1
- package/fesm2022/foxeltech-angular-ui-rich-text.mjs +2 -2
- package/fesm2022/foxeltech-angular-ui-rich-text.mjs.map +1 -1
- package/fesm2022/foxeltech-angular-ui.mjs +849 -69
- package/fesm2022/foxeltech-angular-ui.mjs.map +1 -1
- package/fonts.css +462 -138
- package/ibm-plex-mono/ibm-plex-mono-400-cyrillic-ext.woff2 +0 -0
- package/ibm-plex-mono/ibm-plex-mono-400-cyrillic.woff2 +0 -0
- package/ibm-plex-mono/ibm-plex-mono-400-latin-ext.woff2 +0 -0
- package/ibm-plex-mono/ibm-plex-mono-400-latin.woff2 +0 -0
- package/ibm-plex-mono/ibm-plex-mono-400-vietnamese.woff2 +0 -0
- package/ibm-plex-mono/ibm-plex-mono-500-cyrillic-ext.woff2 +0 -0
- package/ibm-plex-mono/ibm-plex-mono-500-cyrillic.woff2 +0 -0
- package/ibm-plex-mono/ibm-plex-mono-500-latin-ext.woff2 +0 -0
- package/ibm-plex-mono/ibm-plex-mono-500-latin.woff2 +0 -0
- package/ibm-plex-mono/ibm-plex-mono-500-vietnamese.woff2 +0 -0
- package/ibm-plex-mono/ibm-plex-mono-600-cyrillic-ext.woff2 +0 -0
- package/ibm-plex-mono/ibm-plex-mono-600-cyrillic.woff2 +0 -0
- package/ibm-plex-mono/ibm-plex-mono-600-latin-ext.woff2 +0 -0
- package/ibm-plex-mono/ibm-plex-mono-600-latin.woff2 +0 -0
- package/ibm-plex-mono/ibm-plex-mono-600-vietnamese.woff2 +0 -0
- package/jetbrains-mono/jetbrains-mono-400-cyrillic-ext.woff2 +0 -0
- package/jetbrains-mono/jetbrains-mono-400-cyrillic.woff2 +0 -0
- package/jetbrains-mono/jetbrains-mono-400-greek.woff2 +0 -0
- package/jetbrains-mono/jetbrains-mono-400-latin-ext.woff2 +0 -0
- package/jetbrains-mono/jetbrains-mono-400-latin.woff2 +0 -0
- package/jetbrains-mono/jetbrains-mono-400-vietnamese.woff2 +0 -0
- package/jetbrains-mono/jetbrains-mono-500-cyrillic-ext.woff2 +0 -0
- package/jetbrains-mono/jetbrains-mono-500-cyrillic.woff2 +0 -0
- package/jetbrains-mono/jetbrains-mono-500-greek.woff2 +0 -0
- package/jetbrains-mono/jetbrains-mono-500-latin-ext.woff2 +0 -0
- package/jetbrains-mono/jetbrains-mono-500-latin.woff2 +0 -0
- package/jetbrains-mono/jetbrains-mono-500-vietnamese.woff2 +0 -0
- package/jetbrains-mono/jetbrains-mono-600-cyrillic-ext.woff2 +0 -0
- package/jetbrains-mono/jetbrains-mono-600-cyrillic.woff2 +0 -0
- package/jetbrains-mono/jetbrains-mono-600-greek.woff2 +0 -0
- package/jetbrains-mono/jetbrains-mono-600-latin-ext.woff2 +0 -0
- package/jetbrains-mono/jetbrains-mono-600-latin.woff2 +0 -0
- package/jetbrains-mono/jetbrains-mono-600-vietnamese.woff2 +0 -0
- package/jetbrains-mono/jetbrains-mono-700-cyrillic-ext.woff2 +0 -0
- package/jetbrains-mono/jetbrains-mono-700-cyrillic.woff2 +0 -0
- package/jetbrains-mono/jetbrains-mono-700-greek.woff2 +0 -0
- package/jetbrains-mono/jetbrains-mono-700-latin-ext.woff2 +0 -0
- package/jetbrains-mono/jetbrains-mono-700-latin.woff2 +0 -0
- package/jetbrains-mono/jetbrains-mono-700-vietnamese.woff2 +0 -0
- package/newsreader/newsreader-400-latin-ext.woff2 +0 -0
- package/newsreader/newsreader-400-latin.woff2 +0 -0
- package/newsreader/newsreader-400-vietnamese.woff2 +0 -0
- package/newsreader/newsreader-500-latin-ext.woff2 +0 -0
- package/newsreader/newsreader-500-latin.woff2 +0 -0
- package/newsreader/newsreader-500-vietnamese.woff2 +0 -0
- package/newsreader/newsreader-600-latin-ext.woff2 +0 -0
- package/newsreader/newsreader-600-latin.woff2 +0 -0
- package/newsreader/newsreader-600-vietnamese.woff2 +0 -0
- package/package.json +5 -2
- package/source-serif-4/source-serif-4-400-cyrillic-ext.woff2 +0 -0
- package/source-serif-4/source-serif-4-400-cyrillic.woff2 +0 -0
- package/source-serif-4/source-serif-4-400-greek.woff2 +0 -0
- package/source-serif-4/source-serif-4-400-latin-ext.woff2 +0 -0
- package/source-serif-4/source-serif-4-400-latin.woff2 +0 -0
- package/source-serif-4/source-serif-4-400-vietnamese.woff2 +0 -0
- package/source-serif-4/source-serif-4-600-cyrillic-ext.woff2 +0 -0
- package/source-serif-4/source-serif-4-600-cyrillic.woff2 +0 -0
- package/source-serif-4/source-serif-4-600-greek.woff2 +0 -0
- package/source-serif-4/source-serif-4-600-latin-ext.woff2 +0 -0
- package/source-serif-4/source-serif-4-600-latin.woff2 +0 -0
- package/source-serif-4/source-serif-4-600-vietnamese.woff2 +0 -0
- package/src/lib/styles/components.css +12 -12
- package/src/lib/styles/dialogs.css +2 -2
- package/src/lib/styles/fonts.css +462 -138
- package/src/lib/styles/tailwind.css +1 -1
- package/src/lib/styles/theme.css +596 -69
- package/src/lib/styles/tokens.css +56 -19
- package/src/lib/styles/utilities.css +4 -1
- package/src/lib/ui/components/bar-list/bar-list.component.html +29 -0
- package/src/lib/ui/components/button/button.component.html +7 -5
- package/src/lib/ui/components/checkbox/checkbox.component.html +1 -1
- package/src/lib/ui/components/code-block/code-block.component.html +8 -0
- package/src/lib/ui/components/drawer/drawer.component.html +35 -12
- package/src/lib/ui/components/drawer/drawer.component.scss +104 -18
- package/src/lib/ui/components/facets-rail/facets-rail.component.html +42 -0
- package/src/lib/ui/components/filter-pills/filter-pills.component.html +16 -0
- package/src/lib/ui/components/kanban-board/kanban-board.component.scss +9 -9
- package/src/lib/ui/components/list-row/list-row.component.html +20 -0
- package/src/lib/ui/components/master-detail/master-detail.component.css +22 -0
- package/src/lib/ui/components/master-detail/master-detail.component.html +33 -1
- package/src/lib/ui/components/pending-badge/pending-badge.component.html +15 -0
- package/src/lib/ui/components/pipeline-stepper/pipeline-stepper.component.html +45 -0
- package/src/lib/ui/components/project-card/project-card.component.html +102 -0
- package/src/lib/ui/components/radio-button/radio-button.component.html +1 -1
- package/src/lib/ui/components/radio-button-toggle/radio-button-toggle.component.html +1 -1
- package/src/lib/ui/components/sample-frame/sample-frame.component.html +18 -0
- package/src/lib/ui/components/score-badge/score-badge.component.html +7 -0
- package/src/lib/ui/components/screenshot-frame/screenshot-frame.component.html +40 -0
- package/src/lib/ui/components/section-card/section-card.component.html +19 -6
- package/src/lib/ui/components/segmented/segmented.component.html +42 -0
- package/src/lib/ui/components/segmented/segmented.component.scss +12 -0
- package/src/lib/ui/components/slider/slider.component.html +2 -2
- package/src/lib/ui/components/sparkbar/sparkbar.component.html +14 -0
- package/src/lib/ui/components/stage-dots/stage-dots.component.html +13 -0
- package/src/lib/ui/components/stat-cards/stat-cards.component.html +44 -11
- package/src/lib/ui/components/status-dot/status-dot.component.html +13 -0
- package/src/lib/ui/components/tab-group/tab-group.component.html +37 -8
- package/src/lib/ui/components/tab-group/tab-group.component.scss +41 -1
- package/src/lib/ui/components/tag/tag.component.html +2 -2
- package/src/lib/ui/components/theme-picker/theme-picker.component.html +44 -0
- package/src/lib/ui/components/tree-diagram/tree-diagram.component.html +3 -3
- package/tailwind.css +1 -1
- package/theme.css +596 -69
- package/tokens.css +56 -19
- package/types/foxeltech-angular-ui-chart.d.ts +14 -2
- package/types/foxeltech-angular-ui-flow.d.ts +83 -1
- package/types/foxeltech-angular-ui.d.ts +636 -20
- package/utilities.css +4 -1
- package/BeVietnamPro/BeVietnamPro-Bold.woff2 +0 -0
- package/BeVietnamPro/BeVietnamPro-ExtraLight.woff2 +0 -0
- package/BeVietnamPro/BeVietnamPro-Light.woff2 +0 -0
- package/BeVietnamPro/BeVietnamPro-Medium.woff2 +0 -0
- package/BeVietnamPro/BeVietnamPro-Regular.woff2 +0 -0
- package/BeVietnamPro/BeVietnamPro-SemiBold.woff2 +0 -0
- package/BeVietnamPro/BeVietnamPro-Thin.woff2 +0 -0
- package/SpaceMono-Regular.woff2 +0 -0
- package/dm-sans/DMSans-Bold.woff2 +0 -0
- package/dm-sans/DMSans-Light.woff2 +0 -0
- package/dm-sans/DMSans-Medium.woff2 +0 -0
- package/dm-sans/DMSans-Regular.woff2 +0 -0
- package/dm-sans/DMSans-SemiBold.woff2 +0 -0
- package/dm-sans/DMSans-Thin.woff2 +0 -0
- package/orbitron/Orbitron-Bold.woff2 +0 -0
- package/orbitron/Orbitron-Medium.woff2 +0 -0
- package/orbitron/Orbitron-Regular.woff2 +0 -0
- package/orbitron/Orbitron-SemiBold.woff2 +0 -0
- package/roboto/Roboto-Black.woff2 +0 -0
- package/roboto/Roboto-BlackItalic.woff2 +0 -0
- package/roboto/Roboto-Bold.woff2 +0 -0
- package/roboto/Roboto-BoldCondensed.woff2 +0 -0
- package/roboto/Roboto-BoldCondensedItalic.woff2 +0 -0
- package/roboto/Roboto-BoldItalic.woff2 +0 -0
- package/roboto/Roboto-Condensed.woff2 +0 -0
- package/roboto/Roboto-CondensedItalic.woff2 +0 -0
- package/roboto/Roboto-Italic.woff2 +0 -0
- package/roboto/Roboto-Light.woff2 +0 -0
- package/roboto/Roboto-LightItalic.woff2 +0 -0
- package/roboto/Roboto-Medium.woff2 +0 -0
- package/roboto/Roboto-MediumItalic.woff2 +0 -0
- package/roboto/Roboto-Regular.woff2 +0 -0
- package/roboto/Roboto-Thin.woff2 +0 -0
- package/roboto/Roboto-ThinItalic.woff2 +0 -0
|
@@ -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// 'line' and 'radar' were advertised here but have no builder in the\n// registry — they silently rendered an empty chart. Re-add when implemented.\nexport type IChartType = 'bar' | 'pie' | 'sunburst' | '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 readonly mobileWidth = input(350);\n readonly labelFontFamily = input('Roboto');\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 labelFontSize = 12;\n\n private chartInstance?: ECharts;\n private resizeObserver?: ResizeObserver;\n private intersectionObserver?: IntersectionObserver;\n\n private canInit = false;\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) {\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) return;\n this.updateResponsiveState();\n this.forceMediaRecalc();\n });\n\n this.resizeObserver.observe(this.ref.nativeElement);\n }\n\n ngOnChanges(): void {\n if (this.canInit) {\n this.updateResponsiveState();\n this.rebuildChart();\n }\n }\n\n ngOnDestroy(): void {\n this.resizeObserver?.disconnect();\n this.intersectionObserver?.disconnect();\n }\n\n @HostListener('window:theme-changed')\n onThemeChange(): void {\n if (!this.canInit) return;\n requestAnimationFrame(() => this.rebuildChart());\n }\n\n /* ================= EVENTS ================= */\n\n onChartClick(event: any) {\n this.chartClick.emit(event);\n }\n\n onChartInit(chart: any) {\n this.chartInstance = chart;\n this.chartInit.emit(chart);\n\n requestAnimationFrame(() => this.forceMediaRecalc());\n }\n\n /* ================= CORE FIX ================= */\n\n private updateResponsiveState() {\n const { width } = this.ref.nativeElement.getBoundingClientRect();\n if (width > 0) {\n this.containerWidth = width;\n this.isMobile = width < this.mobileWidth();\n }\n }\n\n private forceMediaRecalc(retry = 0) {\n if (!this.chartInstance) return;\n\n const { width, height } = this.ref.nativeElement.getBoundingClientRect();\n\n if ((width === 0 || height === 0) && retry < 10) {\n requestAnimationFrame(() => this.forceMediaRecalc(retry + 1));\n return;\n }\n\n this.rebuildChart();\n this.chartInstance.resize();\n }\n\n private rebuildChart(): void {\n this.isEmpty = this.checkEmpty();\n\n if (this.isEmpty) {\n if (this.chartInstance) {\n this.chartInstance.clear();\n }\n return;\n }\n\n this.chartOptions = this.buildOptions();\n\n if (this.chartInstance) {\n this.chartInstance.clear();\n this.chartInstance.setOption(this.chartOptions, true);\n }\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 === '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.labelFontFamily(),\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.labelFontFamily(),\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.labelFontFamily(),\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 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.labelFontFamily(),\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.labelFontFamily(),\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 graphic: {\n type: 'group',\n left: layout.graphicLeft,\n top: layout.graphicTop,\n bounding: 'raw',\n children: [\n {\n type: 'text',\n style: {\n text: total.toString(),\n fontSize: 24,\n fontWeight: 600,\n fontFamily: this.labelFontFamily(),\n fill: FxUtils.convertColorFromVariable('--text-primary'),\n align: 'center',\n verticalAlign: 'middle',\n },\n },\n ],\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.labelFontFamily(),\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.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 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 {\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/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 labelFontSize = 12;\n\n private chartInstance?: ECharts;\n private resizeObserver?: ResizeObserver;\n private intersectionObserver?: IntersectionObserver;\n\n private canInit = false;\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) {\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) return;\n this.updateResponsiveState();\n this.forceMediaRecalc();\n });\n\n this.resizeObserver.observe(this.ref.nativeElement);\n }\n\n ngOnChanges(): void {\n if (this.canInit) {\n this.updateResponsiveState();\n this.rebuildChart();\n }\n }\n\n ngOnDestroy(): void {\n this.resizeObserver?.disconnect();\n this.intersectionObserver?.disconnect();\n }\n\n @HostListener('window:theme-changed')\n onThemeChange(): void {\n if (!this.canInit) return;\n requestAnimationFrame(() => this.rebuildChart());\n }\n\n /* ================= EVENTS ================= */\n\n onChartClick(event: any) {\n this.chartClick.emit(event);\n }\n\n onChartInit(chart: any) {\n this.chartInstance = chart;\n this.chartInit.emit(chart);\n\n requestAnimationFrame(() => this.forceMediaRecalc());\n }\n\n /* ================= CORE FIX ================= */\n\n private updateResponsiveState() {\n const { width } = this.ref.nativeElement.getBoundingClientRect();\n if (width > 0) {\n this.containerWidth = width;\n this.isMobile = width < this.mobileWidth();\n }\n }\n\n private forceMediaRecalc(retry = 0) {\n if (!this.chartInstance) return;\n\n const { width, height } = this.ref.nativeElement.getBoundingClientRect();\n\n if ((width === 0 || height === 0) && retry < 10) {\n requestAnimationFrame(() => this.forceMediaRecalc(retry + 1));\n return;\n }\n\n this.rebuildChart();\n this.chartInstance.resize();\n }\n\n private rebuildChart(): void {\n this.isEmpty = this.checkEmpty();\n\n if (this.isEmpty) {\n if (this.chartInstance) {\n this.chartInstance.clear();\n }\n return;\n }\n\n this.chartOptions = this.buildOptions();\n\n if (this.chartInstance) {\n this.chartInstance.clear();\n this.chartInstance.setOption(this.chartOptions, true);\n }\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 {\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,6 +1,179 @@
|
|
|
1
1
|
import * as i0 from '@angular/core';
|
|
2
|
-
import { input,
|
|
3
|
-
import {
|
|
2
|
+
import { input, output, computed, ChangeDetectionStrategy, Component, Input } from '@angular/core';
|
|
3
|
+
import { NgClass } from '@angular/common';
|
|
4
|
+
import { VflowComponent, NodeHtmlTemplateDirective, EdgeTemplateDirective, HandleComponent, ConnectionControllerDirective, ChangesControllerDirective } from 'ngx-vflow';
|
|
5
|
+
|
|
6
|
+
/** Kind → severity token. Exported so callers can tint matching chips (the
|
|
7
|
+
stage list beside the canvas) from the same source of truth. */
|
|
8
|
+
const FX_CHAIN_KIND_TONE = {
|
|
9
|
+
entry: 'warning',
|
|
10
|
+
convergence: 'information',
|
|
11
|
+
mitigation: 'success',
|
|
12
|
+
review: 'warning',
|
|
13
|
+
'not-reproduced': 'danger',
|
|
14
|
+
impact: 'critical',
|
|
15
|
+
stage: 'information',
|
|
16
|
+
};
|
|
17
|
+
const COLUMN_GAP = 216;
|
|
18
|
+
const ROW_GAP = 104;
|
|
19
|
+
const NODE_WIDTH = 176;
|
|
20
|
+
const NODE_HEIGHT = 66;
|
|
21
|
+
/**
|
|
22
|
+
* V2 exploit-chain canvas — the attack-path graph of design refs 04..07:
|
|
23
|
+
* kind-tinted node cards laid out left→right, curved edges, draggable nodes on
|
|
24
|
+
* a pannable/zoomable surface.
|
|
25
|
+
*
|
|
26
|
+
* Presentational: it takes a graph plus the currently selected node and emits
|
|
27
|
+
* clicks. Layout is derived from the edges (longest path from a source) unless
|
|
28
|
+
* a node pins its own column/row, so callers can hand over a plain chain.
|
|
29
|
+
*
|
|
30
|
+
* <fx-ui-flow-canvas [nodes]="chainNodes" [edges]="chainEdges"
|
|
31
|
+
* [activeId]="stageId()" (nodeClick)="selectStage($event)" />
|
|
32
|
+
*/
|
|
33
|
+
class FlowCanvasComponent {
|
|
34
|
+
nodes = input([], ...(ngDevMode ? [{ debugName: "nodes" }] : /* istanbul ignore next */ []));
|
|
35
|
+
edges = input([], ...(ngDevMode ? [{ debugName: "edges" }] : /* istanbul ignore next */ []));
|
|
36
|
+
/** Selected/current node: full opacity + accent border; the rest dim. */
|
|
37
|
+
activeId = input(null, ...(ngDevMode ? [{ debugName: "activeId" }] : /* istanbul ignore next */ []));
|
|
38
|
+
/** Explicit canvas height; omit to size it from the number of stacked rows. */
|
|
39
|
+
height = input('', ...(ngDevMode ? [{ debugName: "height" }] : /* istanbul ignore next */ []));
|
|
40
|
+
/** Caller-translated hint shown when the graph is empty. */
|
|
41
|
+
emptyText = input('No chain data available', ...(ngDevMode ? [{ debugName: "emptyText" }] : /* istanbul ignore next */ []));
|
|
42
|
+
nodeClick = output();
|
|
43
|
+
/** Column index per node: pinned value, else longest path from a source. */
|
|
44
|
+
columns = computed(() => {
|
|
45
|
+
const nodes = this.nodes();
|
|
46
|
+
const edges = this.edges();
|
|
47
|
+
const incoming = new Map();
|
|
48
|
+
nodes.forEach((n) => incoming.set(n.id, []));
|
|
49
|
+
edges.forEach((e) => incoming.get(e.target)?.push(e.source));
|
|
50
|
+
const depth = {};
|
|
51
|
+
const resolve = (id, seen) => {
|
|
52
|
+
if (depth[id] !== undefined)
|
|
53
|
+
return depth[id];
|
|
54
|
+
// Cycle guard: a malformed graph must not blow the stack.
|
|
55
|
+
if (seen.has(id))
|
|
56
|
+
return 0;
|
|
57
|
+
seen.add(id);
|
|
58
|
+
const parents = incoming.get(id) ?? [];
|
|
59
|
+
const value = parents.length
|
|
60
|
+
? Math.max(...parents.map((p) => resolve(p, seen))) + 1
|
|
61
|
+
: 0;
|
|
62
|
+
depth[id] = value;
|
|
63
|
+
return value;
|
|
64
|
+
};
|
|
65
|
+
nodes.forEach((n) => {
|
|
66
|
+
depth[n.id] = n.column ?? resolve(n.id, new Set());
|
|
67
|
+
});
|
|
68
|
+
return depth;
|
|
69
|
+
}, ...(ngDevMode ? [{ debugName: "columns" }] : /* istanbul ignore next */ []));
|
|
70
|
+
/** ngx-vflow nodes: html-template cards positioned by the derived layout. */
|
|
71
|
+
flowNodes = computed(() => {
|
|
72
|
+
const columns = this.columns();
|
|
73
|
+
const perColumn = {};
|
|
74
|
+
// Tallest column decides the vertical centre every column is balanced on.
|
|
75
|
+
const counts = {};
|
|
76
|
+
this.nodes().forEach((n) => {
|
|
77
|
+
const c = columns[n.id] ?? 0;
|
|
78
|
+
counts[c] = (counts[c] ?? 0) + 1;
|
|
79
|
+
});
|
|
80
|
+
const tallest = Math.max(1, ...Object.values(counts));
|
|
81
|
+
return this.nodes().map((node) => {
|
|
82
|
+
const column = columns[node.id] ?? 0;
|
|
83
|
+
const row = node.row ?? perColumn[column] ?? 0;
|
|
84
|
+
perColumn[column] = row + 1;
|
|
85
|
+
const rows = counts[column] ?? 1;
|
|
86
|
+
const offset = ((tallest - rows) * ROW_GAP) / 2;
|
|
87
|
+
return {
|
|
88
|
+
id: node.id,
|
|
89
|
+
type: 'html-template',
|
|
90
|
+
point: { x: 24 + column * COLUMN_GAP, y: 24 + offset + row * ROW_GAP },
|
|
91
|
+
width: NODE_WIDTH,
|
|
92
|
+
height: NODE_HEIGHT,
|
|
93
|
+
data: node,
|
|
94
|
+
};
|
|
95
|
+
});
|
|
96
|
+
}, ...(ngDevMode ? [{ debugName: "flowNodes" }] : /* istanbul ignore next */ []));
|
|
97
|
+
/**
|
|
98
|
+
* Edges stay identity-stable across selections: state lives in the template
|
|
99
|
+
* (read off `activeId`), so selecting a stage never re-creates them.
|
|
100
|
+
*/
|
|
101
|
+
flowEdges = computed(() => this.edges().map((e) => ({
|
|
102
|
+
id: `${e.source}->${e.target}`,
|
|
103
|
+
source: e.source,
|
|
104
|
+
target: e.target,
|
|
105
|
+
type: 'template',
|
|
106
|
+
curve: 'bezier',
|
|
107
|
+
markers: { end: { type: 'arrow-closed', width: 11, height: 11 } },
|
|
108
|
+
})), ...(ngDevMode ? [{ debugName: "flowEdges" }] : /* istanbul ignore next */ []));
|
|
109
|
+
/** Nodes one hop from the selection — they stay lit alongside it. */
|
|
110
|
+
relatedIds = computed(() => {
|
|
111
|
+
const active = this.activeId();
|
|
112
|
+
const related = new Set();
|
|
113
|
+
if (!active)
|
|
114
|
+
return related;
|
|
115
|
+
this.edges().forEach((e) => {
|
|
116
|
+
if (e.source === active)
|
|
117
|
+
related.add(e.target);
|
|
118
|
+
if (e.target === active)
|
|
119
|
+
related.add(e.source);
|
|
120
|
+
});
|
|
121
|
+
return related;
|
|
122
|
+
}, ...(ngDevMode ? [{ debugName: "relatedIds" }] : /* istanbul ignore next */ []));
|
|
123
|
+
isEmpty = computed(() => this.nodes().length === 0, ...(ngDevMode ? [{ debugName: "isEmpty" }] : /* istanbul ignore next */ []));
|
|
124
|
+
/**
|
|
125
|
+
* A linear chain needs one row, the design's converging entries need three —
|
|
126
|
+
* sizing from the layout keeps the card from leaving a tall empty band.
|
|
127
|
+
*/
|
|
128
|
+
resolvedHeight = computed(() => {
|
|
129
|
+
const explicit = this.height();
|
|
130
|
+
if (explicit)
|
|
131
|
+
return explicit;
|
|
132
|
+
const counts = {};
|
|
133
|
+
const columns = this.columns();
|
|
134
|
+
this.nodes().forEach((n) => {
|
|
135
|
+
const c = columns[n.id] ?? 0;
|
|
136
|
+
counts[c] = (counts[c] ?? 0) + 1;
|
|
137
|
+
});
|
|
138
|
+
const rows = Math.max(1, ...Object.values(counts));
|
|
139
|
+
return `${48 + rows * ROW_GAP}px`;
|
|
140
|
+
}, ...(ngDevMode ? [{ debugName: "resolvedHeight" }] : /* istanbul ignore next */ []));
|
|
141
|
+
kindTone(kind) {
|
|
142
|
+
return FX_CHAIN_KIND_TONE[kind] ?? 'information';
|
|
143
|
+
}
|
|
144
|
+
isActive(node) {
|
|
145
|
+
const active = this.activeId();
|
|
146
|
+
return active != null && active === node.id;
|
|
147
|
+
}
|
|
148
|
+
/** One hop from the selection: lit, but without the selected accent frame. */
|
|
149
|
+
isRelated(node) {
|
|
150
|
+
return !this.isActive(node) && this.relatedIds().has(node.id);
|
|
151
|
+
}
|
|
152
|
+
/** Nothing selected → every node reads at full strength. */
|
|
153
|
+
isDimmed(node) {
|
|
154
|
+
return this.activeId() != null && !this.isActive(node) && !this.isRelated(node);
|
|
155
|
+
}
|
|
156
|
+
/** An edge touching the selection is part of the step being read. */
|
|
157
|
+
isEdgeActive(edge) {
|
|
158
|
+
const active = this.activeId();
|
|
159
|
+
return active != null && (edge.source === active || edge.target === active);
|
|
160
|
+
}
|
|
161
|
+
isEdgeDimmed(edge) {
|
|
162
|
+
return this.activeId() != null && !this.isEdgeActive(edge);
|
|
163
|
+
}
|
|
164
|
+
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.6\"\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
|
+
}
|
|
167
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.20", ngImport: i0, type: FlowCanvasComponent, decorators: [{
|
|
168
|
+
type: Component,
|
|
169
|
+
args: [{ selector: 'fx-ui-flow-canvas', changeDetection: ChangeDetectionStrategy.OnPush, imports: [
|
|
170
|
+
NgClass,
|
|
171
|
+
VflowComponent,
|
|
172
|
+
NodeHtmlTemplateDirective,
|
|
173
|
+
EdgeTemplateDirective,
|
|
174
|
+
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.6\"\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"] }]
|
|
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"] }] } });
|
|
4
177
|
|
|
5
178
|
class FlowConnection {
|
|
6
179
|
nodes = input([], ...(ngDevMode ? [{ debugName: "nodes" }] : /* istanbul ignore next */ []));
|
|
@@ -34,5 +207,5 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.20", ngImpo
|
|
|
34
207
|
* Generated bundle index. Do not edit.
|
|
35
208
|
*/
|
|
36
209
|
|
|
37
|
-
export { FlowConnection };
|
|
210
|
+
export { FX_CHAIN_KIND_TONE, FlowCanvasComponent, FlowConnection };
|
|
38
211
|
//# sourceMappingURL=foxeltech-angular-ui-flow.mjs.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"foxeltech-angular-ui-flow.mjs","sources":["../../../projects/ui/flow/src/flow-connection/flow-connection.component.ts","../../../projects/ui/flow/src/flow-connection/flow-connection.component.html","../../../projects/ui/flow/src/foxeltech-angular-ui-flow.ts"],"sourcesContent":["import { Component, Input, ChangeDetectionStrategy, input } from '@angular/core';\nimport { Node, Edge, Vflow, Connection, ChangesControllerDirective, VflowComponent, ConnectionControllerDirective } from 'ngx-vflow';\n\n@Component({\n selector: 'fx-ui-flow-connection',\n templateUrl: './flow-connection.component.html',\n styleUrl: './flow-connection.component.scss',\n changeDetection: ChangeDetectionStrategy.OnPush,\n imports: [\n ChangesControllerDirective,\n VflowComponent,\n ConnectionControllerDirective,\n ],\n})\nexport class FlowConnection {\n readonly nodes = input<Node[]>([]);\n @Input() edges: Edge[] = [];\n readonly backgroundColor = input<any>('--bg-hover-primary');\n readonly view = input<any>(['100%', '400px']);\n\n handleConnection(connection: Connection) {\n this.edges = [\n ...this.edges,\n {\n id: `${connection.source} -> ${connection.target}`,\n ...connection,\n },\n ];\n }\n}\n","<vflow\n [background]=\"{\n type: 'solid',\n color: `rgba(var(${backgroundColor()})`\n}\"\n [nodes]=\"nodes()\"\n [edges]=\"edges\"\n (onConnect)=\"handleConnection($event)\"\n [view]=\"view()\"\n/>\n","/**\n * Generated bundle index. Do not edit.\n */\n\nexport * from './public-api';\n"],"names":[],"mappings":";;;;MAca,cAAc,CAAA;AAChB,IAAA,KAAK,GAAG,KAAK,CAAS,EAAE,4EAAC;IACzB,KAAK,GAAW,EAAE;AAClB,IAAA,eAAe,GAAG,KAAK,CAAM,oBAAoB,sFAAC;IAClD,IAAI,GAAG,KAAK,CAAM,CAAC,MAAM,EAAE,OAAO,CAAC,EAAA,IAAA,SAAA,GAAA,CAAA,EAAA,SAAA,EAAA,MAAA,EAAA,CAAA,8BAAA,EAAA,CAAA,CAAC;AAE7C,IAAA,gBAAgB,CAAC,UAAsB,EAAA;QACrC,IAAI,CAAC,KAAK,GAAG;YACX,GAAG,IAAI,CAAC,KAAK;AACb,YAAA;gBACE,EAAE,EAAE,GAAG,UAAU,CAAC,MAAM,CAAA,IAAA,EAAO,UAAU,CAAC,MAAM,CAAA,CAAE;AAClD,gBAAA,GAAG,UAAU;AACd,aAAA;SACF;IACH;wGAdW,cAAc,EAAA,IAAA,EAAA,EAAA,EAAA,MAAA,EAAA,EAAA,CAAA,eAAA,CAAA,SAAA,EAAA,CAAA;AAAd,IAAA,OAAA,IAAA,GAAA,EAAA,CAAA,oBAAA,CAAA,EAAA,UAAA,EAAA,QAAA,EAAA,OAAA,EAAA,SAAA,EAAA,IAAA,EAAA,cAAc,EAAA,YAAA,EAAA,IAAA,EAAA,QAAA,EAAA,uBAAA,EAAA,MAAA,EAAA,EAAA,KAAA,EAAA,EAAA,iBAAA,EAAA,OAAA,EAAA,UAAA,EAAA,OAAA,EAAA,QAAA,EAAA,IAAA,EAAA,UAAA,EAAA,KAAA,EAAA,iBAAA,EAAA,IAAA,EAAA,EAAA,KAAA,EAAA,EAAA,iBAAA,EAAA,OAAA,EAAA,UAAA,EAAA,OAAA,EAAA,QAAA,EAAA,KAAA,EAAA,UAAA,EAAA,KAAA,EAAA,iBAAA,EAAA,IAAA,EAAA,EAAA,eAAA,EAAA,EAAA,iBAAA,EAAA,iBAAA,EAAA,UAAA,EAAA,iBAAA,EAAA,QAAA,EAAA,IAAA,EAAA,UAAA,EAAA,KAAA,EAAA,iBAAA,EAAA,IAAA,EAAA,EAAA,IAAA,EAAA,EAAA,iBAAA,EAAA,MAAA,EAAA,UAAA,EAAA,MAAA,EAAA,QAAA,EAAA,IAAA,EAAA,UAAA,EAAA,KAAA,EAAA,iBAAA,EAAA,IAAA,EAAA,EAAA,EAAA,QAAA,EAAA,EAAA,EAAA,QAAA,ECd3B,iNAUA,EAAA,MAAA,EAAA,CAAA,EAAA,CAAA,EAAA,YAAA,EAAA,CAAA,EAAA,IAAA,EAAA,WAAA,EAAA,IAAA,EDAQ,cAAc,qTACd,6BAA6B,EAAA,QAAA,EAAA,oDAAA,EAAA,OAAA,EAAA,CAAA,WAAA,EAAA,SAAA,EAAA,aAAA,EAAA,WAAA,CAAA,EAAA,CAAA,EAAA,eAAA,EAAA,EAAA,CAAA,uBAAA,CAAA,MAAA,EAAA,CAAA;;4FAGxB,cAAc,EAAA,UAAA,EAAA,CAAA;kBAX1B,SAAS;AACI,YAAA,IAAA,EAAA,CAAA,EAAA,QAAA,EAAA,uBAAuB,EAAA,eAAA,EAGhB,uBAAuB,CAAC,MAAM,EAAA,OAAA,EACtC;wBACL,0BAA0B;wBAC1B,cAAc;wBACd,6BAA6B;AAChC,qBAAA,EAAA,QAAA,EAAA,iNAAA,EAAA;;sBAIF;;;AEhBH;;AAEG;;;;"}
|
|
1
|
+
{"version":3,"file":"foxeltech-angular-ui-flow.mjs","sources":["../../../projects/ui/flow/src/flow-canvas/flow-canvas.component.ts","../../../projects/ui/flow/src/flow-canvas/flow-canvas.component.html","../../../projects/ui/flow/src/flow-connection/flow-connection.component.ts","../../../projects/ui/flow/src/flow-connection/flow-connection.component.html","../../../projects/ui/flow/src/foxeltech-angular-ui-flow.ts"],"sourcesContent":["import {\n ChangeDetectionStrategy,\n Component,\n computed,\n input,\n output,\n} from '@angular/core';\nimport { NgClass } from '@angular/common';\nimport {\n Edge,\n EdgeTemplateDirective,\n HandleComponent,\n Node,\n NodeHtmlTemplateDirective,\n VflowComponent,\n} from 'ngx-vflow';\n\n/**\n * What a chain node represents. Structural kinds (`entry`, `convergence`,\n * `impact`, `stage`) can be derived from the graph itself; the validation kinds\n * (`mitigation`, `review`, `not-reproduced`) come from an analyst verdict.\n */\nexport type FxChainNodeKind =\n | 'entry'\n | 'convergence'\n | 'mitigation'\n | 'review'\n | 'not-reproduced'\n | 'impact'\n | 'stage';\n\nexport interface FxChainNode {\n id: string;\n /** Node title — rendered in the figure/mono face. */\n label: string;\n kind: FxChainNodeKind;\n /** Caller-translated kind eyebrow; falls back to the raw kind key. */\n kindLabel?: string;\n /** Caller-translated muted subtitle. */\n caption?: string;\n /** true = verified badge, false = unverified badge, null/undefined = no badge. */\n verified?: boolean | null;\n /** Explicit column (0 = leftmost); omit to derive depth from the edges. */\n column?: number;\n /** Explicit row inside the column; omit to stack in declaration order. */\n row?: number;\n}\n\nexport interface FxChainEdge {\n source: string;\n target: string;\n}\n\n/** Kind → severity token. Exported so callers can tint matching chips (the\n stage list beside the canvas) from the same source of truth. */\nexport const FX_CHAIN_KIND_TONE: Record<FxChainNodeKind, string> = {\n entry: 'warning',\n convergence: 'information',\n mitigation: 'success',\n review: 'warning',\n 'not-reproduced': 'danger',\n impact: 'critical',\n stage: 'information',\n};\n\nconst COLUMN_GAP = 216;\nconst ROW_GAP = 104;\nconst NODE_WIDTH = 176;\nconst NODE_HEIGHT = 66;\n\n/**\n * V2 exploit-chain canvas — the attack-path graph of design refs 04..07:\n * kind-tinted node cards laid out left→right, curved edges, draggable nodes on\n * a pannable/zoomable surface.\n *\n * Presentational: it takes a graph plus the currently selected node and emits\n * clicks. Layout is derived from the edges (longest path from a source) unless\n * a node pins its own column/row, so callers can hand over a plain chain.\n *\n * <fx-ui-flow-canvas [nodes]=\"chainNodes\" [edges]=\"chainEdges\"\n * [activeId]=\"stageId()\" (nodeClick)=\"selectStage($event)\" />\n */\n@Component({\n selector: 'fx-ui-flow-canvas',\n templateUrl: './flow-canvas.component.html',\n styleUrl: './flow-canvas.component.scss',\n changeDetection: ChangeDetectionStrategy.OnPush,\n imports: [\n NgClass,\n VflowComponent,\n NodeHtmlTemplateDirective,\n EdgeTemplateDirective,\n HandleComponent,\n ],\n})\nexport class FlowCanvasComponent {\n readonly nodes = input<FxChainNode[]>([]);\n readonly edges = input<FxChainEdge[]>([]);\n /** Selected/current node: full opacity + accent border; the rest dim. */\n readonly activeId = input<string | null>(null);\n /** Explicit canvas height; omit to size it from the number of stacked rows. */\n readonly height = input('');\n /** Caller-translated hint shown when the graph is empty. */\n readonly emptyText = input('No chain data available');\n\n readonly nodeClick = output<string>();\n\n /** Column index per node: pinned value, else longest path from a source. */\n private readonly columns = computed<Record<string, number>>(() => {\n const nodes = this.nodes();\n const edges = this.edges();\n const incoming = new Map<string, string[]>();\n nodes.forEach((n) => incoming.set(n.id, []));\n edges.forEach((e) => incoming.get(e.target)?.push(e.source));\n\n const depth: Record<string, number> = {};\n const resolve = (id: string, seen: Set<string>): number => {\n if (depth[id] !== undefined) return depth[id];\n // Cycle guard: a malformed graph must not blow the stack.\n if (seen.has(id)) return 0;\n seen.add(id);\n const parents = incoming.get(id) ?? [];\n const value = parents.length\n ? Math.max(...parents.map((p) => resolve(p, seen))) + 1\n : 0;\n depth[id] = value;\n return value;\n };\n nodes.forEach((n) => {\n depth[n.id] = n.column ?? resolve(n.id, new Set());\n });\n return depth;\n });\n\n /** ngx-vflow nodes: html-template cards positioned by the derived layout. */\n readonly flowNodes = computed<Node[]>(() => {\n const columns = this.columns();\n const perColumn: Record<number, number> = {};\n // Tallest column decides the vertical centre every column is balanced on.\n const counts: Record<number, number> = {};\n this.nodes().forEach((n) => {\n const c = columns[n.id] ?? 0;\n counts[c] = (counts[c] ?? 0) + 1;\n });\n const tallest = Math.max(1, ...Object.values(counts));\n\n return this.nodes().map((node) => {\n const column = columns[node.id] ?? 0;\n const row = node.row ?? perColumn[column] ?? 0;\n perColumn[column] = row + 1;\n const rows = counts[column] ?? 1;\n const offset = ((tallest - rows) * ROW_GAP) / 2;\n return {\n id: node.id,\n type: 'html-template' as const,\n point: { x: 24 + column * COLUMN_GAP, y: 24 + offset + row * ROW_GAP },\n width: NODE_WIDTH,\n height: NODE_HEIGHT,\n data: node,\n };\n });\n });\n\n /**\n * Edges stay identity-stable across selections: state lives in the template\n * (read off `activeId`), so selecting a stage never re-creates them.\n */\n readonly flowEdges = computed<Edge[]>(() =>\n this.edges().map((e) => ({\n id: `${e.source}->${e.target}`,\n source: e.source,\n target: e.target,\n type: 'template' as const,\n curve: 'bezier' as const,\n markers: { end: { type: 'arrow-closed' as const, width: 11, height: 11 } },\n })),\n );\n\n /** Nodes one hop from the selection — they stay lit alongside it. */\n private readonly relatedIds = computed<Set<string>>(() => {\n const active = this.activeId();\n const related = new Set<string>();\n if (!active) return related;\n this.edges().forEach((e) => {\n if (e.source === active) related.add(e.target);\n if (e.target === active) related.add(e.source);\n });\n return related;\n });\n\n readonly isEmpty = computed(() => this.nodes().length === 0);\n\n /**\n * A linear chain needs one row, the design's converging entries need three —\n * sizing from the layout keeps the card from leaving a tall empty band.\n */\n readonly resolvedHeight = computed(() => {\n const explicit = this.height();\n if (explicit) return explicit;\n const counts: Record<number, number> = {};\n const columns = this.columns();\n this.nodes().forEach((n) => {\n const c = columns[n.id] ?? 0;\n counts[c] = (counts[c] ?? 0) + 1;\n });\n const rows = Math.max(1, ...Object.values(counts));\n return `${48 + rows * ROW_GAP}px`;\n });\n\n kindTone(kind: FxChainNodeKind): string {\n return FX_CHAIN_KIND_TONE[kind] ?? 'information';\n }\n\n isActive(node: FxChainNode): boolean {\n const active = this.activeId();\n return active != null && active === node.id;\n }\n\n /** One hop from the selection: lit, but without the selected accent frame. */\n isRelated(node: FxChainNode): boolean {\n return !this.isActive(node) && this.relatedIds().has(node.id);\n }\n\n /** Nothing selected → every node reads at full strength. */\n isDimmed(node: FxChainNode): boolean {\n return this.activeId() != null && !this.isActive(node) && !this.isRelated(node);\n }\n\n /** An edge touching the selection is part of the step being read. */\n isEdgeActive(edge: Edge): boolean {\n const active = this.activeId();\n return active != null && (edge.source === active || edge.target === active);\n }\n\n isEdgeDimmed(edge: Edge): boolean {\n return this.activeId() != null && !this.isEdgeActive(edge);\n }\n}\n","<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.6\"\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 ? '✓' : '○' }}\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","import { Component, Input, ChangeDetectionStrategy, input } from '@angular/core';\nimport { Node, Edge, Vflow, Connection, ChangesControllerDirective, VflowComponent, ConnectionControllerDirective } from 'ngx-vflow';\n\n@Component({\n selector: 'fx-ui-flow-connection',\n templateUrl: './flow-connection.component.html',\n styleUrl: './flow-connection.component.scss',\n changeDetection: ChangeDetectionStrategy.OnPush,\n imports: [\n ChangesControllerDirective,\n VflowComponent,\n ConnectionControllerDirective,\n ],\n})\nexport class FlowConnection {\n readonly nodes = input<Node[]>([]);\n @Input() edges: Edge[] = [];\n readonly backgroundColor = input<any>('--bg-hover-primary');\n readonly view = input<any>(['100%', '400px']);\n\n handleConnection(connection: Connection) {\n this.edges = [\n ...this.edges,\n {\n id: `${connection.source} -> ${connection.target}`,\n ...connection,\n },\n ];\n }\n}\n","<vflow\n [background]=\"{\n type: 'solid',\n color: `rgba(var(${backgroundColor()})`\n}\"\n [nodes]=\"nodes()\"\n [edges]=\"edges\"\n (onConnect)=\"handleConnection($event)\"\n [view]=\"view()\"\n/>\n","/**\n * Generated bundle index. Do not edit.\n */\n\nexport * from './public-api';\n"],"names":[],"mappings":"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"}
|
|
@@ -138,11 +138,11 @@ class RichTextAreaComponent extends FxComponent {
|
|
|
138
138
|
}
|
|
139
139
|
}
|
|
140
140
|
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.20", ngImport: i0, type: RichTextAreaComponent, deps: [{ token: QuillStyleLoaderService }, { token: PLATFORM_ID }], target: i0.ɵɵFactoryTarget.Component });
|
|
141
|
-
static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.2.0", version: "21.2.20", type: RichTextAreaComponent, isStandalone: true, selector: "fx-ui-rich-text-area", inputs: { placeholder: { classPropertyName: "placeholder", publicName: "placeholder", isSignal: true, isRequired: false, transformFunction: null }, toolbarOptions: { classPropertyName: "toolbarOptions", publicName: "toolbarOptions", isSignal: true, isRequired: false, transformFunction: null } }, outputs: { contentChange: "contentChange" }, viewQueries: [{ propertyName: "editorContainer", first: true, predicate: ["editorContainer"], descendants: true, isSignal: true }], usesInheritance: true, ngImport: i0, template: "<div class=\"w-full rounded-
|
|
141
|
+
static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.2.0", version: "21.2.20", type: RichTextAreaComponent, isStandalone: true, selector: "fx-ui-rich-text-area", inputs: { placeholder: { classPropertyName: "placeholder", publicName: "placeholder", isSignal: true, isRequired: false, transformFunction: null }, toolbarOptions: { classPropertyName: "toolbarOptions", publicName: "toolbarOptions", isSignal: true, isRequired: false, transformFunction: null } }, outputs: { contentChange: "contentChange" }, viewQueries: [{ propertyName: "editorContainer", first: true, predicate: ["editorContainer"], descendants: true, isSignal: true }], usesInheritance: true, ngImport: i0, template: "<div class=\"w-full rounded-[var(--og-radius-card)] border border-border-default shadow-sm p-1 bg-bg-primary\">\n <div #editorContainer class=\"min-h-[200px] text-base\"></div>\n</div>", styles: ["@charset \"UTF-8\";:host{display:block}:host ::ng-deep .ql-toolbar.ql-snow{border:none;border-bottom:1px solid rgb(var(--og-border));border-radius:var(--og-radius-card) var(--og-radius-card) 0 0;padding:.5rem;font-family:var(--og-font-body)}:host ::ng-deep .ql-container.ql-snow{border:none;border-radius:0 0 var(--og-radius-card) var(--og-radius-card);font-family:var(--og-font-body)}:host ::ng-deep .ql-editor{min-height:200px;padding:.75rem;font-size:1rem;color:rgb(var(--og-text))}:host ::ng-deep .ql-editor.ql-blank:before{color:rgb(var(--og-text-faint));font-style:normal}:host ::ng-deep .ql-snow .ql-stroke{stroke:rgb(var(--og-text-muted))}:host ::ng-deep .ql-snow .ql-fill,:host ::ng-deep .ql-snow .ql-stroke.ql-fill{fill:rgb(var(--og-text-muted))}:host ::ng-deep .ql-snow .ql-picker{color:rgb(var(--og-text-muted))}:host ::ng-deep .ql-snow .ql-picker-options{background:rgb(var(--og-surface-raised));border-color:rgb(var(--og-border))}:host ::ng-deep .ql-snow .ql-picker-item{color:rgb(var(--og-text-body))}:host ::ng-deep .ql-snow.ql-toolbar button:hover .ql-stroke,:host ::ng-deep .ql-snow.ql-toolbar button.ql-active .ql-stroke,:host ::ng-deep .ql-snow.ql-toolbar .ql-picker-label:hover .ql-stroke{stroke:rgb(var(--og-accent))}:host ::ng-deep .ql-snow.ql-toolbar button:hover .ql-fill,:host ::ng-deep .ql-snow.ql-toolbar button.ql-active .ql-fill{fill:rgb(var(--og-accent))}:host ::ng-deep .ql-snow.ql-toolbar button:hover,:host ::ng-deep .ql-snow.ql-toolbar button.ql-active,:host ::ng-deep .ql-snow .ql-picker-label:hover,:host ::ng-deep .ql-snow .ql-picker-label.ql-active{color:rgb(var(--og-accent))}\n/*! tailwindcss v4.3.3 | MIT License | https://tailwindcss.com */\n"], changeDetection: i0.ChangeDetectionStrategy.OnPush });
|
|
142
142
|
}
|
|
143
143
|
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.20", ngImport: i0, type: RichTextAreaComponent, decorators: [{
|
|
144
144
|
type: Component,
|
|
145
|
-
args: [{ selector: 'fx-ui-rich-text-area', changeDetection: ChangeDetectionStrategy.OnPush, template: "<div class=\"w-full rounded-
|
|
145
|
+
args: [{ selector: 'fx-ui-rich-text-area', changeDetection: ChangeDetectionStrategy.OnPush, template: "<div class=\"w-full rounded-[var(--og-radius-card)] border border-border-default shadow-sm p-1 bg-bg-primary\">\n <div #editorContainer class=\"min-h-[200px] text-base\"></div>\n</div>", styles: ["@charset \"UTF-8\";:host{display:block}:host ::ng-deep .ql-toolbar.ql-snow{border:none;border-bottom:1px solid rgb(var(--og-border));border-radius:var(--og-radius-card) var(--og-radius-card) 0 0;padding:.5rem;font-family:var(--og-font-body)}:host ::ng-deep .ql-container.ql-snow{border:none;border-radius:0 0 var(--og-radius-card) var(--og-radius-card);font-family:var(--og-font-body)}:host ::ng-deep .ql-editor{min-height:200px;padding:.75rem;font-size:1rem;color:rgb(var(--og-text))}:host ::ng-deep .ql-editor.ql-blank:before{color:rgb(var(--og-text-faint));font-style:normal}:host ::ng-deep .ql-snow .ql-stroke{stroke:rgb(var(--og-text-muted))}:host ::ng-deep .ql-snow .ql-fill,:host ::ng-deep .ql-snow .ql-stroke.ql-fill{fill:rgb(var(--og-text-muted))}:host ::ng-deep .ql-snow .ql-picker{color:rgb(var(--og-text-muted))}:host ::ng-deep .ql-snow .ql-picker-options{background:rgb(var(--og-surface-raised));border-color:rgb(var(--og-border))}:host ::ng-deep .ql-snow .ql-picker-item{color:rgb(var(--og-text-body))}:host ::ng-deep .ql-snow.ql-toolbar button:hover .ql-stroke,:host ::ng-deep .ql-snow.ql-toolbar button.ql-active .ql-stroke,:host ::ng-deep .ql-snow.ql-toolbar .ql-picker-label:hover .ql-stroke{stroke:rgb(var(--og-accent))}:host ::ng-deep .ql-snow.ql-toolbar button:hover .ql-fill,:host ::ng-deep .ql-snow.ql-toolbar button.ql-active .ql-fill{fill:rgb(var(--og-accent))}:host ::ng-deep .ql-snow.ql-toolbar button:hover,:host ::ng-deep .ql-snow.ql-toolbar button.ql-active,:host ::ng-deep .ql-snow .ql-picker-label:hover,:host ::ng-deep .ql-snow .ql-picker-label.ql-active{color:rgb(var(--og-accent))}\n/*! tailwindcss v4.3.3 | MIT License | https://tailwindcss.com */\n"] }]
|
|
146
146
|
}], ctorParameters: () => [{ type: QuillStyleLoaderService }, { type: undefined, decorators: [{
|
|
147
147
|
type: Inject,
|
|
148
148
|
args: [PLATFORM_ID]
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"foxeltech-angular-ui-rich-text.mjs","sources":["../../../projects/ui/rich-text/src/quill-style-loader.service.ts","../../../projects/ui/rich-text/src/rich-text-area/rich-text-area.component.ts","../../../projects/ui/rich-text/src/rich-text-area/rich-text-area.component.html","../../../projects/ui/rich-text/src/foxeltech-angular-ui-rich-text.ts"],"sourcesContent":["import { Inject, Injectable, PLATFORM_ID } from '@angular/core';\nimport { isPlatformBrowser } from '@angular/common';\n\n@Injectable({ providedIn: 'root' })\nexport class QuillStyleLoaderService {\n private loaded = false;\n private loadingPromise: Promise<void> | null = null;\n\n constructor(@Inject(PLATFORM_ID) private platformId: object) {}\n\n /**\n * Load Quill CSS (only in browser). Returns a promise that resolves when\n * the CSS links have been appended.\n */\n load(): Promise<void> {\n if (!isPlatformBrowser(this.platformId)) {\n // Server: do nothing and resolve immediately.\n return Promise.resolve();\n }\n\n if (this.loaded) return Promise.resolve();\n if (this.loadingPromise) return this.loadingPromise;\n\n this.loadingPromise = new Promise<void>((resolve) => {\n const cssUrls = [\n // Using CDN is simplest — no consumer angular.json edits needed.\n 'https://cdn.jsdelivr.net/npm/quill/dist/quill.core.css',\n 'https://cdn.jsdelivr.net/npm/quill/dist/quill.snow.css'\n ];\n\n let remaining = cssUrls.length;\n\n const onLoad = () => {\n remaining -= 1;\n if (remaining === 0) {\n this.loaded = true;\n resolve();\n }\n };\n\n cssUrls.forEach((href) => {\n // Do not add duplicate links\n if (document.querySelector(`link[href=\"${href}\"]`)) {\n onLoad();\n return;\n }\n\n const link = document.createElement('link');\n link.rel = 'stylesheet';\n link.href = href;\n link.onload = () => onLoad();\n link.onerror = () => {\n // still count it as loaded to avoid hanging if CDN fails\n console.warn(`[QuillStyleLoader] failed to load: ${href}`);\n onLoad();\n };\n document.head.appendChild(link);\n });\n });\n\n return this.loadingPromise;\n }\n}\n","import {\n AfterViewInit,\n ChangeDetectorRef,\n Component,\n ElementRef,\n Inject,\n PLATFORM_ID,\n ChangeDetectionStrategy,\n input,\n output,\n viewChild\n} from '@angular/core';\nimport { FxComponent, FxUtils } from '@foxeltech/angular-ui';\nimport { QuillStyleLoaderService } from '../quill-style-loader.service';\nimport { isPlatformBrowser } from '@angular/common';\n\n\n@Component({\n selector: 'fx-ui-rich-text-area',\n templateUrl: './rich-text-area.component.html',\n styleUrl: './rich-text-area.component.scss',\n changeDetection: ChangeDetectionStrategy.OnPush,\n})\nexport class RichTextAreaComponent extends FxComponent<any> implements AfterViewInit {\n readonly editorContainer = viewChild.required<ElementRef<HTMLDivElement>>('editorContainer');\n\n readonly placeholder = input('Write something...');\n\n readonly toolbarOptions = input<any>([\n // ['undo', 'redo'],\n [{ 'header': [1, 2, 3, 4, 5, 6, false] }],\n [{ 'font': [] }],\n [{ 'size': ['small', false, 'large', 'huge'] }],\n [{ 'align': [] }],\n [{ 'color': [] }, { 'background': [] }],\n ['bold', 'italic', 'underline', 'strike'],\n ['blockquote', 'code-block'],\n [{ 'list': 'ordered' }, { 'list': 'bullet' }],\n [{ 'indent': '-1' }, { 'indent': '+1' }],\n ['link', 'image'],\n ['clean']\n]);\n\n readonly contentChange = output<string>();\n\n private quillInstance: any;\n\n constructor(\n private styleLoader: QuillStyleLoaderService,\n @Inject(PLATFORM_ID) private platformId: object\n ) {\n super();\n }\n\n async ngAfterViewInit(): Promise<void> {\n if (!isPlatformBrowser(this.platformId)) return;\n\n await this.styleLoader.load();\n\n const QuillModule = await import('quill');\n const Quill = (QuillModule as any).default || QuillModule;\n\n const icons = Quill.import('ui/icons');\n // icons['undo'] = `<svg viewBox=\"0 0 18 18\"><path d=\"M6.4 5.2H3L6.8 1l3.8 4.2H7.9C10.2 5.4 12 7.4 12 9.8c0 2.7-2.2 4.9-4.9 4.9S2.2 12.5 2.2 9.8H0c0 3.8 3.1 6.9 6.9 6.9s6.9-3.1 6.9-6.9S10.7 3 7 3v2.2z\"></path></svg>`;\n // icons['redo'] = `<svg viewBox=\"0 0 18 18\"><path d=\"M11.6 5.2H15L11.2 1 7.4 5.2h2.7C7.8 5.4 6 7.4 6 9.8c0 2.7 2.2 4.9 4.9 4.9s4.9-2.2 4.9-4.9H18c0 3.8-3.1 6.9-6.9 6.9S4.2 13.6 4.2 9.8 7.3 3 11 3v2.2z\"></path></svg>`;\n\n this.quillInstance = new Quill(this.editorContainer().nativeElement, {\n theme: 'snow',\n placeholder: this.placeholder(),\n modules: {\n history: true,\n toolbar: this.toolbarOptions(),\n }\n });\n this.quillInstance.root.style.color = FxUtils.convertColorFromVariable('--text-primary')\n\n const toolbar = this.quillInstance.getModule('toolbar');\n toolbar.addHandler('undo', () => this.quillInstance.history.undo());\n toolbar.addHandler('redo', () => this.quillInstance.history.redo());\n\n if (this.value) {\n this.quillInstance.root.innerHTML = this.value;\n }\n\n this.quillInstance.on('text-change', () => {\n const html = this.quillInstance.root.innerHTML || '';\n this.value = html;\n this.onChange(html);\n this.contentChange.emit(html);\n });\n }\n\n override writeValue(value: any): void {\n this.value = value || '';\n if (this.quillInstance) {\n this.quillInstance.root.innerHTML = this.value;\n }\n }\n\n override setDisabledState(isDisabled: boolean): void {\n this.disabled = isDisabled;\n if (this.quillInstance) {\n this.quillInstance.enable(!isDisabled);\n }\n }\n}\n","<div class=\"w-full rounded-2xl shadow-sm p-1 bg-bg-primary\">\n <div #editorContainer class=\"min-h-[200px] text-base\"></div>\n</div>","/**\n * Generated bundle index. Do not edit.\n */\n\nexport * from './public-api';\n"],"names":[],"mappings":";;;;;MAIa,uBAAuB,CAAA;AAIO,IAAA,UAAA;IAHjC,MAAM,GAAG,KAAK;IACd,cAAc,GAAyB,IAAI;AAEnD,IAAA,WAAA,CAAyC,UAAkB,EAAA;QAAlB,IAAA,CAAA,UAAU,GAAV,UAAU;IAAW;AAE9D;;;AAGG;IACH,IAAI,GAAA;QACF,IAAI,CAAC,iBAAiB,CAAC,IAAI,CAAC,UAAU,CAAC,EAAE;;AAEvC,YAAA,OAAO,OAAO,CAAC,OAAO,EAAE;QAC1B;QAEA,IAAI,IAAI,CAAC,MAAM;AAAE,YAAA,OAAO,OAAO,CAAC,OAAO,EAAE;QACzC,IAAI,IAAI,CAAC,cAAc;YAAE,OAAO,IAAI,CAAC,cAAc;QAEnD,IAAI,CAAC,cAAc,GAAG,IAAI,OAAO,CAAO,CAAC,OAAO,KAAI;AAClD,YAAA,MAAM,OAAO,GAAG;;gBAEd,wDAAwD;gBACxD;aACD;AAED,YAAA,IAAI,SAAS,GAAG,OAAO,CAAC,MAAM;YAE9B,MAAM,MAAM,GAAG,MAAK;gBAClB,SAAS,IAAI,CAAC;AACd,gBAAA,IAAI,SAAS,KAAK,CAAC,EAAE;AACnB,oBAAA,IAAI,CAAC,MAAM,GAAG,IAAI;AAClB,oBAAA,OAAO,EAAE;gBACX;AACF,YAAA,CAAC;AAED,YAAA,OAAO,CAAC,OAAO,CAAC,CAAC,IAAI,KAAI;;gBAEvB,IAAI,QAAQ,CAAC,aAAa,CAAC,cAAc,IAAI,CAAA,EAAA,CAAI,CAAC,EAAE;AAClD,oBAAA,MAAM,EAAE;oBACR;gBACF;gBAEA,MAAM,IAAI,GAAG,QAAQ,CAAC,aAAa,CAAC,MAAM,CAAC;AAC3C,gBAAA,IAAI,CAAC,GAAG,GAAG,YAAY;AACvB,gBAAA,IAAI,CAAC,IAAI,GAAG,IAAI;gBAChB,IAAI,CAAC,MAAM,GAAG,MAAM,MAAM,EAAE;AAC5B,gBAAA,IAAI,CAAC,OAAO,GAAG,MAAK;;AAElB,oBAAA,OAAO,CAAC,IAAI,CAAC,sCAAsC,IAAI,CAAA,CAAE,CAAC;AAC1D,oBAAA,MAAM,EAAE;AACV,gBAAA,CAAC;AACD,gBAAA,QAAQ,CAAC,IAAI,CAAC,WAAW,CAAC,IAAI,CAAC;AACjC,YAAA,CAAC,CAAC;AACJ,QAAA,CAAC,CAAC;QAEF,OAAO,IAAI,CAAC,cAAc;IAC5B;AAzDW,IAAA,OAAA,IAAA,GAAA,EAAA,CAAA,kBAAA,CAAA,EAAA,UAAA,EAAA,QAAA,EAAA,OAAA,EAAA,SAAA,EAAA,QAAA,EAAA,EAAA,EAAA,IAAA,EAAA,uBAAuB,kBAId,WAAW,EAAA,CAAA,EAAA,MAAA,EAAA,EAAA,CAAA,eAAA,CAAA,UAAA,EAAA,CAAA;AAJpB,IAAA,OAAA,KAAA,GAAA,EAAA,CAAA,qBAAA,CAAA,EAAA,UAAA,EAAA,QAAA,EAAA,OAAA,EAAA,SAAA,EAAA,QAAA,EAAA,EAAA,EAAA,IAAA,EAAA,uBAAuB,cADV,MAAM,EAAA,CAAA;;4FACnB,uBAAuB,EAAA,UAAA,EAAA,CAAA;kBADnC,UAAU;mBAAC,EAAE,UAAU,EAAE,MAAM,EAAE;;0BAKnB,MAAM;2BAAC,WAAW;;;ACe3B,MAAO,qBAAsB,SAAQ,WAAgB,CAAA;AAyB/C,IAAA,WAAA;AACqB,IAAA,UAAA;AAzBtB,IAAA,eAAe,GAAG,SAAS,CAAC,QAAQ,CAA6B,iBAAiB,CAAC;AAEnF,IAAA,WAAW,GAAG,KAAK,CAAC,oBAAoB,kFAAC;IAEzC,cAAc,GAAG,KAAK,CAAM;;AAEnC,QAAA,CAAC,EAAE,QAAQ,EAAE,CAAC,CAAC,EAAE,CAAC,EAAE,CAAC,EAAE,CAAC,EAAE,CAAC,EAAE,CAAC,EAAE,KAAK,CAAC,EAAE,CAAC;AACzC,QAAA,CAAC,EAAE,MAAM,EAAE,EAAE,EAAE,CAAC;AAChB,QAAA,CAAC,EAAE,MAAM,EAAE,CAAC,OAAO,EAAE,KAAK,EAAE,OAAO,EAAE,MAAM,CAAC,EAAE,CAAC;AAC/C,QAAA,CAAC,EAAE,OAAO,EAAE,EAAE,EAAE,CAAC;QACjB,CAAC,EAAE,OAAO,EAAE,EAAE,EAAE,EAAE,EAAE,YAAY,EAAE,EAAE,EAAE,CAAC;AACvC,QAAA,CAAC,MAAM,EAAE,QAAQ,EAAE,WAAW,EAAE,QAAQ,CAAC;QACzC,CAAC,YAAY,EAAE,YAAY,CAAC;QAC5B,CAAC,EAAE,MAAM,EAAE,SAAS,EAAE,EAAE,EAAE,MAAM,EAAE,QAAQ,EAAE,CAAC;QAC7C,CAAC,EAAE,QAAQ,EAAE,IAAI,EAAE,EAAE,EAAE,QAAQ,EAAE,IAAI,EAAE,CAAC;QACxC,CAAC,MAAM,EAAE,OAAO,CAAC;AACjB,QAAA,CAAC,OAAO;AACX,KAAA,EAAA,IAAA,SAAA,GAAA,CAAA,EAAA,SAAA,EAAA,gBAAA,EAAA,CAAA,8BAAA,EAAA,CAAA,CAAC;IAES,aAAa,GAAG,MAAM,EAAU;AAEjC,IAAA,aAAa;IAErB,WAAA,CACU,WAAoC,EACf,UAAkB,EAAA;AAE/C,QAAA,KAAK,EAAE;QAHC,IAAA,CAAA,WAAW,GAAX,WAAW;QACU,IAAA,CAAA,UAAU,GAAV,UAAU;IAGzC;AAEA,IAAA,MAAM,eAAe,GAAA;AACnB,QAAA,IAAI,CAAC,iBAAiB,CAAC,IAAI,CAAC,UAAU,CAAC;YAAE;AAEzC,QAAA,MAAM,IAAI,CAAC,WAAW,CAAC,IAAI,EAAE;AAE7B,QAAA,MAAM,WAAW,GAAG,MAAM,OAAO,OAAO,CAAC;AACzC,QAAA,MAAM,KAAK,GAAI,WAAmB,CAAC,OAAO,IAAI,WAAW;QAEzD,MAAM,KAAK,GAAG,KAAK,CAAC,MAAM,CAAC,UAAU,CAAC;;;AAItC,QAAA,IAAI,CAAC,aAAa,GAAG,IAAI,KAAK,CAAC,IAAI,CAAC,eAAe,EAAE,CAAC,aAAa,EAAE;AACnE,YAAA,KAAK,EAAE,MAAM;AACb,YAAA,WAAW,EAAE,IAAI,CAAC,WAAW,EAAE;AAC/B,YAAA,OAAO,EAAE;AACP,gBAAA,OAAO,EAAE,IAAI;AACb,gBAAA,OAAO,EAAE,IAAI,CAAC,cAAc,EAAE;AAC/B;AACF,SAAA,CAAC;AACF,QAAA,IAAI,CAAC,aAAa,CAAC,IAAI,CAAC,KAAK,CAAC,KAAK,GAAG,OAAO,CAAC,wBAAwB,CAAC,gBAAgB,CAAC;QAExF,MAAM,OAAO,GAAG,IAAI,CAAC,aAAa,CAAC,SAAS,CAAC,SAAS,CAAC;AACvD,QAAA,OAAO,CAAC,UAAU,CAAC,MAAM,EAAE,MAAM,IAAI,CAAC,aAAa,CAAC,OAAO,CAAC,IAAI,EAAE,CAAC;AACnE,QAAA,OAAO,CAAC,UAAU,CAAC,MAAM,EAAE,MAAM,IAAI,CAAC,aAAa,CAAC,OAAO,CAAC,IAAI,EAAE,CAAC;AAEnE,QAAA,IAAI,IAAI,CAAC,KAAK,EAAE;YACd,IAAI,CAAC,aAAa,CAAC,IAAI,CAAC,SAAS,GAAG,IAAI,CAAC,KAAK;QAChD;QAEA,IAAI,CAAC,aAAa,CAAC,EAAE,CAAC,aAAa,EAAE,MAAK;YACxC,MAAM,IAAI,GAAG,IAAI,CAAC,aAAa,CAAC,IAAI,CAAC,SAAS,IAAI,EAAE;AACpD,YAAA,IAAI,CAAC,KAAK,GAAG,IAAI;AACjB,YAAA,IAAI,CAAC,QAAQ,CAAC,IAAI,CAAC;AACnB,YAAA,IAAI,CAAC,aAAa,CAAC,IAAI,CAAC,IAAI,CAAC;AAC/B,QAAA,CAAC,CAAC;IACJ;AAES,IAAA,UAAU,CAAC,KAAU,EAAA;AAC5B,QAAA,IAAI,CAAC,KAAK,GAAG,KAAK,IAAI,EAAE;AACxB,QAAA,IAAI,IAAI,CAAC,aAAa,EAAE;YACtB,IAAI,CAAC,aAAa,CAAC,IAAI,CAAC,SAAS,GAAG,IAAI,CAAC,KAAK;QAChD;IACF;AAES,IAAA,gBAAgB,CAAC,UAAmB,EAAA;AAC3C,QAAA,IAAI,CAAC,QAAQ,GAAG,UAAU;AAC1B,QAAA,IAAI,IAAI,CAAC,aAAa,EAAE;YACtB,IAAI,CAAC,aAAa,CAAC,MAAM,CAAC,CAAC,UAAU,CAAC;QACxC;IACF;AAjFW,IAAA,OAAA,IAAA,GAAA,EAAA,CAAA,kBAAA,CAAA,EAAA,UAAA,EAAA,QAAA,EAAA,OAAA,EAAA,SAAA,EAAA,QAAA,EAAA,EAAA,EAAA,IAAA,EAAA,qBAAqB,sDA0BtB,WAAW,EAAA,CAAA,EAAA,MAAA,EAAA,EAAA,CAAA,eAAA,CAAA,SAAA,EAAA,CAAA;AA1BV,IAAA,OAAA,IAAA,GAAA,EAAA,CAAA,oBAAA,CAAA,EAAA,UAAA,EAAA,QAAA,EAAA,OAAA,EAAA,SAAA,EAAA,IAAA,EAAA,qBAAqB,ikBCvBlC,0IAEM,EAAA,MAAA,EAAA,CAAA,q2BAAA,CAAA,EAAA,eAAA,EAAA,EAAA,CAAA,uBAAA,CAAA,MAAA,EAAA,CAAA;;4FDqBO,qBAAqB,EAAA,UAAA,EAAA,CAAA;kBANjC,SAAS;+BACI,sBAAsB,EAAA,eAAA,EAGf,uBAAuB,CAAC,MAAM,EAAA,QAAA,EAAA,0IAAA,EAAA,MAAA,EAAA,CAAA,q2BAAA,CAAA,EAAA;;0BA4B9C,MAAM;2BAAC,WAAW;wFAzBqD,iBAAiB,EAAA,EAAA,QAAA,EAAA,IAAA,EAAA,CAAA,EAAA,CAAA,EAAA,WAAA,EAAA,CAAA,EAAA,IAAA,EAAA,EAAA,CAAA,KAAA,EAAA,IAAA,EAAA,CAAA,EAAA,QAAA,EAAA,IAAA,EAAA,KAAA,EAAA,aAAA,EAAA,QAAA,EAAA,KAAA,EAAA,CAAA,EAAA,CAAA,EAAA,cAAA,EAAA,CAAA,EAAA,IAAA,EAAA,EAAA,CAAA,KAAA,EAAA,IAAA,EAAA,CAAA,EAAA,QAAA,EAAA,IAAA,EAAA,KAAA,EAAA,gBAAA,EAAA,QAAA,EAAA,KAAA,EAAA,CAAA,EAAA,CAAA,EAAA,aAAA,EAAA,CAAA,EAAA,IAAA,EAAA,EAAA,CAAA,MAAA,EAAA,IAAA,EAAA,CAAA,eAAA,CAAA,EAAA,CAAA,EAAA,EAAA,CAAA;;AExB7F;;AAEG;;;;"}
|
|
1
|
+
{"version":3,"file":"foxeltech-angular-ui-rich-text.mjs","sources":["../../../projects/ui/rich-text/src/quill-style-loader.service.ts","../../../projects/ui/rich-text/src/rich-text-area/rich-text-area.component.ts","../../../projects/ui/rich-text/src/rich-text-area/rich-text-area.component.html","../../../projects/ui/rich-text/src/foxeltech-angular-ui-rich-text.ts"],"sourcesContent":["import { Inject, Injectable, PLATFORM_ID } from '@angular/core';\nimport { isPlatformBrowser } from '@angular/common';\n\n@Injectable({ providedIn: 'root' })\nexport class QuillStyleLoaderService {\n private loaded = false;\n private loadingPromise: Promise<void> | null = null;\n\n constructor(@Inject(PLATFORM_ID) private platformId: object) {}\n\n /**\n * Load Quill CSS (only in browser). Returns a promise that resolves when\n * the CSS links have been appended.\n */\n load(): Promise<void> {\n if (!isPlatformBrowser(this.platformId)) {\n // Server: do nothing and resolve immediately.\n return Promise.resolve();\n }\n\n if (this.loaded) return Promise.resolve();\n if (this.loadingPromise) return this.loadingPromise;\n\n this.loadingPromise = new Promise<void>((resolve) => {\n const cssUrls = [\n // Using CDN is simplest — no consumer angular.json edits needed.\n 'https://cdn.jsdelivr.net/npm/quill/dist/quill.core.css',\n 'https://cdn.jsdelivr.net/npm/quill/dist/quill.snow.css'\n ];\n\n let remaining = cssUrls.length;\n\n const onLoad = () => {\n remaining -= 1;\n if (remaining === 0) {\n this.loaded = true;\n resolve();\n }\n };\n\n cssUrls.forEach((href) => {\n // Do not add duplicate links\n if (document.querySelector(`link[href=\"${href}\"]`)) {\n onLoad();\n return;\n }\n\n const link = document.createElement('link');\n link.rel = 'stylesheet';\n link.href = href;\n link.onload = () => onLoad();\n link.onerror = () => {\n // still count it as loaded to avoid hanging if CDN fails\n console.warn(`[QuillStyleLoader] failed to load: ${href}`);\n onLoad();\n };\n document.head.appendChild(link);\n });\n });\n\n return this.loadingPromise;\n }\n}\n","import {\n AfterViewInit,\n ChangeDetectorRef,\n Component,\n ElementRef,\n Inject,\n PLATFORM_ID,\n ChangeDetectionStrategy,\n input,\n output,\n viewChild\n} from '@angular/core';\nimport { FxComponent, FxUtils } from '@foxeltech/angular-ui';\nimport { QuillStyleLoaderService } from '../quill-style-loader.service';\nimport { isPlatformBrowser } from '@angular/common';\n\n\n@Component({\n selector: 'fx-ui-rich-text-area',\n templateUrl: './rich-text-area.component.html',\n styleUrl: './rich-text-area.component.scss',\n changeDetection: ChangeDetectionStrategy.OnPush,\n})\nexport class RichTextAreaComponent extends FxComponent<any> implements AfterViewInit {\n readonly editorContainer = viewChild.required<ElementRef<HTMLDivElement>>('editorContainer');\n\n readonly placeholder = input('Write something...');\n\n readonly toolbarOptions = input<any>([\n // ['undo', 'redo'],\n [{ 'header': [1, 2, 3, 4, 5, 6, false] }],\n [{ 'font': [] }],\n [{ 'size': ['small', false, 'large', 'huge'] }],\n [{ 'align': [] }],\n [{ 'color': [] }, { 'background': [] }],\n ['bold', 'italic', 'underline', 'strike'],\n ['blockquote', 'code-block'],\n [{ 'list': 'ordered' }, { 'list': 'bullet' }],\n [{ 'indent': '-1' }, { 'indent': '+1' }],\n ['link', 'image'],\n ['clean']\n]);\n\n readonly contentChange = output<string>();\n\n private quillInstance: any;\n\n constructor(\n private styleLoader: QuillStyleLoaderService,\n @Inject(PLATFORM_ID) private platformId: object\n ) {\n super();\n }\n\n async ngAfterViewInit(): Promise<void> {\n if (!isPlatformBrowser(this.platformId)) return;\n\n await this.styleLoader.load();\n\n const QuillModule = await import('quill');\n const Quill = (QuillModule as any).default || QuillModule;\n\n const icons = Quill.import('ui/icons');\n // icons['undo'] = `<svg viewBox=\"0 0 18 18\"><path d=\"M6.4 5.2H3L6.8 1l3.8 4.2H7.9C10.2 5.4 12 7.4 12 9.8c0 2.7-2.2 4.9-4.9 4.9S2.2 12.5 2.2 9.8H0c0 3.8 3.1 6.9 6.9 6.9s6.9-3.1 6.9-6.9S10.7 3 7 3v2.2z\"></path></svg>`;\n // icons['redo'] = `<svg viewBox=\"0 0 18 18\"><path d=\"M11.6 5.2H15L11.2 1 7.4 5.2h2.7C7.8 5.4 6 7.4 6 9.8c0 2.7 2.2 4.9 4.9 4.9s4.9-2.2 4.9-4.9H18c0 3.8-3.1 6.9-6.9 6.9S4.2 13.6 4.2 9.8 7.3 3 11 3v2.2z\"></path></svg>`;\n\n this.quillInstance = new Quill(this.editorContainer().nativeElement, {\n theme: 'snow',\n placeholder: this.placeholder(),\n modules: {\n history: true,\n toolbar: this.toolbarOptions(),\n }\n });\n this.quillInstance.root.style.color = FxUtils.convertColorFromVariable('--text-primary')\n\n const toolbar = this.quillInstance.getModule('toolbar');\n toolbar.addHandler('undo', () => this.quillInstance.history.undo());\n toolbar.addHandler('redo', () => this.quillInstance.history.redo());\n\n if (this.value) {\n this.quillInstance.root.innerHTML = this.value;\n }\n\n this.quillInstance.on('text-change', () => {\n const html = this.quillInstance.root.innerHTML || '';\n this.value = html;\n this.onChange(html);\n this.contentChange.emit(html);\n });\n }\n\n override writeValue(value: any): void {\n this.value = value || '';\n if (this.quillInstance) {\n this.quillInstance.root.innerHTML = this.value;\n }\n }\n\n override setDisabledState(isDisabled: boolean): void {\n this.disabled = isDisabled;\n if (this.quillInstance) {\n this.quillInstance.enable(!isDisabled);\n }\n }\n}\n","<div class=\"w-full rounded-[var(--og-radius-card)] border border-border-default shadow-sm p-1 bg-bg-primary\">\n <div #editorContainer class=\"min-h-[200px] text-base\"></div>\n</div>","/**\n * Generated bundle index. Do not edit.\n */\n\nexport * from './public-api';\n"],"names":[],"mappings":"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"}
|