@astryxdesign/lab 0.7.1-canary.e199fa4 → 0.7.1-canary.e71c4e9
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/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@astryxdesign/lab",
|
|
3
|
-
"version": "0.7.1-canary.
|
|
3
|
+
"version": "0.7.1-canary.e71c4e9",
|
|
4
4
|
"description": "Experimental Astryx components — published to npm only under the @canary dist-tag for early testing; never released as a stable (latest) version.",
|
|
5
5
|
"author": "Meta Open Source",
|
|
6
6
|
"license": "MIT",
|
|
@@ -47,7 +47,7 @@
|
|
|
47
47
|
},
|
|
48
48
|
"peerDependencies": {
|
|
49
49
|
"@stylexjs/stylex": ">=0.10.0",
|
|
50
|
-
"@astryxdesign/core": "0.7.1-canary.
|
|
50
|
+
"@astryxdesign/core": "0.7.1-canary.e71c4e9",
|
|
51
51
|
"react": ">=19.0.0",
|
|
52
52
|
"react-dom": ">=19.0.0"
|
|
53
53
|
},
|
|
@@ -57,8 +57,8 @@
|
|
|
57
57
|
"d3-shape": "^3.2.0"
|
|
58
58
|
},
|
|
59
59
|
"devDependencies": {
|
|
60
|
-
"@astryxdesign/a11y-spec": "0.7.1-canary.
|
|
61
|
-
"@astryxdesign/cli": "0.7.1-canary.
|
|
60
|
+
"@astryxdesign/a11y-spec": "0.7.1-canary.e71c4e9",
|
|
61
|
+
"@astryxdesign/cli": "0.7.1-canary.e71c4e9",
|
|
62
62
|
"@babel/cli": "^7.29.7",
|
|
63
63
|
"@babel/core": "^7.29.7",
|
|
64
64
|
"@babel/preset-react": "^7.29.7",
|
|
@@ -634,6 +634,103 @@ describe('Schedule', () => {
|
|
|
634
634
|
});
|
|
635
635
|
});
|
|
636
636
|
|
|
637
|
+
describe('Schedule across a midnight that daylight saving skips', () => {
|
|
638
|
+
// Both zones spring forward at local midnight: the day starts at 01:00.
|
|
639
|
+
const cases = [
|
|
640
|
+
{
|
|
641
|
+
timezoneID: 'America/Santiago',
|
|
642
|
+
date: Date.UTC(2026, 8, 8, 15),
|
|
643
|
+
week: [
|
|
644
|
+
'Sunday, September 6, 2026',
|
|
645
|
+
'Monday, September 7, 2026',
|
|
646
|
+
'Tuesday, September 8, 2026',
|
|
647
|
+
'Wednesday, September 9, 2026',
|
|
648
|
+
'Thursday, September 10, 2026',
|
|
649
|
+
'Friday, September 11, 2026',
|
|
650
|
+
'Saturday, September 12, 2026',
|
|
651
|
+
],
|
|
652
|
+
},
|
|
653
|
+
{
|
|
654
|
+
timezoneID: 'America/Havana',
|
|
655
|
+
date: Date.UTC(2026, 2, 10, 15),
|
|
656
|
+
week: [
|
|
657
|
+
'Sunday, March 8, 2026',
|
|
658
|
+
'Monday, March 9, 2026',
|
|
659
|
+
'Tuesday, March 10, 2026',
|
|
660
|
+
'Wednesday, March 11, 2026',
|
|
661
|
+
'Thursday, March 12, 2026',
|
|
662
|
+
'Friday, March 13, 2026',
|
|
663
|
+
'Saturday, March 14, 2026',
|
|
664
|
+
],
|
|
665
|
+
},
|
|
666
|
+
];
|
|
667
|
+
const renderPopover = () => null;
|
|
668
|
+
const dayGroups = () =>
|
|
669
|
+
screen
|
|
670
|
+
.getAllByRole('group')
|
|
671
|
+
.map(group => group.getAttribute('aria-label') ?? '')
|
|
672
|
+
.filter(name => /, \d{4}$/u.test(name));
|
|
673
|
+
|
|
674
|
+
it.each(cases)(
|
|
675
|
+
'keeps seven days in the week and one in the day view in $timezoneID',
|
|
676
|
+
({timezoneID, date, week}) => {
|
|
677
|
+
const {unmount} = render(
|
|
678
|
+
<Schedule
|
|
679
|
+
view={createScheduleWeeklyView({renderPopover})}
|
|
680
|
+
events={[]}
|
|
681
|
+
date={date}
|
|
682
|
+
timezoneID={timezoneID}
|
|
683
|
+
/>,
|
|
684
|
+
);
|
|
685
|
+
expect(dayGroups()).toEqual(week);
|
|
686
|
+
unmount();
|
|
687
|
+
render(
|
|
688
|
+
<Schedule
|
|
689
|
+
view={createScheduleDayView({renderPopover})}
|
|
690
|
+
events={[]}
|
|
691
|
+
date={date - 2 * 24 * 60 * 60 * 1000}
|
|
692
|
+
timezoneID={timezoneID}
|
|
693
|
+
/>,
|
|
694
|
+
);
|
|
695
|
+
expect(dayGroups()).toEqual([week[0]]);
|
|
696
|
+
},
|
|
697
|
+
);
|
|
698
|
+
|
|
699
|
+
it('keeps seven days in the week and one in the day view that end at the skipped midnight', () => {
|
|
700
|
+
// Santiago's week of Sunday, August 30, 2026 ends on Saturday, September 5;
|
|
701
|
+
// its end is the start of September 6, a midnight that never happens.
|
|
702
|
+
const timezoneID = 'America/Santiago';
|
|
703
|
+
const date = Date.UTC(2026, 8, 5, 15);
|
|
704
|
+
const {unmount} = render(
|
|
705
|
+
<Schedule
|
|
706
|
+
view={createScheduleWeeklyView({renderPopover})}
|
|
707
|
+
events={[]}
|
|
708
|
+
date={date}
|
|
709
|
+
timezoneID={timezoneID}
|
|
710
|
+
/>,
|
|
711
|
+
);
|
|
712
|
+
expect(dayGroups()).toEqual([
|
|
713
|
+
'Sunday, August 30, 2026',
|
|
714
|
+
'Monday, August 31, 2026',
|
|
715
|
+
'Tuesday, September 1, 2026',
|
|
716
|
+
'Wednesday, September 2, 2026',
|
|
717
|
+
'Thursday, September 3, 2026',
|
|
718
|
+
'Friday, September 4, 2026',
|
|
719
|
+
'Saturday, September 5, 2026',
|
|
720
|
+
]);
|
|
721
|
+
unmount();
|
|
722
|
+
render(
|
|
723
|
+
<Schedule
|
|
724
|
+
view={createScheduleDayView({renderPopover})}
|
|
725
|
+
events={[]}
|
|
726
|
+
date={date}
|
|
727
|
+
timezoneID={timezoneID}
|
|
728
|
+
/>,
|
|
729
|
+
);
|
|
730
|
+
expect(dayGroups()).toEqual(['Saturday, September 5, 2026']);
|
|
731
|
+
});
|
|
732
|
+
});
|
|
733
|
+
|
|
637
734
|
describe('sortEvents', () => {
|
|
638
735
|
it('sorts mixed all-day and instant events by start time', () => {
|
|
639
736
|
const sortedEvents = sortEvents(
|
|
@@ -0,0 +1,113 @@
|
|
|
1
|
+
// Copyright (c) Meta Platforms, Inc. and affiliates.
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* @file ScheduleTimeGridSkippedMidnight.a11y.chromium.spec.ts
|
|
5
|
+
* @input The built Lab/Schedule SkippedMidnight story in real Chromium
|
|
6
|
+
* @output Receipted evidence that a week and a day whose midnight daylight
|
|
7
|
+
* saving skips keep their own dates: seven day columns in the week, one in
|
|
8
|
+
* the day view, in America/Santiago and America/Havana
|
|
9
|
+
* @position Browser binding for `component:Schedule` FR8 (no event or day is
|
|
10
|
+
* dropped) across a skipped midnight
|
|
11
|
+
*/
|
|
12
|
+
|
|
13
|
+
import {expect, test, type Page} from '@playwright/test';
|
|
14
|
+
import {
|
|
15
|
+
finishEvidence,
|
|
16
|
+
record,
|
|
17
|
+
startEvidence,
|
|
18
|
+
storyUrl,
|
|
19
|
+
WIDE,
|
|
20
|
+
type Evidence,
|
|
21
|
+
} from './timeGridProbe';
|
|
22
|
+
|
|
23
|
+
const STORY = 'lab-schedule--skipped-midnight';
|
|
24
|
+
const ZONES = [
|
|
25
|
+
{
|
|
26
|
+
timezoneID: 'America/Santiago',
|
|
27
|
+
week: [
|
|
28
|
+
'Sunday, September 6, 2026',
|
|
29
|
+
'Monday, September 7, 2026',
|
|
30
|
+
'Tuesday, September 8, 2026',
|
|
31
|
+
'Wednesday, September 9, 2026',
|
|
32
|
+
'Thursday, September 10, 2026',
|
|
33
|
+
'Friday, September 11, 2026',
|
|
34
|
+
'Saturday, September 12, 2026',
|
|
35
|
+
],
|
|
36
|
+
},
|
|
37
|
+
{
|
|
38
|
+
timezoneID: 'America/Havana',
|
|
39
|
+
week: [
|
|
40
|
+
'Sunday, March 8, 2026',
|
|
41
|
+
'Monday, March 9, 2026',
|
|
42
|
+
'Tuesday, March 10, 2026',
|
|
43
|
+
'Wednesday, March 11, 2026',
|
|
44
|
+
'Thursday, March 12, 2026',
|
|
45
|
+
'Friday, March 13, 2026',
|
|
46
|
+
'Saturday, March 14, 2026',
|
|
47
|
+
],
|
|
48
|
+
},
|
|
49
|
+
] as const;
|
|
50
|
+
|
|
51
|
+
let evidence: Evidence;
|
|
52
|
+
|
|
53
|
+
/** The story holds four schedules, so wait for each zone's pair. */
|
|
54
|
+
async function openSkippedMidnight(page: Page, globals?: string) {
|
|
55
|
+
await page.setViewportSize(WIDE);
|
|
56
|
+
await page.goto(storyUrl(evidence, STORY, globals), {waitUntil: 'load'});
|
|
57
|
+
await expect(page.locator('.astryx-schedule')).toHaveCount(4);
|
|
58
|
+
await page.evaluate(() => document.fonts.ready);
|
|
59
|
+
await page.waitForTimeout(100);
|
|
60
|
+
}
|
|
61
|
+
test.beforeAll(async () => {
|
|
62
|
+
evidence = await startEvidence();
|
|
63
|
+
});
|
|
64
|
+
test.afterAll(async () => {
|
|
65
|
+
await finishEvidence(evidence, 'skipped-midnight');
|
|
66
|
+
});
|
|
67
|
+
|
|
68
|
+
for (const [direction, globals] of [
|
|
69
|
+
['ltr', undefined],
|
|
70
|
+
['rtl', 'direction:rtl'],
|
|
71
|
+
] as const) {
|
|
72
|
+
test(`a skipped midnight keeps seven days in the week and one in the day view (${direction})`, async ({
|
|
73
|
+
page,
|
|
74
|
+
}) => {
|
|
75
|
+
await openSkippedMidnight(page, globals);
|
|
76
|
+
const readings = [];
|
|
77
|
+
for (const zone of ZONES) {
|
|
78
|
+
const section = page.getByRole('region', {name: zone.timezoneID});
|
|
79
|
+
const grids = section.getByRole('grid', {name: 'Schedule time grid'});
|
|
80
|
+
await expect(grids).toHaveCount(2);
|
|
81
|
+
const days = async (index: number) =>
|
|
82
|
+
(
|
|
83
|
+
await grids
|
|
84
|
+
.nth(index)
|
|
85
|
+
.getByRole('columnheader')
|
|
86
|
+
.evaluateAll(headers =>
|
|
87
|
+
headers.map(header => header.textContent?.trim() ?? ''),
|
|
88
|
+
)
|
|
89
|
+
).filter(name => /, \d{4}$/u.test(name));
|
|
90
|
+
const week = await days(0);
|
|
91
|
+
const day = await days(1);
|
|
92
|
+
// The first hour's event paints in the first day's column.
|
|
93
|
+
const firstHour = await section
|
|
94
|
+
.getByText('First hour', {exact: true})
|
|
95
|
+
.first()
|
|
96
|
+
.isVisible();
|
|
97
|
+
readings.push({zone: zone.timezoneID, week, day, firstHour});
|
|
98
|
+
expect(week, `${zone.timezoneID} week`).toEqual([...zone.week]);
|
|
99
|
+
expect(day, `${zone.timezoneID} day`).toEqual([zone.week[0]]);
|
|
100
|
+
expect(firstHour, `${zone.timezoneID} first hour painted`).toBe(true);
|
|
101
|
+
}
|
|
102
|
+
await record(
|
|
103
|
+
evidence,
|
|
104
|
+
page,
|
|
105
|
+
`skipped-midnight-${direction}`,
|
|
106
|
+
STORY,
|
|
107
|
+
direction,
|
|
108
|
+
{
|
|
109
|
+
readings,
|
|
110
|
+
},
|
|
111
|
+
);
|
|
112
|
+
});
|
|
113
|
+
}
|