Skip to content

Commit 6ec8ad4

Browse files
committed
fix(calendar-beta): Remove slotted days, as it was causing flickering
1 parent b4dda0e commit 6ec8ad4

File tree

6 files changed

+58
-165
lines changed

6 files changed

+58
-165
lines changed

packages/genesys-spark-components/src/components/beta/gux-calendar-beta/example.html

+6-25
Original file line numberDiff line numberDiff line change
@@ -5,25 +5,6 @@ <h2>Single Date Selection</h2>
55
<input type="date" value="2023-05-19" />
66
</gux-calendar-beta>
77

8-
<h2>Customized Date Styles</h2>
9-
<style>
10-
.my-custom-day:not([gux-selected]) {
11-
background: red;
12-
}
13-
14-
.my-custom-day:focus-within {
15-
outline-color: green;
16-
}
17-
</style>
18-
<gux-calendar-beta oninput="notify(event)">
19-
<input type="date" value="2023-05-19" min="2023-05-10" />
20-
<gux-day-beta
21-
slot="2023-05-15"
22-
day="2023-05-15"
23-
class="my-custom-day"
24-
></gux-day-beta>
25-
</gux-calendar-beta>
26-
278
<h2>Empty Date Selection</h2>
289
<gux-calendar-beta oninput="notify(event)">
2910
<input type="date" />
@@ -38,20 +19,20 @@ <h2>Start day of week</h2>
3819
<div class="container">
3920
<div class="item">
4021
<h3>Monday</h3>
41-
<gux-calendar-beta oninput="notify(event)">
42-
<input type="date" value="2023-07-28" start-day-of-week="1" />
22+
<gux-calendar-beta start-day-of-week="1" oninput="notify(event)">
23+
<input type="date" value="2023-07-28" />
4324
</gux-calendar-beta>
4425
</div>
4526
<div class="item">
4627
<h3>Saturday</h3>
47-
<gux-calendar-beta oninput="notify(event)">
48-
<input type="date" value="2023-07-28" start-day-of-week="6" />
28+
<gux-calendar-beta start-day-of-week="6" oninput="notify(event)">
29+
<input type="date" value="2023-07-28" />
4930
</gux-calendar-beta>
5031
</div>
5132
<div class="item">
5233
<h3>Sunday</h3>
53-
<gux-calendar-beta oninput="notify(event)">
54-
<input type="date" value="2023-07-28" start-day-of-week="7" />
34+
<gux-calendar-beta start-day-of-week="7" oninput="notify(event)">
35+
<input type="date" value="2023-07-28" />
5536
</gux-calendar-beta>
5637
</div>
5738
</div>

packages/genesys-spark-components/src/components/beta/gux-calendar-beta/gux-calendar.tsx

+48-69
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,14 @@
1-
import { Component, Element, h, JSX, Listen, State } from '@stencil/core';
1+
import {
2+
Component,
3+
Element,
4+
forceUpdate,
5+
h,
6+
JSX,
7+
Listen,
8+
Method,
9+
Prop,
10+
State
11+
} from '@stencil/core';
212
import { IWeekElement, GuxCalendarDayOfWeek } from './gux-calendar.types';
313
import {
414
getWeekdays,
@@ -27,6 +37,17 @@ export class GuxCalendar {
2737
@Element()
2838
root: HTMLElement;
2939

40+
// The start day of the week based on user's locale
41+
// Some locales will have the start day of the week be different than others
42+
@Prop()
43+
startDayOfWeek: GuxCalendarDayOfWeek;
44+
45+
@Method()
46+
async guxForceUpdate(): Promise<void> {
47+
this.readSlottedInputState();
48+
forceUpdate(this.root);
49+
}
50+
3051
/**
3152
* The date that receives focus when selecting a specific day. This also
3253
* determines what month is currently displayed. The corresponding element
@@ -56,14 +77,21 @@ export class GuxCalendar {
5677
// Total number of dates that will display for each month in the calendar
5778
private MONTH_DATE_COUNT: number = 42;
5879

59-
// Keeps track of the start day of the week based on user's locale
60-
// Some locales will have the start day of the week be different than others
61-
private startDayOfWeek: GuxCalendarDayOfWeek;
62-
6380
private get slottedInput(): HTMLInputElement {
6481
return this.root.querySelector('input[type="date"]');
6582
}
6683

84+
private readSlottedInputState(): void {
85+
// Set min value from the "min" input prop
86+
if (this.slottedInput.min) {
87+
this.minValue = Temporal.PlainDate.from(this.slottedInput.min);
88+
}
89+
// Set max value from the "max" input prop
90+
if (this.slottedInput.max) {
91+
this.maxValue = Temporal.PlainDate.from(this.slottedInput.max);
92+
}
93+
}
94+
6795
async componentWillLoad(): Promise<void> {
6896
if (!this.slottedInput) {
6997
logError(
@@ -75,13 +103,6 @@ export class GuxCalendar {
75103
this.locale = getDesiredLocale(this.root);
76104

77105
// Set start day of week
78-
const startDayOfWeek = this.slottedInput.getAttribute('start-day-of-week');
79-
if (startDayOfWeek?.length) {
80-
this.startDayOfWeek = parseInt(
81-
startDayOfWeek,
82-
10
83-
) as GuxCalendarDayOfWeek;
84-
}
85106
this.startDayOfWeek = this.startDayOfWeek || getFirstDayOfWeek(this.locale);
86107

87108
this.i18n = await buildI18nForComponent(this.root, translationResources);
@@ -91,71 +112,29 @@ export class GuxCalendar {
91112
this.focusDate = selectedDate;
92113
}
93114

94-
// Set min value from the "min" input prop
95-
if (this.slottedInput.min) {
96-
this.minValue = Temporal.PlainDate.from(this.slottedInput.min);
97-
}
98-
// Set max value from the "max" input prop
99-
if (this.slottedInput.max) {
100-
this.maxValue = Temporal.PlainDate.from(this.slottedInput.max);
101-
}
102-
}
103-
104-
async componentDidRender() {
105-
// Because the selection state may be set on slotted attributes, we have
106-
// to update it after rendering.
107-
this.renderDateSelection();
115+
this.readSlottedInputState();
108116
}
109117

110118
/**
111119
* Finds the `gux-day` element corresponding to the provided
112-
* date string, whether rendered by this component or slotted.
120+
* date string.
113121
* @param dateStr The date to find in ISO format
114122
*/
115123
private getGuxDayForDate(dateStr: string): HTMLElement | null {
116-
return (
117-
this.root.shadowRoot
118-
// Find the slot for the date
119-
.querySelector<HTMLSlotElement>(`slot[name="${dateStr}"]`)
120-
// Get the first of the rendered items for that slot
121-
?.assignedNodes({ flatten: true })[0] as HTMLElement
122-
);
124+
return this.root.shadowRoot.querySelector(`.day-${dateStr}`);
123125
}
124126

125127
private selectDate(date: Temporal.PlainDate): void {
126128
if (this.isInvalidDate(date)) {
127129
return;
128130
}
129-
const oldDateStr = this.slottedInput.value;
130131
const newDateStr = date.toString();
131132
this.focusDate = date;
132133
this.slottedInput.value = newDateStr;
133134

134-
afterNextRenderTimeout(() => {
135-
this.renderDateSelection(oldDateStr);
136-
});
137-
138135
simulateNativeEvent(this.root, 'input');
139136
}
140137

141-
/**
142-
* Clears the `gux-selected` attribute on the old element and add it
143-
* to the new element. This enables styling of the selected state in
144-
* the gux-day element in a way that can be used by slotted elements.
145-
*/
146-
private renderDateSelection(oldDateStr?: string): void {
147-
const selectedDate = this.getSelectedDate();
148-
if (oldDateStr) {
149-
const oldSelectedElement = this.getGuxDayForDate(oldDateStr);
150-
oldSelectedElement?.removeAttribute('gux-selected');
151-
}
152-
153-
if (selectedDate) {
154-
const newSelectedElement = this.getGuxDayForDate(selectedDate.toString());
155-
newSelectedElement?.setAttribute('gux-selected', '');
156-
}
157-
}
158-
159138
/**
160139
* Shifts the focused date by the provided interval
161140
* @param interval A Temporal-compatible interval definition
@@ -347,20 +326,16 @@ export class GuxCalendar {
347326
{week.dates.map(day => {
348327
const isoDateStr = day.date.toString();
349328
return (
350-
<gux-focus-proxy
329+
<gux-day-beta
330+
day={isoDateStr}
351331
aria-current={day.selected ? 'true' : 'false'}
352332
aria-disabled={day.disabled ? 'true' : 'false'}
353333
tabindex={day.selected || day.focused ? '0' : '-1'}
354-
>
355-
<slot key={isoDateStr} name={isoDateStr}>
356-
<gux-day-beta
357-
day={isoDateStr}
358-
class={{
359-
'gux-muted': !day.inCurrentMonth || day.disabled
360-
}}
361-
></gux-day-beta>
362-
</slot>
363-
</gux-focus-proxy>
334+
class={`
335+
${!day.inCurrentMonth || day.disabled ? 'gux-muted' : ''}
336+
day-${isoDateStr}
337+
`}
338+
></gux-day-beta>
364339
) as JSX.Element;
365340
})}
366341
</div>
@@ -375,7 +350,11 @@ export class GuxCalendar {
375350
render(): JSX.Element {
376351
return (
377352
<div class="gux-calendar-beta">
378-
<slot />
353+
<slot
354+
onSlotchange={() => {
355+
this.readSlottedInputState();
356+
}}
357+
/>
379358
{this.renderHeader()}
380359
{this.renderContent()}
381360
</div>

packages/genesys-spark-components/src/components/beta/gux-day/gux-day.scss

+1-1
Original file line numberDiff line numberDiff line change
@@ -26,7 +26,7 @@
2626
border-radius: var(--gse-ui-calendarMenu-month-focusBorderRadius);
2727
}
2828

29-
:host([gux-selected]) {
29+
:host([aria-current='true']) {
3030
color: var(--gse-ui-calendarMenu-date-selected-foregroundColor);
3131
background-color: var(--gse-ui-calendarMenu-date-selected-backgroundColor);
3232
}

packages/genesys-spark-components/src/components/beta/gux-day/gux-day.tsx

+3-6
Original file line numberDiff line numberDiff line change
@@ -15,9 +15,8 @@ import { Temporal } from '@js-temporal/polyfill';
1515
import { formatPlainDate } from '@utils/date/temporal';
1616

1717
/**
18-
* The gux-day component is how we render a day within an calendar. Custom-styled
19-
* instances can be slotted in to exiting calendars by users of Spark, but it
20-
* should not be used stand-alone.
18+
* The gux-day component is how we render a day within an calendar. It should
19+
* not be used stand-alone.
2120
*/
2221
@Component({
2322
styleUrl: 'gux-day.scss',
@@ -74,9 +73,7 @@ export class GuxDay {
7473
return (
7574
<button onClick={() => this.daySelected.emit(this.day)} type="button">
7675
<slot>
77-
<span aria-hidden="true">
78-
{formatPlainDate(this.dayFormatter, this.date)}
79-
</span>
76+
<span aria-hidden="true">{this.date.day}</span>
8077
<span class="gux-sr-only">
8178
{formatPlainDate(this.readerFormatter, this.date)}
8279
</span>

packages/genesys-spark-components/src/components/utility/focus-proxy/focus-proxy.tsx

-25
This file was deleted.

packages/genesys-spark-components/src/components/utility/focus-proxy/readme.md

-39
This file was deleted.

0 commit comments

Comments
 (0)