-
Notifications
You must be signed in to change notification settings - Fork 77
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
feat(dialog): add focusTrapDisabled property for non-modal dialogs #11362
base: dev
Are you sure you want to change the base?
Changes from all commits
0439c86
702b4c8
61cb7b2
3fd589b
5225520
99aa605
7e910f6
a82272d
aa64339
66736a4
f4a4a99
bdf7a80
cf808df
278464f
0e2ab22
826d93f
0c7a4f9
2873183
5c11de0
ee12e16
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -187,6 +187,9 @@ export class Dialog | |
/** When `true`, displays a scrim blocking interaction underneath the component. */ | ||
@property({ reflect: true }) modal = false; | ||
|
||
/** When `true` and `modal` is `false`, prevents focus trapping. */ | ||
@property({ reflect: true }) focusTrapDisabled = false; | ||
|
||
/** When `true`, displays and positions the component. */ | ||
@property({ reflect: true }) | ||
get open(): boolean { | ||
|
@@ -270,6 +273,11 @@ export class Dialog | |
updateFocusTrapElements(this); | ||
} | ||
|
||
/** When defined, provides a condition to disable focus trapping. When `true`, prevents focus trapping. */ | ||
focusTrapDisabledOverride(): boolean { | ||
return !this.modal && this.focusTrapDisabled; | ||
} | ||
|
||
// #endregion | ||
|
||
// #region Events | ||
|
@@ -328,6 +336,9 @@ export class Dialog | |
if (changes.has("modal") && (this.hasUpdated || this.modal !== false)) { | ||
this.updateOverflowHiddenClass(); | ||
} | ||
if ((changes.has("modal") || changes.has("focusTrapDisabled")) && this.hasUpdated) { | ||
this.handleFocusTrapDisabled(); | ||
} | ||
|
||
if ( | ||
(changes.has("open") && (this.hasUpdated || this.open !== false)) || | ||
|
@@ -366,6 +377,15 @@ export class Dialog | |
// #endregion | ||
|
||
// #region Private Methods | ||
|
||
private handleFocusTrapDisabled(): void { | ||
if (!this.open) { | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. shouldn't it deactivate if not open? There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. The logic needs to handle changes to
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I think this hasn't been resolved yet. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I think the onOpen/onClose handles the deactivation part. We may not need this check at all. We can probably remove this function and call There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Gotcha. Sounds like There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Yeah, I think we handle that in multiple places. |
||
return; | ||
} | ||
|
||
activateFocusTrap(this); | ||
} | ||
|
||
private updateAssistiveText(): void { | ||
const { messages } = this; | ||
this.assistiveText = | ||
|
@@ -380,7 +400,7 @@ export class Dialog | |
|
||
onOpen(): void { | ||
this.calciteDialogOpen.emit(); | ||
activateFocusTrap(this); | ||
this.handleFocusTrapDisabled(); | ||
} | ||
|
||
onBeforeClose(): void { | ||
|
Elijbet marked this conversation as resolved.
Show resolved
Hide resolved
|
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -112,4 +112,37 @@ describe("focusTrapComponent", () => { | |
expect(customFocusTrapStack).toHaveLength(1); | ||
}); | ||
}); | ||
describe("focusTrapDisabledOverride", () => { | ||
it("should activate focus trap when focusTrapDisabledOverride returns false", () => { | ||
const fakeComponent = {} as FocusTrapComponent; | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Let's DRY test setup by using |
||
fakeComponent.el = document.createElement("div"); | ||
|
||
connectFocusTrap(fakeComponent); | ||
|
||
const activateSpy = vi.fn(); | ||
fakeComponent.focusTrap.activate = activateSpy; | ||
|
||
fakeComponent.focusTrapDisabledOverride = () => false; | ||
|
||
activateFocusTrap(fakeComponent); | ||
|
||
expect(activateSpy).toHaveBeenCalledTimes(1); | ||
}); | ||
|
||
it("should not activate focus trap when focusTrapDisabledOverride returns true", () => { | ||
const fakeComponent = {} as FocusTrapComponent; | ||
fakeComponent.el = document.createElement("div"); | ||
|
||
connectFocusTrap(fakeComponent); | ||
|
||
const activateSpy = vi.fn(); | ||
fakeComponent.focusTrap.activate = activateSpy; | ||
|
||
fakeComponent.focusTrapDisabledOverride = () => true; | ||
|
||
activateFocusTrap(fakeComponent); | ||
|
||
expect(activateSpy).toHaveBeenCalledTimes(0); | ||
}); | ||
}); | ||
}); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
For completeness, can you add tests that cover
focusTrapDisabled = false
?