diff --git a/src/lib/components/transitions/TransitionChild.svelte b/src/lib/components/transitions/TransitionChild.svelte index 9138b90..1c54ff3 100644 --- a/src/lib/components/transitions/TransitionChild.svelte +++ b/src/lib/components/transitions/TransitionChild.svelte @@ -40,16 +40,19 @@ const dispatch = createEventDispatcher(); let container: HTMLElement | null = null; - let state = TreeStates.Visible; let transitionContext = useTransitionContext(); let nestingContext = useParentNesting(); + let state = + $transitionContext.initialShow || $$props.unmount !== false + ? TreeStates.Visible + : TreeStates.Hidden; let initial = true; - let id = useId(); - let isTransitioning = false; + $: strategy = + $$props.unmount === false ? RenderStrategy.Hidden : RenderStrategy.Unmount; let nesting: Writable = writable( useNesting(() => { @@ -68,7 +71,7 @@ $: { (() => { // If we are in another mode than the Hidden mode then ignore - /* if (strategy.value !== RenderStrategy.Hidden) return */ + if (strategy !== RenderStrategy.Hidden) return; if (!id) return; // Make sure that we are visible @@ -90,13 +93,15 @@ .filter((className) => className.trim().length > 1); } - let enterClasses = splitClasses(enter); - let enterFromClasses = splitClasses(enterFrom); - let enterToClasses = splitClasses(enterTo); + $: enterClasses = splitClasses(enter); + $: enterFromClasses = splitClasses(enterFrom); + $: enterToClasses = splitClasses(enterTo); - let leaveClasses = splitClasses(leave); - let leaveFromClasses = splitClasses(leaveFrom); - let leaveToClasses = splitClasses(leaveTo); + $: enteredClasses = splitClasses(entered); + + $: leaveClasses = splitClasses(leave); + $: leaveFromClasses = splitClasses(leaveFrom); + $: leaveToClasses = splitClasses(leaveTo); let mounted = false; onMount(() => (mounted = true)); @@ -120,6 +125,7 @@ enterClasses, enterFromClasses, enterToClasses, + enteredClasses, (reason) => { isTransitioning = false; if (reason === Reason.Finished) dispatch("afterEnter"); @@ -130,6 +136,7 @@ leaveClasses, leaveFromClasses, leaveToClasses, + enteredClasses, (reason) => { isTransitioning = false; diff --git a/src/lib/components/transitions/TransitionRoot.svelte b/src/lib/components/transitions/TransitionRoot.svelte index 992e399..dd38d37 100644 --- a/src/lib/components/transitions/TransitionRoot.svelte +++ b/src/lib/components/transitions/TransitionRoot.svelte @@ -15,6 +15,12 @@ interface TransitionContextValues { show: boolean; appear: boolean; + // This is not part of base Headless UI, but we need it because TransitionRoot does not render. + // In base Headless UI, for a component with unmount=false, the initial state for the Child is + // still "visible". It still works, because the parent still is hidden and has display: none + // In our version the parent renders nothing, so we need to send down the correct initial state + // ourselves. + initialShow: boolean; } const TRANSITION_CONTEXT_NAME = "headlessui-transition-context"; @@ -148,6 +154,9 @@ show, openClosedState !== undefined ? $openClosedState : undefined ); + + let initialShow = shouldShow; + $: { shouldShow = computeShow( show, @@ -172,6 +181,7 @@ $: transitionBag.set({ show: !!shouldShow, appear: appear || !initial, + initialShow: !!initialShow, }); onMount(() => { diff --git a/src/lib/utils/transition.ts b/src/lib/utils/transition.ts index e7b8c2e..fc51bbd 100644 --- a/src/lib/utils/transition.ts +++ b/src/lib/utils/transition.ts @@ -62,12 +62,13 @@ export function transition( base: string[], from: string[], to: string[], + entered: string[], done?: (reason: Reason) => void ) { let d = disposables(); let _done = done !== undefined ? once(done) : () => { }; - removeClasses(node); + removeClasses(node, ...entered); addClasses(node, ...base, ...from); d.nextFrame(() => { @@ -77,6 +78,7 @@ export function transition( d.add( waitForTransition(node, (reason) => { removeClasses(node, ...to, ...base); + addClasses(node, ...entered); return _done(reason); }) );