Files
svelte-headlessui/src/lib/components/transitions/TransitionRoot.svelte
Ryan Gossiaux cc27615e96 Add JSDoc comments
Yay
2022-03-18 11:19:25 -07:00

134 lines
3.4 KiB
Svelte

<script lang="ts" context="module">
export type TTransitionRootProps<
TAsProp extends SupportedAs,
TDefaultAs
> = TTransitionChildProps<TAsProp, TDefaultAs> & {
/** Whether the children should be shown */
show?: boolean;
/** Whether the transition should run on initial mount */
appear?: boolean;
};
</script>
<script lang="ts">
import { onMount, setContext } from "svelte";
import { writable } from "svelte/store";
import { match } from "$lib/utils/match";
import { State, useOpenClosed } from "$lib/internal/open-closed";
import TransitionChild, {
type TTransitionChildProps,
} from "$lib/components/transitions/TransitionChild.svelte";
import { forwardEventsBuilder } from "$lib/internal/forwardEventsBuilder";
import { get_current_component } from "svelte/internal";
import type { SupportedAs } from "$lib/internal/elements";
import type { HTMLActionArray } from "$lib/hooks/use-actions";
import type {
NestingContextValues,
TransitionContextValues,
} from "./common.svelte";
import {
hasChildren,
NESTING_CONTEXT_NAME,
TRANSITION_CONTEXT_NAME,
TreeStates,
useNesting,
} from "./common.svelte";
const forwardEvents = forwardEventsBuilder(get_current_component(), [
"beforeEnter",
"beforeLeave",
"afterEnter",
"afterLeave",
]);
/***** Props *****/
type TAsProp = $$Generic<SupportedAs>;
type $$Props = TTransitionRootProps<TAsProp, "div">;
export let as: SupportedAs = "div";
export let use: HTMLActionArray = [];
export let show: boolean | undefined = undefined;
export let appear = false;
/***** Events *****/
/***** Component *****/
let openClosedState = useOpenClosed();
function computeShow(
show: boolean | undefined,
openClosedState: State | undefined
): boolean | undefined {
if (show === undefined && openClosedState !== undefined) {
return match(openClosedState, {
[State.Open]: true,
[State.Closed]: false,
});
}
return show;
}
let shouldShow = computeShow(
show,
openClosedState !== undefined ? $openClosedState : undefined
);
let initialShow = shouldShow;
$: {
shouldShow = computeShow(
show,
openClosedState !== undefined ? $openClosedState : undefined
);
if (shouldShow !== true && shouldShow !== false) {
throw new Error(
"A <Transition /> is used but it is missing a `show={true | false}` prop."
);
}
}
let state = shouldShow ? TreeStates.Visible : TreeStates.Hidden;
let nestingBag = writable<NestingContextValues>(
useNesting(() => {
state = TreeStates.Hidden;
})
);
let initial = true;
let transitionBag = writable<TransitionContextValues>();
$: transitionBag.set({
show: !!shouldShow,
appear: appear || !initial,
initialShow: !!initialShow,
});
onMount(() => {
initial = false;
});
$: if (!initial) {
if (shouldShow) {
state = TreeStates.Visible;
} else if (!hasChildren($nestingBag)) {
state = TreeStates.Hidden;
}
}
setContext(NESTING_CONTEXT_NAME, nestingBag);
setContext(TRANSITION_CONTEXT_NAME, transitionBag);
</script>
{#if state === TreeStates.Visible || $$props.unmount === false}
<TransitionChild
{...$$restProps}
{as}
use={[...use, forwardEvents]}
on:afterEnter
on:afterLeave
on:beforeEnter
on:beforeLeave
>
<slot />
</TransitionChild>
{/if}