⚠ This page is served via a proxy. Original site: https://github.com
This service does not collect credentials or authentication data.
Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Original file line number Diff line number Diff line change
Expand Up @@ -1337,9 +1337,9 @@ describe('Appointment Form', () => {
scheduler.showAppointmentPopup();

expect(POM.popup.isMainGroupVisible()).toBe(true);
expect(POM.popup.mainGroup?.getAttribute('tabindex')).toBeNull();
expect(POM.popup.mainGroup?.getAttribute('inert')).toBeNull();
expect(POM.popup.isRecurrenceGroupVisible()).toBe(false);
expect(POM.popup.recurrenceGroup?.getAttribute('tabindex')).toBe('-1');
expect(POM.popup.recurrenceGroup?.getAttribute('inert')).toBe('true');

POM.popup.selectRepeatValue('weekly');
await new Promise(process.nextTick);
Expand All @@ -1349,17 +1349,17 @@ describe('Appointment Form', () => {
expect(typeof popupHeight).toBe('number');

expect(POM.popup.isMainGroupVisible()).toBe(false);
expect(POM.popup.mainGroup?.getAttribute('tabindex')).toBe('-1');
expect(POM.popup.mainGroup?.getAttribute('inert')).toBe('true');
expect(POM.popup.isRecurrenceGroupVisible()).toBe(true);
expect(POM.popup.recurrenceGroup?.getAttribute('tabindex')).toBeNull();
expect(POM.popup.recurrenceGroup?.getAttribute('inert')).toBeNull();

POM.popup.getBackButton().click();

expect(POM.popup.component.option('height')).toBe('auto');
expect(POM.popup.isMainGroupVisible()).toBe(true);
expect(POM.popup.mainGroup?.getAttribute('tabindex')).toBeNull();
expect(POM.popup.mainGroup?.getAttribute('inert')).toBeNull();
expect(POM.popup.isRecurrenceGroupVisible()).toBe(false);
expect(POM.popup.recurrenceGroup?.getAttribute('tabindex')).toBe('-1');
expect(POM.popup.recurrenceGroup?.getAttribute('inert')).toBe('true');
});

it('should open main form when opening recurring appointment', async () => {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,7 @@ const CLASSES = {
form: 'dx-scheduler-form',
icon: 'dx-icon',
hidden: 'dx-hidden',
fieldItemContent: 'dx-field-item-content',

groupWithIcon: 'dx-scheduler-form-group-with-icon',
formIcon: 'dx-scheduler-form-icon',
Expand Down Expand Up @@ -858,6 +859,8 @@ export class AppointmentForm {
}

showMainGroup(): void {
this._popup.updateToolbarForMainGroup();

const currentHeight = this.dxPopup.option('height') as string | number | undefined;
const editingConfig = this.scheduler.getEditingConfig();
const configuredHeight = editingConfig?.popup?.height ?? 'auto';
Expand All @@ -866,28 +869,40 @@ export class AppointmentForm {
this.dxPopup.option('height', configuredHeight);
}

this._$mainGroup?.removeClass(CLASSES.mainHidden);
this._$mainGroup?.removeAttr('tabindex');
this._$recurrenceGroup?.addClass(CLASSES.recurrenceHidden);
this._$recurrenceGroup?.attr('tabindex', '-1');
if (this._$mainGroup) {
this._$mainGroup.removeClass(CLASSES.mainHidden);
this._$mainGroup.removeAttr('inert');

this._popup.updateToolbarForMainGroup();
this.focusFirstFocusableInGroup(this._$mainGroup);
}

if (this._$recurrenceGroup) {
this._$recurrenceGroup.addClass(CLASSES.recurrenceHidden);
this._$recurrenceGroup.attr('inert', true);
}
}

showRecurrenceGroup(): void {
this._popup.updateToolbarForRecurrenceGroup();

const currentHeight = this.dxPopup.option('height') as string | number | undefined;

if (currentHeight === 'auto' || currentHeight === undefined) {
const overlayHeight = this.dxPopup.$overlayContent().get(0).clientHeight;
this.dxPopup.option('height', overlayHeight);
}

this._$mainGroup?.addClass(CLASSES.mainHidden);
this._$mainGroup?.attr('tabindex', '-1');
this._$recurrenceGroup?.removeClass(CLASSES.recurrenceHidden);
this._$recurrenceGroup?.removeAttr('tabindex');
if (this._$mainGroup) {
this._$mainGroup.addClass(CLASSES.mainHidden);
this._$mainGroup.attr('inert', true);
}

if (this._$recurrenceGroup) {
this._$recurrenceGroup.removeClass(CLASSES.recurrenceHidden);
this._$recurrenceGroup.removeAttr('inert');

this._popup.updateToolbarForRecurrenceGroup();
this.focusFirstFocusableInGroup(this._$recurrenceGroup);
}
}

saveRecurrenceValue(): void {
Expand Down Expand Up @@ -1006,4 +1021,9 @@ export class AppointmentForm {
this.dxForm.itemOption(endTimeItemName, 'visible', visible);
this.dxForm.endUpdate();
}

private focusFirstFocusableInGroup($group: dxElementWrapper): void {
const focusTarget = $group.find(`.${CLASSES.fieldItemContent} [tabindex]`).first().get(0) as HTMLElement;
focusTarget?.focus({ preventScroll: true });
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -269,6 +269,10 @@ export class RecurrenceForm {
}

private createRecurrenceRuleGroup(): GroupItem {
// Change of frequency editor's value causes rerender of the recurrencePatternGroup.
// To prevent focus loss in this editor, we use this flag.
let needRestoreFrequencyEditorFocus = false;
Copy link
Contributor Author

@Tucchhaa Tucchhaa Jan 16, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The reason of focus loss is because recurrencePatternGroup group gets rerendered when updateDayEditorsVisibility() is called.

Another solution is to wrap weekGroup, monthGroup and yearGroup into different group here.

I have decided to use this flag, because it's used in very narrow scope and because form items already have very deep nesting (docs).

But if you have any objections, let's discuss it :)


return {
itemType: 'group',
name: GROUP_NAMES.recurrenceRuleRepeatGroup,
Expand Down Expand Up @@ -314,6 +318,13 @@ export class RecurrenceForm {
displayExpr: 'text',
onContentReady: (e): void => {
e.component.option('value', this.recurrenceRule.frequency);

if (needRestoreFrequencyEditorFocus) {
setTimeout(() => {
e.component.focus();
needRestoreFrequencyEditorFocus = false;
});
}
},
onValueChanged: (e): void => {
const previousValue = this.recurrenceRule.frequency;
Expand All @@ -322,6 +333,10 @@ export class RecurrenceForm {
return;
}

if (e.event) {
needRestoreFrequencyEditorFocus = true;
}

this.recurrenceRule.frequency = e.value;
this.updateDayEditorsVisibility();
},
Expand Down
Loading