Skip to content

Commit a666485

Browse files
authored
fix(calendar): fix date styles and formating (#16618)
* fix(calendar): ensure text in calendar components does not wrap unexpectedly * fix(calendar): update days formatting logic to extract day part and add additional locales in sample * fix(calendar): correct locale codes in sample for Chinese regions * fix(calendar): add DayDigitPipe to handle non-numeric day characters in locales like zh-CN - Introduced DayDigitPipe to strip non-numeric characters from localized day strings. - Updated `IgxDaysViewComponent` to use the new pipe in the day formatting logic. - Added a test to verify correct formatting for zh-CN locale. * chore(calendar): update DayDigitPipe paths - Updated `DayDigitPipe` import paths to use relative paths. * chore(calendar): mark DayDigitPipe as standalone
1 parent dcfd32b commit a666485

File tree

7 files changed

+75
-2
lines changed

7 files changed

+75
-2
lines changed
Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,26 @@
1+
import { Pipe, PipeTransform } from '@angular/core';
2+
import { IFormattingViews } from "./calendar";
3+
4+
@Pipe({
5+
name: 'dayDigit',
6+
standalone: true
7+
})
8+
export class DayDigitPipe implements PipeTransform {
9+
public transform(value: string, formatViews: IFormattingViews): string {
10+
if (!value) {
11+
return '';
12+
}
13+
14+
// strip non-numeric characters that might have been added by the locale formatter (e.g., "25日" -> "25").
15+
if (formatViews.day) {
16+
// Use regex to extract the numeric day value.
17+
// This handles locales that include non-numeric characters (e.g. '25日' in zh-CN).
18+
// match(/\d+/) is preferred over parseInt() as it robustly finds the digits regardless
19+
// of their position (prefix/suffix) in the localized string.
20+
const match = value.match(/\d+/);
21+
return match ? match[0] : value;
22+
}
23+
24+
return value;
25+
}
26+
}

projects/igniteui-angular/calendar/src/calendar/days-view/days-view.component.html

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -81,7 +81,7 @@
8181
(mouseEnter)="changePreviewRange(day.native)"
8282
(mouseLeave)="clearPreviewRange()"
8383
>
84-
{{ formattedDate(day.native) }}
84+
{{ formattedDate(day.native) | dayDigit:formatViews }}
8585
</igx-day-item>
8686
}
8787
</div>

projects/igniteui-angular/calendar/src/calendar/days-view/days-view.component.spec.ts

Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@ import { ScrollDirection } from "../calendar";
77
import { KeyboardNavigationService } from '../calendar.services';
88
import { CalendarDay } from 'igniteui-angular/core';
99
import { UIInteractions } from '../../../../test-utils/ui-interactions.spec';
10+
import { DayDigitPipe } from "igniteui-angular/calendar/src/calendar/day-digit.pipe";
1011

1112
const TODAY = new Date(2024, 6, 12);
1213

@@ -114,6 +115,37 @@ describe("Days View Component", () => {
114115
}
115116
});
116117

118+
it("should format date correctly for zh-CN locale programmatically vs template pipe", () => {
119+
const fixture = TestBed.createComponent(InitDaysViewComponent);
120+
const daysView = fixture.componentInstance.instance;
121+
const pipe = new DayDigitPipe();
122+
const date = new Date(2020, 10, 25); // Nov 25
123+
124+
// Initialize component
125+
daysView.formatViews = { day: true, month: true, year: true };
126+
fixture.detectChanges();
127+
128+
// Mock the formatter behavior
129+
// Simulate a locale (like zh-CN) that adds a suffix to the day number.
130+
// Cast to 'any' to overwrite the protected 'formatterDay' property used by formattedDate()
131+
(daysView as any).formatterDay = {
132+
format: () => '25日',
133+
} as Intl.DateTimeFormat;
134+
135+
// 1. Verify Programmatic Access (formattedDate method)
136+
// Should return the raw formatted string from the formatter (with suffix)
137+
const programmaticResult = daysView.formattedDate(date);
138+
expect(programmaticResult).toBe('25日', 'Programmatic API should return the full locale string (including suffix, in this case 日)');
139+
140+
// 2. Verify Pipe Logic
141+
// The pipe takes the formatted string "25日" and strips non-digits to return "25"
142+
const pipeResult = pipe.transform(programmaticResult, daysView.formatViews);
143+
expect(pipeResult).toBe('25', 'Pipe should strip non-numeric characters from the input string');
144+
145+
// 3. Confirm the difference implies the pipe did its job
146+
expect(programmaticResult).not.toEqual(pipeResult);
147+
});
148+
117149
describe("Keyboard navigation", () => {
118150
let fixture: ComponentFixture<InitDaysViewComponent>;
119151
let el: HTMLElement;

projects/igniteui-angular/calendar/src/calendar/days-view/days-view.component.ts

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -37,6 +37,7 @@ import {
3737
import { IgxCalendarBaseDirective } from '../calendar-base';
3838
import { IViewChangingEventArgs } from './days-view.interface';
3939
import { KeyboardNavigationService } from '../calendar.services';
40+
import { DayDigitPipe } from "../day-digit.pipe";
4041

4142
let NEXT_ID = 0;
4243

@@ -52,7 +53,7 @@ let NEXT_ID = 0;
5253
selector: 'igx-days-view',
5354
templateUrl: 'days-view.component.html',
5455
changeDetection: ChangeDetectionStrategy.OnPush,
55-
imports: [IgxDayItemComponent, TitleCasePipe]
56+
imports: [IgxDayItemComponent, TitleCasePipe, DayDigitPipe]
5657
})
5758
export class IgxDaysViewComponent extends IgxCalendarBaseDirective implements AfterContentChecked {
5859
protected el = inject(ElementRef);

projects/igniteui-angular/core/src/core/styles/components/calendar/_calendar-theme.scss

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2516,6 +2516,7 @@
25162516
letter-spacing: sizable(var(--ig-body-2-letter-spacing), var(--ig-body-2-letter-spacing), var(--ig-body-1-letter-spacing));
25172517
text-transform: sizable(var(--ig-body-2-text-transform), var(--ig-body-2-text-transform), var(--ig-body-1-text-transform));
25182518
margin: 0;
2519+
white-space: nowrap;
25192520
}
25202521
}
25212522

@@ -2528,6 +2529,7 @@
25282529
letter-spacing: sizable(var(--ig-body-2-letter-spacing), var(--ig-body-2-letter-spacing), var(--ig-body-1-letter-spacing));
25292530
text-transform: sizable(var(--ig-body-2-text-transform), var(--ig-body-2-text-transform), var(--ig-body-1-text-transform));
25302531
margin: 0;
2532+
white-space: nowrap;
25312533
}
25322534
}
25332535
}

src/app/calendar/calendar.sample.html

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,7 @@
1414
[showWeekNumbers]="properties.showWeekNumbers"
1515
[hasHeader]="!properties.hideHeader"
1616
[formatOptions]="formatOptions"
17+
[formatViews]="formatViews"
1718
[disabledDates]="disabledDates"
1819
[specialDates]="specialDates"
1920
(selected)="onSelection($event)"

src/app/calendar/calendar.sample.ts

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,7 @@ import {
1919
DateRange,
2020
DateRangeDescriptor,
2121
DateRangeType,
22+
IFormattingViews,
2223
} from 'igniteui-angular';
2324
import {
2425
Properties,
@@ -62,6 +63,12 @@ export class CalendarSampleComponent implements OnInit {
6263
year: 'numeric',
6364
};
6465

66+
protected formatViews: IFormattingViews = {
67+
day: true,
68+
month: true,
69+
year: true
70+
};
71+
6572
public panelConfig: PropertyPanelConfig = {
6673
locale: {
6774
label: 'Change Locale',
@@ -87,6 +94,10 @@ export class CalendarSampleComponent implements OnInit {
8794
{
8895
value: 'ja-JP',
8996
label: 'JP'
97+
},
98+
{
99+
value: 'zh-CN',
100+
label: 'CN'
90101
}
91102
],
92103
defaultValue: 'en-US'

0 commit comments

Comments
 (0)