Fixes to issues with Dialog, FocusTrap, and StackContextProvider

* StackContextProvider had some reactivity that didn't make sense and would cause an infinite loop if it ever triggered.
* FocusTrap and Dialog did not work together properly all of the time. A top-level <Dialog> with initial state of closed would not have the FocusTrap triggered correctly when it was opened. Needed to make it reactive to changes in `containers`
This commit is contained in:
Ryan Gossiaux
2021-12-26 16:28:37 -08:00
parent 10f2eab08d
commit a2745e1770
3 changed files with 12 additions and 14 deletions

View File

@@ -253,10 +253,11 @@
onUpdate={(message, element) => {
return match(message, {
[StackMessage.Add]() {
containers.add(element);
containers = new Set([...containers, element]);
},
[StackMessage.Remove]() {
containers.delete(element);
containers = new Set([...containers]);
},
});
}}

View File

@@ -7,7 +7,7 @@
FocusResult,
} from "$lib/utils/focus-management";
import { contains } from "$lib/internal/dom-containers";
import { afterUpdate, onMount, onDestroy, tick } from "svelte";
import { onMount, onDestroy, tick } from "svelte";
export let containers: Set<HTMLElement>;
export let enabled: boolean = true;
@@ -74,7 +74,7 @@
// Handle initial focus
onMount(handleFocus);
afterUpdate(() => (enabled ? handleFocus() : restore()));
$: enabled && containers ? handleFocus() : restore();
// When this component is being destroyed, focusElement is called
// before handleWindowFocus is removed, so in the svelte port we add this

View File

@@ -9,24 +9,21 @@
<script lang="ts">
import { getContext, onDestroy, setContext } from "svelte";
import { Readable, writable, Writable } from "svelte/store";
type OnUpdate = (message: StackMessage, element: HTMLElement) => void;
export let onUpdate: OnUpdate | undefined;
export let element: HTMLElement | null;
let parentUpdateStore: Readable<OnUpdate> | undefined =
getContext(STACK_CONTEXT_NAME);
let notifyStore: Writable<OnUpdate> = writable(() => {});
setContext(STACK_CONTEXT_NAME, notifyStore);
$: notifyStore.set((...args: Parameters<OnUpdate>) => {
function notify(...args: Parameters<OnUpdate>) {
// Notify our layer
onUpdate?.(...args);
// Notify the parent
$parentUpdateStore?.(...args);
});
parentUpdate?.(...args);
}
let parentUpdate: OnUpdate | undefined = getContext(STACK_CONTEXT_NAME);
setContext(STACK_CONTEXT_NAME, notify);
$: _cleanup = (() => {
if (_cleanup) {
@@ -34,8 +31,8 @@
}
if (!element) return null;
let savedElement = element;
$notifyStore(StackMessage.Add, savedElement);
return () => $notifyStore(StackMessage.Remove, savedElement);
notify(StackMessage.Add, savedElement);
return () => notify(StackMessage.Remove, savedElement);
})();
onDestroy(() => {