ng-prime-tools 1.0.84 → 1.0.86

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.
@@ -1,7 +1,7 @@
1
1
  import * as i0 from '@angular/core';
2
- import { Pipe, EventEmitter, ViewChild, Output, Input, Component, NgModule, Injectable, HostListener, ContentChild, HostBinding } from '@angular/core';
2
+ import { Pipe, EventEmitter, ViewChild, Output, Input, Component, NgModule, Injectable, Inject, HostListener, ContentChild, HostBinding } from '@angular/core';
3
3
  import * as i1 from '@angular/common';
4
- import { CommonModule } from '@angular/common';
4
+ import { CommonModule, DOCUMENT } from '@angular/common';
5
5
  import * as i2 from '@angular/forms';
6
6
  import { FormGroup, FormControl, Validators, ReactiveFormsModule, FormsModule } from '@angular/forms';
7
7
  import * as i3 from 'primeng/table';
@@ -3798,66 +3798,602 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.14", ngImpo
3798
3798
  }] });
3799
3799
 
3800
3800
  class PTChartComponent {
3801
- constructor() {
3801
+ constructor(document) {
3802
+ this.document = document;
3803
+ this.viewInitialized = false;
3804
+ this.colorSchemeChangeListener = () => {
3805
+ this.refreshTheme();
3806
+ };
3802
3807
  Chart.register(...registerables, ChartDataLabels);
3803
3808
  }
3804
- ngOnInit() {
3809
+ ngAfterViewInit() {
3810
+ this.viewInitialized = true;
3805
3811
  this.initializeChart();
3812
+ this.observeContainerResize();
3813
+ this.observeThemeChanges();
3814
+ }
3815
+ ngOnChanges(changes) {
3816
+ if (this.viewInitialized && changes['chartConfig'] && this.chartConfig) {
3817
+ this.updateChart();
3818
+ }
3806
3819
  }
3807
3820
  ngOnDestroy() {
3821
+ this.resizeObserver?.disconnect();
3822
+ this.themeMutationObserver?.disconnect();
3823
+ this.colorSchemeMediaQuery?.removeEventListener('change', this.colorSchemeChangeListener);
3808
3824
  this.destroyChart();
3809
3825
  }
3826
+ get chartContainerStyle() {
3827
+ return {
3828
+ width: this.chartConfig?.chartWidth?.trim() || '100%',
3829
+ height: this.chartConfig?.chartHeight?.trim() || '100%',
3830
+ };
3831
+ }
3832
+ get chartAriaLabel() {
3833
+ return this.chartConfig?.medianTitle?.trim() || 'Graphique de données';
3834
+ }
3810
3835
  initializeChart() {
3836
+ if (!this.viewInitialized || !this.chartConfig) {
3837
+ return;
3838
+ }
3811
3839
  const canvas = this.canvasRef.nativeElement;
3812
- // Destroy the existing chart instance if it already exists
3813
3840
  this.destroyChart();
3814
- const config = {
3815
- type: this.chartConfig.type,
3816
- data: this.chartConfig.data,
3817
- options: {
3818
- ...this.chartConfig.options,
3819
- plugins: {
3820
- datalabels: {
3821
- formatter: (value, context) => {
3822
- const data = context.chart.data.datasets[0].data;
3823
- const total = data.reduce((sum, val) => sum + val, 0);
3824
- const percentage = ((value / total) * 100).toFixed(1) + '%';
3825
- return percentage;
3826
- },
3827
- color: '#000',
3841
+ const configuration = this.buildChartConfiguration();
3842
+ this.chart = new Chart(canvas, configuration);
3843
+ this.currentChartType = this.chartConfig.type;
3844
+ }
3845
+ updateChart() {
3846
+ if (!this.viewInitialized || !this.chartConfig) {
3847
+ return;
3848
+ }
3849
+ if (!this.chart) {
3850
+ this.initializeChart();
3851
+ return;
3852
+ }
3853
+ const requestedType = this.chartConfig.type;
3854
+ /*
3855
+ * Chart.js does not safely support changing the root chart type
3856
+ * dynamically. Recreate the chart when the requested type changes.
3857
+ */
3858
+ if (this.currentChartType !== requestedType) {
3859
+ this.initializeChart();
3860
+ return;
3861
+ }
3862
+ const configuration = this.buildChartConfiguration();
3863
+ this.chart.data = configuration.data;
3864
+ if (configuration.options) {
3865
+ this.chart.options = configuration.options;
3866
+ }
3867
+ this.chart.update();
3868
+ }
3869
+ buildChartConfiguration() {
3870
+ const chartType = this.chartConfig.type;
3871
+ const theme = this.resolveTheme();
3872
+ const defaultOptions = this.buildDefaultOptions(chartType, theme);
3873
+ const consumerOptions = this.chartConfig.options ?? {};
3874
+ return {
3875
+ type: chartType,
3876
+ data: this.cloneChartData(this.chartConfig.data),
3877
+ options: this.mergeChartOptions(defaultOptions, consumerOptions, chartType),
3878
+ };
3879
+ }
3880
+ buildDefaultOptions(chartType, theme) {
3881
+ const isCartesianChart = this.isCartesianChart(chartType);
3882
+ const isCircularChart = this.isCircularChart(chartType);
3883
+ const options = {
3884
+ responsive: true,
3885
+ maintainAspectRatio: false,
3886
+ resizeDelay: 100,
3887
+ interaction: {
3888
+ intersect: false,
3889
+ mode: isCartesianChart ? 'index' : 'nearest',
3890
+ },
3891
+ animation: {
3892
+ duration: 450,
3893
+ easing: 'easeOutQuart',
3894
+ },
3895
+ layout: {
3896
+ padding: {
3897
+ top: 12,
3898
+ right: 12,
3899
+ bottom: 8,
3900
+ left: 12,
3901
+ },
3902
+ },
3903
+ plugins: {
3904
+ legend: {
3905
+ display: true,
3906
+ position: 'bottom',
3907
+ align: 'center',
3908
+ labels: {
3909
+ color: theme.textColor,
3910
+ usePointStyle: true,
3911
+ pointStyle: 'circle',
3912
+ boxWidth: 9,
3913
+ boxHeight: 9,
3914
+ padding: 18,
3828
3915
  font: {
3829
- weight: 'bold',
3916
+ family: this.resolveFontFamily(),
3917
+ size: 12,
3918
+ weight: 500,
3830
3919
  },
3831
3920
  },
3832
- ...this.chartConfig.options?.plugins,
3921
+ },
3922
+ title: {
3923
+ display: Boolean(this.chartConfig.medianTitle?.trim()),
3924
+ text: this.chartConfig.medianTitle?.trim() || '',
3925
+ align: 'start',
3926
+ color: theme.textColor,
3927
+ padding: {
3928
+ top: 4,
3929
+ bottom: 18,
3930
+ },
3931
+ font: {
3932
+ family: this.resolveFontFamily(),
3933
+ size: 16,
3934
+ weight: 600,
3935
+ },
3936
+ },
3937
+ tooltip: {
3938
+ enabled: true,
3939
+ backgroundColor: theme.tooltipBackgroundColor,
3940
+ titleColor: theme.tooltipTextColor,
3941
+ bodyColor: theme.tooltipTextColor,
3942
+ footerColor: theme.secondaryTextColor,
3943
+ borderColor: theme.tooltipBorderColor,
3944
+ borderWidth: 1,
3945
+ cornerRadius: 10,
3946
+ caretSize: 7,
3947
+ caretPadding: 8,
3948
+ padding: 12,
3949
+ boxPadding: 6,
3950
+ usePointStyle: true,
3951
+ displayColors: true,
3952
+ titleFont: {
3953
+ family: this.resolveFontFamily(),
3954
+ size: 13,
3955
+ weight: 600,
3956
+ },
3957
+ bodyFont: {
3958
+ family: this.resolveFontFamily(),
3959
+ size: 12,
3960
+ weight: 400,
3961
+ },
3962
+ callbacks: {
3963
+ label: (context) => {
3964
+ return this.buildTooltipLabel(context, isCircularChart);
3965
+ },
3966
+ },
3967
+ },
3968
+ datalabels: {
3969
+ display: isCircularChart,
3970
+ color: theme.textColor,
3971
+ anchor: isCircularChart ? 'center' : 'end',
3972
+ align: isCircularChart ? 'center' : 'top',
3973
+ clamp: true,
3974
+ clip: false,
3975
+ formatter: (value, context) => {
3976
+ return this.formatDataLabel(value, context.chart, context.datasetIndex, isCircularChart);
3977
+ },
3978
+ font: {
3979
+ family: this.resolveFontFamily(),
3980
+ size: 11,
3981
+ weight: 'bold',
3982
+ },
3983
+ textStrokeColor: theme.surfaceColor,
3984
+ textStrokeWidth: isCircularChart ? 2 : 0,
3833
3985
  },
3834
3986
  },
3835
3987
  };
3836
- // Create a new Chart instance
3837
- this.chart = new Chart(canvas, config);
3988
+ if (isCartesianChart) {
3989
+ options.scales = this.buildDefaultScales(theme);
3990
+ }
3991
+ return options;
3838
3992
  }
3839
- updateChart() {
3840
- if (this.chart) {
3841
- this.chart.data = this.chartConfig.data;
3842
- if (this.chartConfig.options) {
3843
- this.chart.options = this.chartConfig.options;
3993
+ buildDefaultScales(theme) {
3994
+ const commonTickFont = {
3995
+ family: this.resolveFontFamily(),
3996
+ size: 11,
3997
+ weight: 400,
3998
+ };
3999
+ return {
4000
+ x: {
4001
+ display: true,
4002
+ beginAtZero: false,
4003
+ border: {
4004
+ display: false,
4005
+ },
4006
+ grid: {
4007
+ display: false,
4008
+ color: theme.gridColor,
4009
+ drawTicks: false,
4010
+ },
4011
+ ticks: {
4012
+ color: theme.secondaryTextColor,
4013
+ padding: 10,
4014
+ maxRotation: 0,
4015
+ autoSkip: true,
4016
+ font: commonTickFont,
4017
+ },
4018
+ title: {
4019
+ display: Boolean(this.chartConfig.xAxisTitle?.trim()),
4020
+ text: this.chartConfig.xAxisTitle?.trim() || '',
4021
+ color: theme.textColor,
4022
+ padding: {
4023
+ top: 12,
4024
+ },
4025
+ font: {
4026
+ family: this.resolveFontFamily(),
4027
+ size: 12,
4028
+ weight: 600,
4029
+ },
4030
+ },
4031
+ },
4032
+ y: {
4033
+ display: true,
4034
+ beginAtZero: this.chartConfig.scales?.y?.ticks?.beginAtZero ?? true,
4035
+ min: this.chartConfig.scales?.y?.min,
4036
+ max: this.chartConfig.scales?.y?.max,
4037
+ border: {
4038
+ display: false,
4039
+ },
4040
+ grid: {
4041
+ display: true,
4042
+ color: theme.gridColor,
4043
+ drawTicks: false,
4044
+ lineWidth: 1,
4045
+ },
4046
+ ticks: {
4047
+ color: theme.secondaryTextColor,
4048
+ padding: 10,
4049
+ stepSize: this.chartConfig.scales?.y?.ticks?.stepSize,
4050
+ font: commonTickFont,
4051
+ },
4052
+ title: {
4053
+ display: Boolean(this.chartConfig.yAxisTitle?.trim()),
4054
+ text: this.chartConfig.yAxisTitle?.trim() || '',
4055
+ color: theme.textColor,
4056
+ padding: {
4057
+ bottom: 12,
4058
+ },
4059
+ font: {
4060
+ family: this.resolveFontFamily(),
4061
+ size: 12,
4062
+ weight: 600,
4063
+ },
4064
+ },
4065
+ },
4066
+ };
4067
+ }
4068
+ mergeChartOptions(defaultOptions, consumerOptions, chartType) {
4069
+ const defaultPlugins = defaultOptions.plugins;
4070
+ const consumerPlugins = consumerOptions.plugins;
4071
+ const mergedOptions = {
4072
+ ...defaultOptions,
4073
+ ...consumerOptions,
4074
+ interaction: {
4075
+ ...defaultOptions.interaction,
4076
+ ...consumerOptions.interaction,
4077
+ },
4078
+ animation: consumerOptions.animation === false
4079
+ ? false
4080
+ : {
4081
+ ...(typeof defaultOptions.animation === 'object'
4082
+ ? defaultOptions.animation
4083
+ : {}),
4084
+ ...(typeof consumerOptions.animation === 'object'
4085
+ ? consumerOptions.animation
4086
+ : {}),
4087
+ },
4088
+ layout: {
4089
+ ...defaultOptions.layout,
4090
+ ...consumerOptions.layout,
4091
+ padding: consumerOptions.layout?.padding ?? defaultOptions.layout?.padding,
4092
+ },
4093
+ plugins: {
4094
+ ...defaultPlugins,
4095
+ ...consumerPlugins,
4096
+ legend: {
4097
+ ...defaultPlugins?.legend,
4098
+ ...consumerPlugins?.legend,
4099
+ labels: {
4100
+ ...defaultPlugins?.legend?.labels,
4101
+ ...consumerPlugins?.legend?.labels,
4102
+ /*
4103
+ * Chart.js font options may be scriptable callbacks.
4104
+ * Keep the complete consumer value rather than spreading it.
4105
+ */
4106
+ font: consumerPlugins?.legend?.labels?.font ??
4107
+ defaultPlugins?.legend?.labels?.font,
4108
+ },
4109
+ },
4110
+ title: {
4111
+ ...defaultPlugins?.title,
4112
+ ...consumerPlugins?.title,
4113
+ font: consumerPlugins?.title?.font ?? defaultPlugins?.title?.font,
4114
+ },
4115
+ tooltip: {
4116
+ ...defaultPlugins?.tooltip,
4117
+ ...consumerPlugins?.tooltip,
4118
+ titleFont: consumerPlugins?.tooltip?.titleFont ??
4119
+ defaultPlugins?.tooltip?.titleFont,
4120
+ bodyFont: consumerPlugins?.tooltip?.bodyFont ??
4121
+ defaultPlugins?.tooltip?.bodyFont,
4122
+ footerFont: consumerPlugins?.tooltip?.footerFont ??
4123
+ defaultPlugins?.tooltip?.footerFont,
4124
+ callbacks: {
4125
+ ...defaultPlugins?.tooltip?.callbacks,
4126
+ ...consumerPlugins?.tooltip?.callbacks,
4127
+ },
4128
+ },
4129
+ datalabels: {
4130
+ ...defaultPlugins?.datalabels,
4131
+ ...consumerPlugins?.datalabels,
4132
+ },
4133
+ },
4134
+ };
4135
+ if (this.isCartesianChart(chartType)) {
4136
+ mergedOptions.scales = this.mergeScales(defaultOptions.scales, consumerOptions.scales);
4137
+ }
4138
+ else if (consumerOptions.scales) {
4139
+ mergedOptions.scales = consumerOptions.scales;
4140
+ }
4141
+ return mergedOptions;
4142
+ }
4143
+ mergeScales(defaultScales, consumerScales) {
4144
+ const defaultScaleRecord = defaultScales ??
4145
+ {};
4146
+ const consumerScaleRecord = consumerScales ??
4147
+ {};
4148
+ const scaleKeys = new Set([
4149
+ ...Object.keys(defaultScaleRecord),
4150
+ ...Object.keys(consumerScaleRecord),
4151
+ ]);
4152
+ const mergedScales = {};
4153
+ scaleKeys.forEach((scaleKey) => {
4154
+ const defaultScale = defaultScaleRecord[scaleKey] ?? {};
4155
+ const consumerScale = consumerScaleRecord[scaleKey] ?? {};
4156
+ mergedScales[scaleKey] = {
4157
+ ...defaultScale,
4158
+ ...consumerScale,
4159
+ border: {
4160
+ ...this.asObject(defaultScale['border']),
4161
+ ...this.asObject(consumerScale['border']),
4162
+ },
4163
+ grid: {
4164
+ ...this.asObject(defaultScale['grid']),
4165
+ ...this.asObject(consumerScale['grid']),
4166
+ },
4167
+ ticks: {
4168
+ ...this.asObject(defaultScale['ticks']),
4169
+ ...this.asObject(consumerScale['ticks']),
4170
+ },
4171
+ title: {
4172
+ ...this.asObject(defaultScale['title']),
4173
+ ...this.asObject(consumerScale['title']),
4174
+ },
4175
+ };
4176
+ });
4177
+ return mergedScales;
4178
+ }
4179
+ buildTooltipLabel(context, includePercentage) {
4180
+ const datasetLabel = context.dataset.label?.trim();
4181
+ const value = this.extractNumericValue(context.raw);
4182
+ const formattedValue = value !== null ? this.formatNumber(value) : context.formattedValue;
4183
+ const prefix = datasetLabel ? `${datasetLabel}: ` : '';
4184
+ if (!includePercentage || value === null) {
4185
+ return `${prefix}${formattedValue}`;
4186
+ }
4187
+ const total = this.calculateDatasetTotal(context.dataset);
4188
+ if (total <= 0) {
4189
+ return `${prefix}${formattedValue}`;
4190
+ }
4191
+ const percentage = ((Math.abs(value) / total) * 100).toFixed(1);
4192
+ return `${prefix}${formattedValue} (${percentage} %)`;
4193
+ }
4194
+ formatDataLabel(value, chart, datasetIndex, displayPercentage) {
4195
+ const numericValue = this.extractNumericValue(value);
4196
+ if (numericValue === null) {
4197
+ return '';
4198
+ }
4199
+ if (!displayPercentage) {
4200
+ return this.formatNumber(numericValue);
4201
+ }
4202
+ const dataset = chart.data.datasets[datasetIndex];
4203
+ if (!dataset) {
4204
+ return '';
4205
+ }
4206
+ const total = this.calculateDatasetTotal(dataset);
4207
+ if (total <= 0) {
4208
+ return '';
4209
+ }
4210
+ const percentage = (Math.abs(numericValue) / total) * 100;
4211
+ return percentage >= 1 ? `${percentage.toFixed(1)}%` : '';
4212
+ }
4213
+ calculateDatasetTotal(dataset) {
4214
+ return dataset.data.reduce((total, currentValue) => {
4215
+ const numericValue = this.extractNumericValue(currentValue);
4216
+ return numericValue !== null ? total + Math.abs(numericValue) : total;
4217
+ }, 0);
4218
+ }
4219
+ extractNumericValue(value) {
4220
+ if (typeof value === 'number' && Number.isFinite(value)) {
4221
+ return value;
4222
+ }
4223
+ if (typeof value === 'string') {
4224
+ const parsedValue = Number(value);
4225
+ return Number.isFinite(parsedValue) ? parsedValue : null;
4226
+ }
4227
+ if (Array.isArray(value)) {
4228
+ const candidate = value.find((item) => typeof item === 'number' && Number.isFinite(item));
4229
+ return typeof candidate === 'number' ? candidate : null;
4230
+ }
4231
+ if (value && typeof value === 'object') {
4232
+ const point = value;
4233
+ const candidate = point['y'] ?? point['r'] ?? point['value'] ?? point['x'];
4234
+ return this.extractNumericValue(candidate);
4235
+ }
4236
+ return null;
4237
+ }
4238
+ formatNumber(value) {
4239
+ return new Intl.NumberFormat(undefined, {
4240
+ maximumFractionDigits: 2,
4241
+ }).format(value);
4242
+ }
4243
+ cloneChartData(data) {
4244
+ return {
4245
+ ...data,
4246
+ labels: data.labels ? [...data.labels] : undefined,
4247
+ xLabels: data.xLabels ? [...data.xLabels] : undefined,
4248
+ yLabels: data.yLabels ? [...data.yLabels] : undefined,
4249
+ datasets: data.datasets.map((dataset) => ({
4250
+ ...dataset,
4251
+ data: [...dataset.data],
4252
+ })),
4253
+ };
4254
+ }
4255
+ observeContainerResize() {
4256
+ if (typeof ResizeObserver === 'undefined') {
4257
+ return;
4258
+ }
4259
+ const container = this.canvasRef.nativeElement.parentElement;
4260
+ if (!container) {
4261
+ return;
4262
+ }
4263
+ this.resizeObserver = new ResizeObserver(() => {
4264
+ this.chart?.resize();
4265
+ });
4266
+ this.resizeObserver.observe(container);
4267
+ }
4268
+ observeThemeChanges() {
4269
+ const documentElement = this.document.documentElement;
4270
+ if (typeof MutationObserver !== 'undefined') {
4271
+ this.themeMutationObserver = new MutationObserver(() => {
4272
+ this.refreshTheme();
4273
+ });
4274
+ this.themeMutationObserver.observe(documentElement, {
4275
+ attributes: true,
4276
+ attributeFilter: ['class', 'style', 'data-theme'],
4277
+ });
4278
+ if (this.document.body) {
4279
+ this.themeMutationObserver.observe(this.document.body, {
4280
+ attributes: true,
4281
+ attributeFilter: ['class', 'style', 'data-theme'],
4282
+ });
3844
4283
  }
3845
- this.chart.update();
4284
+ }
4285
+ if (typeof window !== 'undefined' && window.matchMedia) {
4286
+ this.colorSchemeMediaQuery = window.matchMedia('(prefers-color-scheme: dark)');
4287
+ this.colorSchemeMediaQuery.addEventListener('change', this.colorSchemeChangeListener);
3846
4288
  }
3847
4289
  }
3848
- destroyChart() {
3849
- if (this.chart) {
3850
- this.chart.destroy();
3851
- this.chart = undefined;
4290
+ refreshTheme() {
4291
+ if (!this.chart || !this.chartConfig) {
4292
+ return;
3852
4293
  }
4294
+ const configuration = this.buildChartConfiguration();
4295
+ if (configuration.options) {
4296
+ this.chart.options = configuration.options;
4297
+ }
4298
+ this.chart.update('none');
4299
+ }
4300
+ resolveTheme() {
4301
+ const rootStyles = getComputedStyle(this.document.documentElement);
4302
+ const bodyStyles = this.document.body
4303
+ ? getComputedStyle(this.document.body)
4304
+ : rootStyles;
4305
+ const isDarkMode = this.isDarkMode(rootStyles, bodyStyles);
4306
+ return {
4307
+ textColor: this.resolveCssVariable(rootStyles, ['--p-text-color', '--text-color'], isDarkMode ? '#f8fafc' : '#0f172a'),
4308
+ secondaryTextColor: this.resolveCssVariable(rootStyles, [
4309
+ '--p-text-muted-color',
4310
+ '--p-text-secondary-color',
4311
+ '--text-color-secondary',
4312
+ ], isDarkMode ? '#94a3b8' : '#64748b'),
4313
+ surfaceColor: this.resolveCssVariable(rootStyles, [
4314
+ '--p-content-background',
4315
+ '--p-surface-0',
4316
+ '--surface-card',
4317
+ '--surface-ground',
4318
+ ], isDarkMode ? '#0f172a' : '#ffffff'),
4319
+ gridColor: this.resolveCssVariable(rootStyles, ['--p-content-border-color', '--p-surface-border', '--surface-border'], isDarkMode ? 'rgba(148, 163, 184, 0.16)' : 'rgba(15, 23, 42, 0.08)'),
4320
+ tooltipBackgroundColor: this.resolveCssVariable(rootStyles, ['--p-tooltip-background', '--p-surface-900', '--surface-900'], isDarkMode ? 'rgba(15, 23, 42, 0.96)' : 'rgba(15, 23, 42, 0.94)'),
4321
+ tooltipTextColor: this.resolveCssVariable(rootStyles, ['--p-tooltip-color', '--p-surface-0', '--surface-0'], '#f8fafc'),
4322
+ tooltipBorderColor: this.resolveCssVariable(rootStyles, ['--p-content-border-color', '--p-surface-border', '--surface-border'], isDarkMode ? 'rgba(148, 163, 184, 0.35)' : 'rgba(255, 255, 255, 0.18)'),
4323
+ };
4324
+ }
4325
+ isDarkMode(rootStyles, bodyStyles) {
4326
+ const root = this.document.documentElement;
4327
+ const body = this.document.body;
4328
+ const darkClassDetected = root.classList.contains('p-dark') ||
4329
+ root.classList.contains('dark') ||
4330
+ root.classList.contains('dark-mode') ||
4331
+ body?.classList.contains('p-dark') ||
4332
+ body?.classList.contains('dark') ||
4333
+ body?.classList.contains('dark-mode') ||
4334
+ root.getAttribute('data-theme') === 'dark' ||
4335
+ body?.getAttribute('data-theme') === 'dark';
4336
+ if (darkClassDetected) {
4337
+ return true;
4338
+ }
4339
+ const rootColorScheme = rootStyles
4340
+ .getPropertyValue('color-scheme')
4341
+ .trim()
4342
+ .toLowerCase();
4343
+ const bodyColorScheme = bodyStyles
4344
+ .getPropertyValue('color-scheme')
4345
+ .trim()
4346
+ .toLowerCase();
4347
+ if (rootColorScheme === 'dark' || bodyColorScheme === 'dark') {
4348
+ return true;
4349
+ }
4350
+ return (typeof window !== 'undefined' &&
4351
+ window.matchMedia?.('(prefers-color-scheme: dark)').matches === true);
3853
4352
  }
3854
- static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.14", ngImport: i0, type: PTChartComponent, deps: [], target: i0.ɵɵFactoryTarget.Component }); }
3855
- static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "21.2.14", type: PTChartComponent, isStandalone: false, selector: "pt-chart", inputs: { chartConfig: "chartConfig" }, viewQueries: [{ propertyName: "canvasRef", first: true, predicate: ["chartCanvas"], descendants: true, static: true }], ngImport: i0, template: "<div style=\"position: relative; height: 100%; width: 100%\">\n <canvas #chartCanvas></canvas>\n</div>\n", styles: [""] }); }
4353
+ resolveCssVariable(styles, variableNames, fallback) {
4354
+ for (const variableName of variableNames) {
4355
+ const value = styles.getPropertyValue(variableName).trim();
4356
+ if (value) {
4357
+ return value;
4358
+ }
4359
+ }
4360
+ return fallback;
4361
+ }
4362
+ resolveFontFamily() {
4363
+ const rootStyles = getComputedStyle(this.document.documentElement);
4364
+ return this.resolveCssVariable(rootStyles, ['--p-font-family', '--font-family'], 'Inter, ui-sans-serif, system-ui, -apple-system, BlinkMacSystemFont, "Segoe UI", sans-serif');
4365
+ }
4366
+ asObject(value) {
4367
+ return value !== null && typeof value === 'object'
4368
+ ? value
4369
+ : {};
4370
+ }
4371
+ isCircularChart(chartType) {
4372
+ return (chartType === 'pie' ||
4373
+ chartType === 'doughnut' ||
4374
+ chartType === 'polarArea');
4375
+ }
4376
+ isCartesianChart(chartType) {
4377
+ return (chartType === 'bar' ||
4378
+ chartType === 'line' ||
4379
+ chartType === 'scatter' ||
4380
+ chartType === 'bubble');
4381
+ }
4382
+ destroyChart() {
4383
+ this.chart?.destroy();
4384
+ this.chart = undefined;
4385
+ this.currentChartType = undefined;
4386
+ }
4387
+ static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.14", ngImport: i0, type: PTChartComponent, deps: [{ token: DOCUMENT }], target: i0.ɵɵFactoryTarget.Component }); }
4388
+ static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "21.2.14", type: PTChartComponent, isStandalone: false, selector: "pt-chart", inputs: { chartConfig: "chartConfig" }, viewQueries: [{ propertyName: "canvasRef", first: true, predicate: ["chartCanvas"], descendants: true, static: true }], usesOnChanges: true, ngImport: i0, template: "<div\n class=\"pt-chart\"\n [ngStyle]=\"chartContainerStyle\"\n role=\"img\"\n [attr.aria-label]=\"chartAriaLabel\"\n>\n <div class=\"pt-chart__canvas-container\">\n <canvas #chartCanvas></canvas>\n </div>\n</div>\n", styles: [":host{display:block;width:100%;min-width:0;height:100%;min-height:0}.pt-chart{position:relative;display:block;box-sizing:border-box;min-width:0;min-height:18rem;overflow:hidden;color:var(--p-text-color, var(--text-color, #0f172a));background:linear-gradient(145deg,color-mix(in srgb,var(--p-content-background, var(--surface-card, #ffffff)) 97%,var(--p-primary-color, #3b82f6) 3%),var(--p-content-background, var(--surface-card, #ffffff)));border:1px solid var(--p-content-border-color, var(--surface-border, rgba(15, 23, 42, .1)));border-radius:var(--p-content-border-radius, .875rem);box-shadow:0 1px 2px #0f172a0a,0 8px 24px #0f172a0d;transition:background-color .18s ease,border-color .18s ease,box-shadow .18s ease}.pt-chart:before{position:absolute;top:0;right:12%;left:12%;z-index:0;height:1px;pointer-events:none;content:\"\";background:linear-gradient(90deg,transparent,color-mix(in srgb,var(--p-primary-color, #3b82f6) 45%,transparent),transparent)}.pt-chart__canvas-container{position:relative;z-index:1;width:100%;height:100%;min-width:0;min-height:inherit;padding:clamp(.75rem,1.5vw,1.25rem);box-sizing:border-box}.pt-chart canvas{display:block;width:100%!important;max-width:100%;height:100%!important;max-height:100%;outline:none}.pt-chart:focus-within{border-color:var(--p-primary-color, #3b82f6);box-shadow:0 0 0 3px color-mix(in srgb,var(--p-primary-color, #3b82f6) 18%,transparent),0 10px 30px #0f172a14}:host-context(.p-dark) .pt-chart,:host-context(.dark) .pt-chart,:host-context(.dark-mode) .pt-chart,:host-context([data-theme=\"dark\"]) .pt-chart{background:linear-gradient(145deg,color-mix(in srgb,var(--p-content-background, var(--surface-card, #0f172a)) 96%,var(--p-primary-color, #60a5fa) 4%),var(--p-content-background, var(--surface-card, #0f172a)));border-color:var( --p-content-border-color, var(--surface-border, rgba(148, 163, 184, .2)) );box-shadow:0 1px 2px #0000002e,0 12px 32px #00000038}@media(prefers-color-scheme:dark){.pt-chart{box-shadow:0 1px 2px #0000002e,0 12px 32px #0000002e}}@media(max-width:768px){.pt-chart{min-height:16rem;border-radius:.75rem}.pt-chart__canvas-container{padding:.75rem .625rem}}@media(max-width:480px){.pt-chart{min-height:15rem}.pt-chart__canvas-container{padding:.625rem .375rem}}@media(prefers-reduced-motion:reduce){.pt-chart{transition:none}}@media print{.pt-chart{overflow:visible;background:#fff;border:1px solid #d1d5db;box-shadow:none}}\n"], dependencies: [{ kind: "directive", type: i1.NgStyle, selector: "[ngStyle]", inputs: ["ngStyle"] }] }); }
3856
4389
  }
3857
4390
  i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.14", ngImport: i0, type: PTChartComponent, decorators: [{
3858
4391
  type: Component,
3859
- args: [{ selector: 'pt-chart', standalone: false, template: "<div style=\"position: relative; height: 100%; width: 100%\">\n <canvas #chartCanvas></canvas>\n</div>\n" }]
3860
- }], ctorParameters: () => [], propDecorators: { chartConfig: [{
4392
+ args: [{ selector: 'pt-chart', standalone: false, template: "<div\n class=\"pt-chart\"\n [ngStyle]=\"chartContainerStyle\"\n role=\"img\"\n [attr.aria-label]=\"chartAriaLabel\"\n>\n <div class=\"pt-chart__canvas-container\">\n <canvas #chartCanvas></canvas>\n </div>\n</div>\n", styles: [":host{display:block;width:100%;min-width:0;height:100%;min-height:0}.pt-chart{position:relative;display:block;box-sizing:border-box;min-width:0;min-height:18rem;overflow:hidden;color:var(--p-text-color, var(--text-color, #0f172a));background:linear-gradient(145deg,color-mix(in srgb,var(--p-content-background, var(--surface-card, #ffffff)) 97%,var(--p-primary-color, #3b82f6) 3%),var(--p-content-background, var(--surface-card, #ffffff)));border:1px solid var(--p-content-border-color, var(--surface-border, rgba(15, 23, 42, .1)));border-radius:var(--p-content-border-radius, .875rem);box-shadow:0 1px 2px #0f172a0a,0 8px 24px #0f172a0d;transition:background-color .18s ease,border-color .18s ease,box-shadow .18s ease}.pt-chart:before{position:absolute;top:0;right:12%;left:12%;z-index:0;height:1px;pointer-events:none;content:\"\";background:linear-gradient(90deg,transparent,color-mix(in srgb,var(--p-primary-color, #3b82f6) 45%,transparent),transparent)}.pt-chart__canvas-container{position:relative;z-index:1;width:100%;height:100%;min-width:0;min-height:inherit;padding:clamp(.75rem,1.5vw,1.25rem);box-sizing:border-box}.pt-chart canvas{display:block;width:100%!important;max-width:100%;height:100%!important;max-height:100%;outline:none}.pt-chart:focus-within{border-color:var(--p-primary-color, #3b82f6);box-shadow:0 0 0 3px color-mix(in srgb,var(--p-primary-color, #3b82f6) 18%,transparent),0 10px 30px #0f172a14}:host-context(.p-dark) .pt-chart,:host-context(.dark) .pt-chart,:host-context(.dark-mode) .pt-chart,:host-context([data-theme=\"dark\"]) .pt-chart{background:linear-gradient(145deg,color-mix(in srgb,var(--p-content-background, var(--surface-card, #0f172a)) 96%,var(--p-primary-color, #60a5fa) 4%),var(--p-content-background, var(--surface-card, #0f172a)));border-color:var( --p-content-border-color, var(--surface-border, rgba(148, 163, 184, .2)) );box-shadow:0 1px 2px #0000002e,0 12px 32px #00000038}@media(prefers-color-scheme:dark){.pt-chart{box-shadow:0 1px 2px #0000002e,0 12px 32px #0000002e}}@media(max-width:768px){.pt-chart{min-height:16rem;border-radius:.75rem}.pt-chart__canvas-container{padding:.75rem .625rem}}@media(max-width:480px){.pt-chart{min-height:15rem}.pt-chart__canvas-container{padding:.625rem .375rem}}@media(prefers-reduced-motion:reduce){.pt-chart{transition:none}}@media print{.pt-chart{overflow:visible;background:#fff;border:1px solid #d1d5db;box-shadow:none}}\n"] }]
4393
+ }], ctorParameters: () => [{ type: Document, decorators: [{
4394
+ type: Inject,
4395
+ args: [DOCUMENT]
4396
+ }] }], propDecorators: { chartConfig: [{
3861
4397
  type: Input
3862
4398
  }], canvasRef: [{
3863
4399
  type: ViewChild,
@@ -5350,6 +5886,7 @@ class PTLoginCardComponent {
5350
5886
  this.fb = fb;
5351
5887
  this.loginErrorMessage = null;
5352
5888
  this.loginSubmit = new EventEmitter();
5889
+ this.destroy$ = new Subject();
5353
5890
  this.formGroup = this.fb.group({});
5354
5891
  }
5355
5892
  ngOnInit() {
@@ -5359,23 +5896,26 @@ class PTLoginCardComponent {
5359
5896
  username: this.loginPageConfig?.login?.username || '',
5360
5897
  password: this.loginPageConfig?.login?.password || '',
5361
5898
  });
5362
- // Enable/Disable the button based on form validity
5363
- this.formGroup.statusChanges.subscribe((status) => {
5364
- this.loginPageConfig.buttonConfig = {
5365
- ...this.loginPageConfig.buttonConfig,
5366
- disabled: status !== 'VALID',
5367
- };
5899
+ this.updateButtonDisabledState(this.formGroup.valid);
5900
+ this.formGroup.statusChanges
5901
+ .pipe(takeUntil(this.destroy$))
5902
+ .subscribe((status) => {
5903
+ this.updateButtonDisabledState(status === 'VALID');
5368
5904
  });
5369
5905
  }
5370
- // Initialize default values for all fields in loginPageConfig if not set
5906
+ ngOnDestroy() {
5907
+ this.destroy$.next();
5908
+ this.destroy$.complete();
5909
+ }
5910
+ get visibleAdditionalContent() {
5911
+ return (this.loginPageConfig.additionalContent?.filter((item) => item.visible !== false) ?? []);
5912
+ }
5371
5913
  initializeDefaults() {
5372
- // Initialize backgroundImage
5373
5914
  this.loginPageConfig.backgroundImage = {
5374
5915
  imageUrl: this.loginPageConfig.backgroundImage?.imageUrl || '',
5375
5916
  transparencyPercentage: this.loginPageConfig.backgroundImage?.transparencyPercentage || '100',
5376
5917
  ...this.loginPageConfig.backgroundImage,
5377
5918
  };
5378
- // Initialize title
5379
5919
  this.loginPageConfig.title = {
5380
5920
  text: this.loginPageConfig.title?.text || 'Login',
5381
5921
  position: this.loginPageConfig.title?.position || 'center',
@@ -5383,7 +5923,6 @@ class PTLoginCardComponent {
5383
5923
  fontSize: this.loginPageConfig.title?.fontSize || '24px',
5384
5924
  ...this.loginPageConfig.title,
5385
5925
  };
5386
- // Initialize logoUrl
5387
5926
  this.loginPageConfig.logoUrl = {
5388
5927
  altText: this.loginPageConfig.logoUrl?.altText || 'Logo',
5389
5928
  imageUrl: this.loginPageConfig.logoUrl?.imageUrl || '',
@@ -5391,13 +5930,11 @@ class PTLoginCardComponent {
5391
5930
  height: this.loginPageConfig.logoUrl?.height || 'auto',
5392
5931
  ...this.loginPageConfig.logoUrl,
5393
5932
  };
5394
- // Initialize footer
5395
5933
  this.loginPageConfig.footer = {
5396
5934
  version: this.loginPageConfig.footer?.version || 'V1.0',
5397
5935
  copyright: this.loginPageConfig.footer?.copyright || 'Your Company © 2024',
5398
5936
  ...this.loginPageConfig.footer,
5399
5937
  };
5400
- // Initialize login
5401
5938
  this.loginPageConfig.login = {
5402
5939
  username: this.loginPageConfig.login?.username || '',
5403
5940
  password: this.loginPageConfig.login?.password || '',
@@ -5406,14 +5943,12 @@ class PTLoginCardComponent {
5406
5943
  "Veuillez saisir votre nom d'utilisateur et votre mot de passe !",
5407
5944
  ...this.loginPageConfig.login,
5408
5945
  };
5409
- // Initialize cardConfig
5410
5946
  this.loginPageConfig.loginCardConfig = {
5411
5947
  noBorder: this.loginPageConfig.loginCardConfig?.noBorder ?? true,
5412
5948
  width: this.loginPageConfig.loginCardConfig?.width ?? '400px',
5413
5949
  padding: this.loginPageConfig.loginCardConfig?.padding ?? '40px',
5414
5950
  ...this.loginPageConfig.loginCardConfig,
5415
5951
  };
5416
- // Initialize usernameField
5417
5952
  this.loginPageConfig.usernameField = {
5418
5953
  name: this.loginPageConfig.usernameField?.name || 'username',
5419
5954
  label: this.loginPageConfig.usernameField?.label || "Nom d'utilisateur",
@@ -5422,7 +5957,6 @@ class PTLoginCardComponent {
5422
5957
  "Entrer votre nom d'utilisateur",
5423
5958
  ...this.loginPageConfig.usernameField,
5424
5959
  };
5425
- // Initialize passwordField
5426
5960
  this.loginPageConfig.passwordField = {
5427
5961
  name: this.loginPageConfig.passwordField?.name || 'password',
5428
5962
  label: this.loginPageConfig.passwordField?.label || 'Mot de passe',
@@ -5430,13 +5964,10 @@ class PTLoginCardComponent {
5430
5964
  placeholder: this.loginPageConfig.passwordField?.placeholder ||
5431
5965
  'Entrer votre mot de passe',
5432
5966
  type: this.loginPageConfig.passwordField?.type || FormInputTypeEnum.PASSWORD,
5433
- // Show / hide password is now handled by pt-text-input via PrimeNG p-password.
5434
5967
  toggleMask: this.loginPageConfig.passwordField?.toggleMask ?? true,
5435
- // Disabled by default for login forms.
5436
5968
  feedback: this.loginPageConfig.passwordField?.feedback ?? false,
5437
5969
  ...this.loginPageConfig.passwordField,
5438
5970
  };
5439
- // Initialize buttonConfig
5440
5971
  this.loginPageConfig.buttonConfig = {
5441
5972
  label: this.loginPageConfig.buttonConfig?.label || 'Login',
5442
5973
  type: this.loginPageConfig.buttonConfig?.type || 'submit',
@@ -5447,40 +5978,77 @@ class PTLoginCardComponent {
5447
5978
  width: this.loginPageConfig.buttonConfig?.width ?? '100%',
5448
5979
  ...this.loginPageConfig.buttonConfig,
5449
5980
  };
5981
+ this.loginPageConfig.additionalContent =
5982
+ this.loginPageConfig.additionalContent?.map((item) => ({
5983
+ type: item.type ?? this.resolveItemType(item),
5984
+ target: item.target ?? '_self',
5985
+ linkPosition: item.linkPosition ?? 'after',
5986
+ align: item.align ?? 'center',
5987
+ visible: item.visible ?? true,
5988
+ ...item,
5989
+ })) ?? [];
5450
5990
  }
5451
5991
  onSubmit() {
5452
5992
  if (this.formGroup.valid) {
5453
- this.loginSubmit.emit(this.formGroup.value);
5454
- }
5455
- else {
5456
- this.loginPageConfig.login.errorMessage =
5457
- this.loginPageConfig.login?.emptyFieldsErrorMessage;
5993
+ this.loginSubmit.emit(this.formGroup.getRawValue());
5994
+ return;
5458
5995
  }
5996
+ this.formGroup.markAllAsTouched();
5997
+ this.loginPageConfig.login.errorMessage =
5998
+ this.loginPageConfig.login?.emptyFieldsErrorMessage;
5459
5999
  }
5460
- // Setup form fields using the usernameField and passwordField from LoginPageConfig
5461
6000
  setupFormFields() {
5462
- const usernameValidators = this.loginPageConfig.usernameField?.required
6001
+ const usernameField = this.loginPageConfig.usernameField;
6002
+ const passwordField = this.loginPageConfig.passwordField;
6003
+ const usernameValidators = usernameField.required
5463
6004
  ? [Validators.required]
5464
6005
  : [];
5465
- const passwordValidators = this.loginPageConfig.passwordField?.required
6006
+ const passwordValidators = passwordField.required
5466
6007
  ? [Validators.required]
5467
6008
  : [];
5468
- this.formGroup.addControl(this.loginPageConfig.usernameField.name, this.fb.control(this.loginPageConfig.login?.username, usernameValidators));
5469
- this.formGroup.addControl(this.loginPageConfig.passwordField.name, this.fb.control(this.loginPageConfig.login?.password, passwordValidators));
6009
+ this.formGroup.addControl(usernameField.name, this.fb.control(this.loginPageConfig.login?.username ?? '', usernameValidators));
6010
+ this.formGroup.addControl(passwordField.name, this.fb.control(this.loginPageConfig.login?.password ?? '', passwordValidators));
6011
+ }
6012
+ getAdditionalContentClass(item) {
6013
+ return [
6014
+ `additional-content-${item.align ?? 'center'}`,
6015
+ item.styleClass ?? '',
6016
+ ].filter(Boolean);
6017
+ }
6018
+ getLinkRel(item) {
6019
+ if (item.rel) {
6020
+ return item.rel;
6021
+ }
6022
+ return item.target === '_blank' ? 'noopener noreferrer' : null;
6023
+ }
6024
+ resolveItemType(item) {
6025
+ if (item.text && item.linkText && item.url) {
6026
+ return 'text-with-link';
6027
+ }
6028
+ if (item.linkText && item.url) {
6029
+ return 'link';
6030
+ }
6031
+ return 'text';
6032
+ }
6033
+ updateButtonDisabledState(formValid) {
6034
+ this.loginPageConfig.buttonConfig = {
6035
+ ...this.loginPageConfig.buttonConfig,
6036
+ disabled: !formValid,
6037
+ };
5470
6038
  }
5471
6039
  static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.14", ngImport: i0, type: PTLoginCardComponent, deps: [{ token: i2.FormBuilder }], target: i0.ɵɵFactoryTarget.Component }); }
5472
- static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "21.2.14", type: PTLoginCardComponent, isStandalone: true, selector: "pt-login-card", inputs: { loginPageConfig: "loginPageConfig", loginErrorMessage: "loginErrorMessage" }, outputs: { loginSubmit: "loginSubmit" }, ngImport: i0, template: "<pt-card [config]=\"loginPageConfig.loginCardConfig!\">\n <!-- Logo -->\n @if (loginPageConfig.logoUrl?.imageUrl) {\n <div class=\"logo-container\">\n <img\n [src]=\"loginPageConfig.logoUrl?.imageUrl\"\n [alt]=\"loginPageConfig.logoUrl?.altText || 'Logo'\"\n [style.width]=\"loginPageConfig.logoUrl?.width || '100px'\"\n [style.height]=\"loginPageConfig.logoUrl?.height || 'auto'\"\n />\n </div>\n }\n\n <!-- Title -->\n <div class=\"title-container\">\n <h1\n [ngStyle]=\"{\n color: loginPageConfig.title?.color || '#333',\n 'font-size': loginPageConfig.title?.fontSize || '24px',\n }\"\n >\n {{ loginPageConfig.title?.text || \"Default Title\" }}\n </h1>\n </div>\n\n <!-- External Error Message -->\n @if (loginErrorMessage) {\n <div class=\"error-message\">\n {{ loginErrorMessage }}\n </div>\n }\n\n <!-- Form -->\n <form class=\"form-container\" [formGroup]=\"formGroup\" (ngSubmit)=\"onSubmit()\">\n @if (loginPageConfig.login?.errorMessage) {\n <div class=\"error-message\">\n {{ loginPageConfig.login?.errorMessage }}\n </div>\n }\n\n <div class=\"field\">\n <pt-text-input\n [formGroup]=\"formGroup\"\n [formField]=\"loginPageConfig.usernameField!\"\n ></pt-text-input>\n </div>\n\n <div class=\"field\">\n <pt-text-input\n [formGroup]=\"formGroup\"\n [formField]=\"loginPageConfig.passwordField!\"\n ></pt-text-input>\n </div>\n\n @if (\n loginPageConfig.forgotPasswordConfig?.text &&\n loginPageConfig.forgotPasswordConfig?.url\n ) {\n <div\n class=\"forgot-password-container\"\n [ngClass]=\"\n 'forgot-password-' +\n (loginPageConfig.forgotPasswordConfig?.align || 'center')\n \"\n >\n <a\n [href]=\"loginPageConfig.forgotPasswordConfig?.url\"\n [target]=\"loginPageConfig.forgotPasswordConfig?.target || '_self'\"\n [ngStyle]=\"loginPageConfig.forgotPasswordConfig?.style\"\n [class]=\"\n loginPageConfig.forgotPasswordConfig?.styleClass ||\n 'forgot-password-link'\n \"\n >\n {{ loginPageConfig.forgotPasswordConfig?.text }}\n </a>\n </div>\n }\n\n <div class=\"submit-btn\">\n <pt-button [buttonConfig]=\"loginPageConfig.buttonConfig!\"></pt-button>\n </div>\n </form>\n\n <div class=\"login-footer\">\n {{ loginPageConfig.footer?.version }}\n <span>{{ loginPageConfig.footer?.copyright }}</span>\n </div>\n</pt-card>\n", styles: [".logo-container{display:flex;justify-content:center;align-items:center;margin-bottom:20px}.title-container{text-align:center;margin-bottom:20px}.form-container{width:100%}.field{display:flex;flex-direction:column;margin-bottom:20px;width:100%}.error-message{color:red;background-color:#ffe6e6;border:1px solid red;padding:10px;margin-bottom:10px;border-radius:5px;width:100%;text-align:center}.forgot-password-container{width:100%;display:flex;justify-content:center;margin-top:-10px;margin-bottom:20px}.forgot-password-left{justify-content:flex-start}.forgot-password-center{justify-content:center}.forgot-password-right{justify-content:flex-end}.forgot-password-link{color:#2563eb;font-size:.9rem;font-weight:500;text-decoration:none;cursor:pointer;transition:color .2s ease}.forgot-password-link:hover{color:#1d4ed8;text-decoration:underline}.submit-btn{display:flex;justify-content:center;width:100%}::ng-deep pt-button{width:100%}::ng-deep .submit-btn p-button button{width:100%}.login-footer{margin-top:20px;text-align:center;font-size:.9em;color:#555}.login-footer span{display:block;margin-top:.25rem}@media(max-width:768px){pt-card{max-width:300px}.submit-btn{min-width:100%}.forgot-password-container{justify-content:center}}\n"], dependencies: [{ kind: "ngmodule", type: CommonModule }, { kind: "directive", type: i1.NgClass, selector: "[ngClass]", inputs: ["class", "ngClass"] }, { kind: "directive", type: i1.NgStyle, selector: "[ngStyle]", inputs: ["ngStyle"] }, { kind: "ngmodule", type: FormsModule }, { kind: "directive", type: i2.ɵNgNoValidate, selector: "form:not([ngNoForm]):not([ngNativeValidate])" }, { kind: "directive", type: i2.NgControlStatusGroup, selector: "[formGroupName],[formArrayName],[ngModelGroup],[formGroup],[formArray],form:not([ngNoForm]),[ngForm]" }, { kind: "ngmodule", type: ReactiveFormsModule }, { kind: "directive", type: i2.FormGroupDirective, selector: "[formGroup]", inputs: ["formGroup"], outputs: ["ngSubmit"], exportAs: ["ngForm"] }, { kind: "ngmodule", type: PTCardModule }, { kind: "component", type: PTCardComponent, selector: "pt-card", inputs: ["config"] }, { kind: "ngmodule", type: PTButtonModule }, { kind: "component", type: PTButtonComponent, selector: "pt-button", inputs: ["buttonConfig"] }, { kind: "ngmodule", type: PTTextInputModule }, { kind: "component", type: PTTextInputComponent, selector: "pt-text-input", inputs: ["formGroup", "formField"] }] }); }
6040
+ static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "21.2.14", type: PTLoginCardComponent, isStandalone: true, selector: "pt-login-card", inputs: { loginPageConfig: "loginPageConfig", loginErrorMessage: "loginErrorMessage" }, outputs: { loginSubmit: "loginSubmit" }, ngImport: i0, template: "<pt-card [config]=\"loginPageConfig.loginCardConfig!\">\n @if (loginPageConfig.logoUrl?.imageUrl) {\n <div class=\"logo-container\">\n <img\n [src]=\"loginPageConfig.logoUrl?.imageUrl\"\n [alt]=\"loginPageConfig.logoUrl?.altText || 'Logo'\"\n [style.width]=\"loginPageConfig.logoUrl?.width || '100px'\"\n [style.height]=\"loginPageConfig.logoUrl?.height || 'auto'\"\n />\n </div>\n }\n\n <div class=\"title-container\">\n <h1\n [ngStyle]=\"{\n color: loginPageConfig.title?.color || '#333',\n 'font-size': loginPageConfig.title?.fontSize || '24px',\n }\"\n >\n {{ loginPageConfig.title?.text || \"Default Title\" }}\n </h1>\n </div>\n\n @if (loginErrorMessage) {\n <div class=\"error-message\" role=\"alert\">\n {{ loginErrorMessage }}\n </div>\n }\n\n <form class=\"form-container\" [formGroup]=\"formGroup\" (ngSubmit)=\"onSubmit()\">\n @if (loginPageConfig.login?.errorMessage) {\n <div class=\"error-message\" role=\"alert\">\n {{ loginPageConfig.login?.errorMessage }}\n </div>\n }\n\n <div class=\"field\">\n <pt-text-input\n [formGroup]=\"formGroup\"\n [formField]=\"loginPageConfig.usernameField!\"\n ></pt-text-input>\n </div>\n\n <div class=\"field\">\n <pt-text-input\n [formGroup]=\"formGroup\"\n [formField]=\"loginPageConfig.passwordField!\"\n ></pt-text-input>\n </div>\n\n <div class=\"submit-btn\">\n <pt-button [buttonConfig]=\"loginPageConfig.buttonConfig!\"></pt-button>\n </div>\n\n @if (\n loginPageConfig.forgotPasswordConfig?.text &&\n loginPageConfig.forgotPasswordConfig?.url\n ) {\n <div\n class=\"forgot-password-container\"\n [ngClass]=\"\n 'forgot-password-' +\n (loginPageConfig.forgotPasswordConfig?.align || 'center')\n \"\n >\n <a\n [href]=\"loginPageConfig.forgotPasswordConfig?.url\"\n [target]=\"loginPageConfig.forgotPasswordConfig?.target || '_self'\"\n [rel]=\"\n loginPageConfig.forgotPasswordConfig?.target === '_blank'\n ? 'noopener noreferrer'\n : null\n \"\n [ngStyle]=\"loginPageConfig.forgotPasswordConfig?.style\"\n [class]=\"\n loginPageConfig.forgotPasswordConfig?.styleClass ||\n 'forgot-password-link'\n \"\n >\n {{ loginPageConfig.forgotPasswordConfig?.text }}\n </a>\n </div>\n }\n\n @if (visibleAdditionalContent.length > 0) {\n <div class=\"additional-content-list\">\n @for (item of visibleAdditionalContent; track item.id || $index) {\n <div\n class=\"additional-content-item\"\n [ngClass]=\"getAdditionalContentClass(item)\"\n [ngStyle]=\"item.style\"\n >\n @switch (item.type) {\n @case (\"link\") {\n @if (item.linkText && item.url) {\n <a\n [href]=\"item.url\"\n [target]=\"item.target || '_self'\"\n [rel]=\"getLinkRel(item)\"\n [class]=\"item.linkStyleClass || 'additional-content-link'\"\n [ngStyle]=\"item.linkStyle\"\n >\n {{ item.linkText }}\n </a>\n }\n }\n\n @case (\"text-with-link\") {\n @if (\n item.linkPosition === \"before\" && item.linkText && item.url\n ) {\n <a\n [href]=\"item.url\"\n [target]=\"item.target || '_self'\"\n [rel]=\"getLinkRel(item)\"\n [class]=\"item.linkStyleClass || 'additional-content-link'\"\n [ngStyle]=\"item.linkStyle\"\n >\n {{ item.linkText }}\n </a>\n\n @if (item.text) {\n <span class=\"additional-content-text\">\n {{ item.text }}\n </span>\n }\n } @else {\n @if (item.text) {\n <span class=\"additional-content-text\">\n {{ item.text }}\n </span>\n }\n\n @if (item.linkText && item.url) {\n <a\n [href]=\"item.url\"\n [target]=\"item.target || '_self'\"\n [rel]=\"getLinkRel(item)\"\n [class]=\"item.linkStyleClass || 'additional-content-link'\"\n [ngStyle]=\"item.linkStyle\"\n >\n {{ item.linkText }}\n </a>\n }\n }\n }\n\n @default {\n @if (item.text) {\n <span class=\"additional-content-text\">\n {{ item.text }}\n </span>\n }\n }\n }\n </div>\n }\n </div>\n }\n </form>\n\n <div class=\"login-footer\">\n {{ loginPageConfig.footer?.version }}\n\n <span>\n {{ loginPageConfig.footer?.copyright }}\n </span>\n </div>\n</pt-card>\n", styles: [":host{display:block;width:100%;min-width:0}.logo-container{display:flex;align-items:center;justify-content:center;margin-bottom:1.25rem}.logo-container img{display:block;max-width:100%;object-fit:contain}.title-container{margin-bottom:1.25rem;text-align:center}.title-container h1{margin:0;line-height:1.25}.form-container{width:100%}.field{display:flex;flex-direction:column;width:100%;margin-bottom:1.25rem}.error-message{width:100%;box-sizing:border-box;margin-bottom:.75rem;padding:.75rem .875rem;color:var(--p-message-error-color, #b91c1c);background:var(--p-message-error-background, #fef2f2);border:1px solid var(--p-message-error-border-color, #fecaca);border-radius:var(--p-content-border-radius, .5rem);font-size:.875rem;line-height:1.4;text-align:center}.submit-btn{display:flex;justify-content:center;width:100%}:host ::ng-deep .submit-btn pt-button{display:block;width:100%}:host ::ng-deep .submit-btn p-button,:host ::ng-deep .submit-btn p-button button{width:100%}.forgot-password-container{display:flex;width:100%;box-sizing:border-box;margin-top:.875rem;margin-bottom:0;font-size:.875rem;line-height:1.4}.forgot-password-left{justify-content:flex-start;text-align:left}.forgot-password-center{justify-content:center;text-align:center}.forgot-password-right{justify-content:flex-end;text-align:right}.forgot-password-link,.additional-content-link{color:var(--p-primary-color, #2563eb);font-size:.875rem;font-weight:500;line-height:1.4;text-decoration:none;cursor:pointer;transition:color .16s ease,text-decoration-color .16s ease}.forgot-password-link:hover,.additional-content-link:hover{color:var(--p-primary-hover-color, #1d4ed8);text-decoration:underline;text-underline-offset:.2rem}.forgot-password-link:focus-visible,.additional-content-link:focus-visible{outline:2px solid var(--p-primary-color, #2563eb);outline-offset:.2rem;border-radius:.2rem}.additional-content-list{display:flex;flex-direction:column;width:100%;margin-top:1rem;gap:.55rem}.forgot-password-container+.additional-content-list{margin-top:.75rem}.additional-content-item{display:flex;flex-wrap:wrap;align-items:baseline;width:100%;box-sizing:border-box;gap:.3rem;color:var(--p-text-muted-color, var(--text-color-secondary, #64748b));font-size:.875rem;line-height:1.45}.additional-content-left{justify-content:flex-start;text-align:left}.additional-content-center{justify-content:center;text-align:center}.additional-content-right{justify-content:flex-end;text-align:right}.additional-content-text{color:inherit}.login-footer{margin-top:1.25rem;color:var(--p-text-muted-color, var(--text-color-secondary, #64748b));font-size:.8rem;line-height:1.4;text-align:center}.login-footer span{display:block;margin-top:.25rem}:host-context(.p-dark) .error-message,:host-context(.app-dark) .error-message,:host-context(.dark) .error-message,:host-context(.dark-mode) .error-message,:host-context([data-theme=\"dark\"]) .error-message{color:var(--p-message-error-color, #fca5a5);background:var(--p-message-error-background, rgba(127, 29, 29, .25));border-color:var(--p-message-error-border-color, rgba(248, 113, 113, .4))}:host-context(.p-dark) .forgot-password-link,:host-context(.app-dark) .forgot-password-link,:host-context(.dark) .forgot-password-link,:host-context(.dark-mode) .forgot-password-link,:host-context([data-theme=\"dark\"]) .forgot-password-link,:host-context(.p-dark) .additional-content-link,:host-context(.app-dark) .additional-content-link,:host-context(.dark) .additional-content-link,:host-context(.dark-mode) .additional-content-link,:host-context([data-theme=\"dark\"]) .additional-content-link{color:var(--p-primary-color, #60a5fa)}:host-context(.p-dark) .forgot-password-link:hover,:host-context(.app-dark) .forgot-password-link:hover,:host-context(.dark) .forgot-password-link:hover,:host-context(.dark-mode) .forgot-password-link:hover,:host-context([data-theme=\"dark\"]) .forgot-password-link:hover,:host-context(.p-dark) .additional-content-link:hover,:host-context(.app-dark) .additional-content-link:hover,:host-context(.dark) .additional-content-link:hover,:host-context(.dark-mode) .additional-content-link:hover,:host-context([data-theme=\"dark\"]) .additional-content-link:hover{color:var(--p-primary-hover-color, #93c5fd)}:host-context(.p-dark) .additional-content-item,:host-context(.app-dark) .additional-content-item,:host-context(.dark) .additional-content-item,:host-context(.dark-mode) .additional-content-item,:host-context([data-theme=\"dark\"]) .additional-content-item,:host-context(.p-dark) .login-footer,:host-context(.app-dark) .login-footer,:host-context(.dark) .login-footer,:host-context(.dark-mode) .login-footer,:host-context([data-theme=\"dark\"]) .login-footer{color:var(--p-text-muted-color, var(--text-color-secondary, #cbd5e1))}@media(max-width:768px){:host ::ng-deep pt-card{width:100%;max-width:100%}.submit-btn{min-width:100%}.forgot-password-container{margin-top:.75rem}.additional-content-list{margin-top:.875rem}.forgot-password-container+.additional-content-list{margin-top:.65rem}}@media(max-width:480px){.logo-container,.title-container,.field{margin-bottom:1rem}.forgot-password-container,.forgot-password-link,.additional-content-item,.additional-content-link{font-size:.82rem}.additional-content-list{gap:.5rem}}\n"], dependencies: [{ kind: "ngmodule", type: CommonModule }, { kind: "directive", type: i1.NgClass, selector: "[ngClass]", inputs: ["class", "ngClass"] }, { kind: "directive", type: i1.NgStyle, selector: "[ngStyle]", inputs: ["ngStyle"] }, { kind: "ngmodule", type: FormsModule }, { kind: "directive", type: i2.ɵNgNoValidate, selector: "form:not([ngNoForm]):not([ngNativeValidate])" }, { kind: "directive", type: i2.NgControlStatusGroup, selector: "[formGroupName],[formArrayName],[ngModelGroup],[formGroup],[formArray],form:not([ngNoForm]),[ngForm]" }, { kind: "ngmodule", type: ReactiveFormsModule }, { kind: "directive", type: i2.FormGroupDirective, selector: "[formGroup]", inputs: ["formGroup"], outputs: ["ngSubmit"], exportAs: ["ngForm"] }, { kind: "ngmodule", type: PTCardModule }, { kind: "component", type: PTCardComponent, selector: "pt-card", inputs: ["config"] }, { kind: "ngmodule", type: PTButtonModule }, { kind: "component", type: PTButtonComponent, selector: "pt-button", inputs: ["buttonConfig"] }, { kind: "ngmodule", type: PTTextInputModule }, { kind: "component", type: PTTextInputComponent, selector: "pt-text-input", inputs: ["formGroup", "formField"] }] }); }
5473
6041
  }
5474
6042
  i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.14", ngImport: i0, type: PTLoginCardComponent, decorators: [{
5475
6043
  type: Component,
5476
- args: [{ selector: 'pt-login-card', imports: [
6044
+ args: [{ selector: 'pt-login-card', standalone: true, imports: [
5477
6045
  CommonModule,
5478
6046
  FormsModule,
5479
6047
  ReactiveFormsModule,
5480
6048
  PTCardModule,
5481
6049
  PTButtonModule,
5482
6050
  PTTextInputModule,
5483
- ], template: "<pt-card [config]=\"loginPageConfig.loginCardConfig!\">\n <!-- Logo -->\n @if (loginPageConfig.logoUrl?.imageUrl) {\n <div class=\"logo-container\">\n <img\n [src]=\"loginPageConfig.logoUrl?.imageUrl\"\n [alt]=\"loginPageConfig.logoUrl?.altText || 'Logo'\"\n [style.width]=\"loginPageConfig.logoUrl?.width || '100px'\"\n [style.height]=\"loginPageConfig.logoUrl?.height || 'auto'\"\n />\n </div>\n }\n\n <!-- Title -->\n <div class=\"title-container\">\n <h1\n [ngStyle]=\"{\n color: loginPageConfig.title?.color || '#333',\n 'font-size': loginPageConfig.title?.fontSize || '24px',\n }\"\n >\n {{ loginPageConfig.title?.text || \"Default Title\" }}\n </h1>\n </div>\n\n <!-- External Error Message -->\n @if (loginErrorMessage) {\n <div class=\"error-message\">\n {{ loginErrorMessage }}\n </div>\n }\n\n <!-- Form -->\n <form class=\"form-container\" [formGroup]=\"formGroup\" (ngSubmit)=\"onSubmit()\">\n @if (loginPageConfig.login?.errorMessage) {\n <div class=\"error-message\">\n {{ loginPageConfig.login?.errorMessage }}\n </div>\n }\n\n <div class=\"field\">\n <pt-text-input\n [formGroup]=\"formGroup\"\n [formField]=\"loginPageConfig.usernameField!\"\n ></pt-text-input>\n </div>\n\n <div class=\"field\">\n <pt-text-input\n [formGroup]=\"formGroup\"\n [formField]=\"loginPageConfig.passwordField!\"\n ></pt-text-input>\n </div>\n\n @if (\n loginPageConfig.forgotPasswordConfig?.text &&\n loginPageConfig.forgotPasswordConfig?.url\n ) {\n <div\n class=\"forgot-password-container\"\n [ngClass]=\"\n 'forgot-password-' +\n (loginPageConfig.forgotPasswordConfig?.align || 'center')\n \"\n >\n <a\n [href]=\"loginPageConfig.forgotPasswordConfig?.url\"\n [target]=\"loginPageConfig.forgotPasswordConfig?.target || '_self'\"\n [ngStyle]=\"loginPageConfig.forgotPasswordConfig?.style\"\n [class]=\"\n loginPageConfig.forgotPasswordConfig?.styleClass ||\n 'forgot-password-link'\n \"\n >\n {{ loginPageConfig.forgotPasswordConfig?.text }}\n </a>\n </div>\n }\n\n <div class=\"submit-btn\">\n <pt-button [buttonConfig]=\"loginPageConfig.buttonConfig!\"></pt-button>\n </div>\n </form>\n\n <div class=\"login-footer\">\n {{ loginPageConfig.footer?.version }}\n <span>{{ loginPageConfig.footer?.copyright }}</span>\n </div>\n</pt-card>\n", styles: [".logo-container{display:flex;justify-content:center;align-items:center;margin-bottom:20px}.title-container{text-align:center;margin-bottom:20px}.form-container{width:100%}.field{display:flex;flex-direction:column;margin-bottom:20px;width:100%}.error-message{color:red;background-color:#ffe6e6;border:1px solid red;padding:10px;margin-bottom:10px;border-radius:5px;width:100%;text-align:center}.forgot-password-container{width:100%;display:flex;justify-content:center;margin-top:-10px;margin-bottom:20px}.forgot-password-left{justify-content:flex-start}.forgot-password-center{justify-content:center}.forgot-password-right{justify-content:flex-end}.forgot-password-link{color:#2563eb;font-size:.9rem;font-weight:500;text-decoration:none;cursor:pointer;transition:color .2s ease}.forgot-password-link:hover{color:#1d4ed8;text-decoration:underline}.submit-btn{display:flex;justify-content:center;width:100%}::ng-deep pt-button{width:100%}::ng-deep .submit-btn p-button button{width:100%}.login-footer{margin-top:20px;text-align:center;font-size:.9em;color:#555}.login-footer span{display:block;margin-top:.25rem}@media(max-width:768px){pt-card{max-width:300px}.submit-btn{min-width:100%}.forgot-password-container{justify-content:center}}\n"] }]
6051
+ ], template: "<pt-card [config]=\"loginPageConfig.loginCardConfig!\">\n @if (loginPageConfig.logoUrl?.imageUrl) {\n <div class=\"logo-container\">\n <img\n [src]=\"loginPageConfig.logoUrl?.imageUrl\"\n [alt]=\"loginPageConfig.logoUrl?.altText || 'Logo'\"\n [style.width]=\"loginPageConfig.logoUrl?.width || '100px'\"\n [style.height]=\"loginPageConfig.logoUrl?.height || 'auto'\"\n />\n </div>\n }\n\n <div class=\"title-container\">\n <h1\n [ngStyle]=\"{\n color: loginPageConfig.title?.color || '#333',\n 'font-size': loginPageConfig.title?.fontSize || '24px',\n }\"\n >\n {{ loginPageConfig.title?.text || \"Default Title\" }}\n </h1>\n </div>\n\n @if (loginErrorMessage) {\n <div class=\"error-message\" role=\"alert\">\n {{ loginErrorMessage }}\n </div>\n }\n\n <form class=\"form-container\" [formGroup]=\"formGroup\" (ngSubmit)=\"onSubmit()\">\n @if (loginPageConfig.login?.errorMessage) {\n <div class=\"error-message\" role=\"alert\">\n {{ loginPageConfig.login?.errorMessage }}\n </div>\n }\n\n <div class=\"field\">\n <pt-text-input\n [formGroup]=\"formGroup\"\n [formField]=\"loginPageConfig.usernameField!\"\n ></pt-text-input>\n </div>\n\n <div class=\"field\">\n <pt-text-input\n [formGroup]=\"formGroup\"\n [formField]=\"loginPageConfig.passwordField!\"\n ></pt-text-input>\n </div>\n\n <div class=\"submit-btn\">\n <pt-button [buttonConfig]=\"loginPageConfig.buttonConfig!\"></pt-button>\n </div>\n\n @if (\n loginPageConfig.forgotPasswordConfig?.text &&\n loginPageConfig.forgotPasswordConfig?.url\n ) {\n <div\n class=\"forgot-password-container\"\n [ngClass]=\"\n 'forgot-password-' +\n (loginPageConfig.forgotPasswordConfig?.align || 'center')\n \"\n >\n <a\n [href]=\"loginPageConfig.forgotPasswordConfig?.url\"\n [target]=\"loginPageConfig.forgotPasswordConfig?.target || '_self'\"\n [rel]=\"\n loginPageConfig.forgotPasswordConfig?.target === '_blank'\n ? 'noopener noreferrer'\n : null\n \"\n [ngStyle]=\"loginPageConfig.forgotPasswordConfig?.style\"\n [class]=\"\n loginPageConfig.forgotPasswordConfig?.styleClass ||\n 'forgot-password-link'\n \"\n >\n {{ loginPageConfig.forgotPasswordConfig?.text }}\n </a>\n </div>\n }\n\n @if (visibleAdditionalContent.length > 0) {\n <div class=\"additional-content-list\">\n @for (item of visibleAdditionalContent; track item.id || $index) {\n <div\n class=\"additional-content-item\"\n [ngClass]=\"getAdditionalContentClass(item)\"\n [ngStyle]=\"item.style\"\n >\n @switch (item.type) {\n @case (\"link\") {\n @if (item.linkText && item.url) {\n <a\n [href]=\"item.url\"\n [target]=\"item.target || '_self'\"\n [rel]=\"getLinkRel(item)\"\n [class]=\"item.linkStyleClass || 'additional-content-link'\"\n [ngStyle]=\"item.linkStyle\"\n >\n {{ item.linkText }}\n </a>\n }\n }\n\n @case (\"text-with-link\") {\n @if (\n item.linkPosition === \"before\" && item.linkText && item.url\n ) {\n <a\n [href]=\"item.url\"\n [target]=\"item.target || '_self'\"\n [rel]=\"getLinkRel(item)\"\n [class]=\"item.linkStyleClass || 'additional-content-link'\"\n [ngStyle]=\"item.linkStyle\"\n >\n {{ item.linkText }}\n </a>\n\n @if (item.text) {\n <span class=\"additional-content-text\">\n {{ item.text }}\n </span>\n }\n } @else {\n @if (item.text) {\n <span class=\"additional-content-text\">\n {{ item.text }}\n </span>\n }\n\n @if (item.linkText && item.url) {\n <a\n [href]=\"item.url\"\n [target]=\"item.target || '_self'\"\n [rel]=\"getLinkRel(item)\"\n [class]=\"item.linkStyleClass || 'additional-content-link'\"\n [ngStyle]=\"item.linkStyle\"\n >\n {{ item.linkText }}\n </a>\n }\n }\n }\n\n @default {\n @if (item.text) {\n <span class=\"additional-content-text\">\n {{ item.text }}\n </span>\n }\n }\n }\n </div>\n }\n </div>\n }\n </form>\n\n <div class=\"login-footer\">\n {{ loginPageConfig.footer?.version }}\n\n <span>\n {{ loginPageConfig.footer?.copyright }}\n </span>\n </div>\n</pt-card>\n", styles: [":host{display:block;width:100%;min-width:0}.logo-container{display:flex;align-items:center;justify-content:center;margin-bottom:1.25rem}.logo-container img{display:block;max-width:100%;object-fit:contain}.title-container{margin-bottom:1.25rem;text-align:center}.title-container h1{margin:0;line-height:1.25}.form-container{width:100%}.field{display:flex;flex-direction:column;width:100%;margin-bottom:1.25rem}.error-message{width:100%;box-sizing:border-box;margin-bottom:.75rem;padding:.75rem .875rem;color:var(--p-message-error-color, #b91c1c);background:var(--p-message-error-background, #fef2f2);border:1px solid var(--p-message-error-border-color, #fecaca);border-radius:var(--p-content-border-radius, .5rem);font-size:.875rem;line-height:1.4;text-align:center}.submit-btn{display:flex;justify-content:center;width:100%}:host ::ng-deep .submit-btn pt-button{display:block;width:100%}:host ::ng-deep .submit-btn p-button,:host ::ng-deep .submit-btn p-button button{width:100%}.forgot-password-container{display:flex;width:100%;box-sizing:border-box;margin-top:.875rem;margin-bottom:0;font-size:.875rem;line-height:1.4}.forgot-password-left{justify-content:flex-start;text-align:left}.forgot-password-center{justify-content:center;text-align:center}.forgot-password-right{justify-content:flex-end;text-align:right}.forgot-password-link,.additional-content-link{color:var(--p-primary-color, #2563eb);font-size:.875rem;font-weight:500;line-height:1.4;text-decoration:none;cursor:pointer;transition:color .16s ease,text-decoration-color .16s ease}.forgot-password-link:hover,.additional-content-link:hover{color:var(--p-primary-hover-color, #1d4ed8);text-decoration:underline;text-underline-offset:.2rem}.forgot-password-link:focus-visible,.additional-content-link:focus-visible{outline:2px solid var(--p-primary-color, #2563eb);outline-offset:.2rem;border-radius:.2rem}.additional-content-list{display:flex;flex-direction:column;width:100%;margin-top:1rem;gap:.55rem}.forgot-password-container+.additional-content-list{margin-top:.75rem}.additional-content-item{display:flex;flex-wrap:wrap;align-items:baseline;width:100%;box-sizing:border-box;gap:.3rem;color:var(--p-text-muted-color, var(--text-color-secondary, #64748b));font-size:.875rem;line-height:1.45}.additional-content-left{justify-content:flex-start;text-align:left}.additional-content-center{justify-content:center;text-align:center}.additional-content-right{justify-content:flex-end;text-align:right}.additional-content-text{color:inherit}.login-footer{margin-top:1.25rem;color:var(--p-text-muted-color, var(--text-color-secondary, #64748b));font-size:.8rem;line-height:1.4;text-align:center}.login-footer span{display:block;margin-top:.25rem}:host-context(.p-dark) .error-message,:host-context(.app-dark) .error-message,:host-context(.dark) .error-message,:host-context(.dark-mode) .error-message,:host-context([data-theme=\"dark\"]) .error-message{color:var(--p-message-error-color, #fca5a5);background:var(--p-message-error-background, rgba(127, 29, 29, .25));border-color:var(--p-message-error-border-color, rgba(248, 113, 113, .4))}:host-context(.p-dark) .forgot-password-link,:host-context(.app-dark) .forgot-password-link,:host-context(.dark) .forgot-password-link,:host-context(.dark-mode) .forgot-password-link,:host-context([data-theme=\"dark\"]) .forgot-password-link,:host-context(.p-dark) .additional-content-link,:host-context(.app-dark) .additional-content-link,:host-context(.dark) .additional-content-link,:host-context(.dark-mode) .additional-content-link,:host-context([data-theme=\"dark\"]) .additional-content-link{color:var(--p-primary-color, #60a5fa)}:host-context(.p-dark) .forgot-password-link:hover,:host-context(.app-dark) .forgot-password-link:hover,:host-context(.dark) .forgot-password-link:hover,:host-context(.dark-mode) .forgot-password-link:hover,:host-context([data-theme=\"dark\"]) .forgot-password-link:hover,:host-context(.p-dark) .additional-content-link:hover,:host-context(.app-dark) .additional-content-link:hover,:host-context(.dark) .additional-content-link:hover,:host-context(.dark-mode) .additional-content-link:hover,:host-context([data-theme=\"dark\"]) .additional-content-link:hover{color:var(--p-primary-hover-color, #93c5fd)}:host-context(.p-dark) .additional-content-item,:host-context(.app-dark) .additional-content-item,:host-context(.dark) .additional-content-item,:host-context(.dark-mode) .additional-content-item,:host-context([data-theme=\"dark\"]) .additional-content-item,:host-context(.p-dark) .login-footer,:host-context(.app-dark) .login-footer,:host-context(.dark) .login-footer,:host-context(.dark-mode) .login-footer,:host-context([data-theme=\"dark\"]) .login-footer{color:var(--p-text-muted-color, var(--text-color-secondary, #cbd5e1))}@media(max-width:768px){:host ::ng-deep pt-card{width:100%;max-width:100%}.submit-btn{min-width:100%}.forgot-password-container{margin-top:.75rem}.additional-content-list{margin-top:.875rem}.forgot-password-container+.additional-content-list{margin-top:.65rem}}@media(max-width:480px){.logo-container,.title-container,.field{margin-bottom:1rem}.forgot-password-container,.forgot-password-link,.additional-content-item,.additional-content-link{font-size:.82rem}.additional-content-list{gap:.5rem}}\n"] }]
5484
6052
  }], ctorParameters: () => [{ type: i2.FormBuilder }], propDecorators: { loginPageConfig: [{
5485
6053
  type: Input
5486
6054
  }], loginErrorMessage: [{