fix: Dialog focus issues (#2908)

## Description

closes #2889

## Steps for reproduction

1. click button
2. expect xyz

## Code Review

- [ ] hi @kof, I need you to do
  - conceptual review (architecture, feature-correctness)
  - detailed review (read every line)
  - test it on preview

## Before requesting a review

- [ ] made a self-review
- [ ] added inline comments where things may be not obvious (the "why",
not "what")

## Before merging

- [ ] tested locally and on preview environment (preview dev login:
5de6)
- [ ] updated [test
cases](https://github.com/webstudio-is/webstudio/blob/main/apps/builder/docs/test-cases.md)
document
- [ ] added tests
- [ ] if any new env variables are added, added them to `.env.example`
and the `builder/env-check.js` if mandatory
This commit is contained in:
Ivan Starkov authored and GitHub committed 2024-02-13 20:40:28 +03:00
1 parent 2e5e116b47
commit e67b13d64d
2 files changed
+38 -1

No files matched your search

@@ -9,6 +9,7 @@ export const SelectControl = ({
property,
currentStyle,
setProperty,
deleteProperty,
items,
}: ControlProps) => {
const { items: defaultItems } = styleConfigByName(property);
@@ -48,7 +49,7 @@ export const SelectControl = ({
onOpenChange={(isOpen) => {
// Remove ephemeral changes when closing the menu.
if (isOpen === false && styleValue !== undefined) {
setValue(styleValue, { isEphemeral: true });
deleteProperty(property, { isEphemeral: true });
}
}}
/>
+36
View File
@@ -116,7 +116,43 @@ const subscribePreviewMode = () => {
const subscribeEphemeralStyle = (params: Params) => {
// track custom properties added on previous ephemeral styles change
const addedCustomProperties = new Set<string>();
let timeoutHandle: number | undefined = undefined;
const resetInert = () => {
document.body.removeAttribute("inert");
clearTimeout(timeoutHandle);
timeoutHandle = undefined;
};
// 1000 ms is a reasonable time for the preview to reset.
// Anyway should never happen after user has finished preview changes (can happen during preview changes)
const AUTO_DISPOSE_INERT_TIMEOUT = 1000;
// A brief delay to ensure mutation observers within the focus scope are activated by the preview changes.
const DISPOSE_INERT_TIMEOUT = 300;
const setAutoDisposeInert = (timeout: number) => {
document.body.setAttribute("inert", "true");
// To prevent a completely non-interactive canvas due to edge cases,
// make sure to clean up preview changes if preview styles fail to reset correctly.
clearTimeout(timeoutHandle);
timeoutHandle = window.setTimeout(resetInert, timeout);
};
return $ephemeralStyles.subscribe((ephemeralStyles) => {
// Controls (e.g., radix focus scope) may inadvertently shift focus from inputs.
// Currently, there's no way to block focus shifts inside iframes (see https://github.com/w3c/webappsec-permissions-policy/issues/273 for future updates).
// Workaround: use the `inert` attribute on iframe body to prevent focus changes.
if (ephemeralStyles.length > 0) {
setAutoDisposeInert(AUTO_DISPOSE_INERT_TIMEOUT);
} else {
// Delayed reset same as set with smaller timeout
setAutoDisposeInert(DISPOSE_INERT_TIMEOUT);
}
// track custom properties not set on this change
const deletedCustomProperties = new Set(addedCustomProperties);