Skip to content

Commit 8158cbd

Browse files
Copilotdesig9stein
andcommitted
Cherry-pick PR #16618: fix date styles and formatting for Calendar component
Co-authored-by: desig9stein <[email protected]>
1 parent 2e15d88 commit 8158cbd

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/src/lib/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/src/lib/calendar/days-view/days-view.component.spec.ts

Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@ import { UIInteractions } from "../../test-utils/ui-interactions.spec";
66
import { CalendarDay } from "../common/model";
77
import { DateRangeDescriptor, DateRangeType } from 'igniteui-webcomponents';
88
import { ScrollDirection } from "../calendar";
9+
import { DayDigitPipe } from "../day-digit.pipe";
910

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

@@ -110,6 +111,37 @@ describe("Days View Component", () => {
110111
}
111112
});
112113

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

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

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -35,6 +35,7 @@ import {
3535
} from "../common/helpers";
3636
import { CalendarDay } from '../common/model';
3737
import {IgxTheme, THEME_TOKEN, ThemeToken} from "../../services/theme/theme.token";
38+
import { DayDigitPipe } from "../day-digit.pipe";
3839

3940
let NEXT_ID = 0;
4041

@@ -49,7 +50,7 @@ let NEXT_ID = 0;
4950
selector: 'igx-days-view',
5051
templateUrl: 'days-view.component.html',
5152
changeDetection: ChangeDetectionStrategy.OnPush,
52-
imports: [IgxDayItemComponent, TitleCasePipe]
53+
imports: [IgxDayItemComponent, TitleCasePipe, DayDigitPipe]
5354
})
5455
export class IgxDaysViewComponent extends IgxCalendarBaseDirective implements AfterContentChecked {
5556
#standalone = true;

projects/igniteui-angular/src/lib/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
@@ -16,6 +16,7 @@ import {
1616
IViewDateChangeEventArgs,
1717
IgxCalendarView,
1818
IFormattingOptions,
19+
IFormattingViews,
1920
DateRange,
2021
DateRangeDescriptor,
2122
DateRangeType,
@@ -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)