Skip to content

Commit

Permalink
push incremental changes for debugging
Browse files Browse the repository at this point in the history
  • Loading branch information
JonathonRP committed Dec 10, 2024
1 parent ef38928 commit 1897412
Show file tree
Hide file tree
Showing 7 changed files with 162 additions and 158 deletions.
Binary file modified bun.lockb
Binary file not shown.
2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -66,7 +66,7 @@
"vitest": "latest"
},
"peerDependencies": {
"svelte": "^5.10.0"
"svelte": "^5.10.1"
},
"engines": {
"bun": ">=1.0.0",
Expand Down
3 changes: 1 addition & 2 deletions src/lib/motion-start/animation/utils/is-animatable.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,8 +3,7 @@ based on [email protected],
Copyright (c) 2018 Framer B.V.
*/

// import { complex } from 'style-value-types';
import { complex } from "../../value/types/complex"
import { complex } from '../../value/types/complex';
import type { ValueKeyframesDefinition } from '../types';

/**
Expand Down
242 changes: 113 additions & 129 deletions src/lib/motion-start/components/AnimatePresence/AnimatePresence.svelte
Original file line number Diff line number Diff line change
Expand Up @@ -9,13 +9,13 @@ Copyright (c) 2018 Framer B.V. -->
import PresenceChild from "./PresenceChild/PresenceChild.svelte";
import { fromStore } from "svelte/store";
import { SvelteMap, SvelteSet } from "svelte/reactivity";
import { untrack, type Snippet } from "svelte";
import { onDestroy, untrack, type Snippet } from "svelte";
import { type ComponentKey, getChildKey } from "./utils.js";
import { invariant } from "../../utils/errors.js";
type Props = AnimatePresenceProps<ConditionalGeneric<T>> & {
isCustom?: boolean;
children?: Snippet<[ConditionalGeneric<T> | { key: number }]>;
children?: Snippet<[typeof list | { key: number }]>;
};
let {
Expand All @@ -35,88 +35,26 @@ Copyright (c) 2018 Framer B.V. -->
let _list = $state(list !== undefined ? list : show ? [{ key: 1 }] : []);
const presentChildren = $derived(_list);
let presentChildren = $state(_list);
const presentKeys = $derived(presentChildren.map(getChildKey));
let isInitialRender = $state(true);
let pendingPresentChildren = $state(presentChildren);
let diffedChildren = $state(presentChildren);
let renderedChildren = $state(presentChildren);
let exitComplete = new SvelteMap<ComponentKey, boolean>();
// $inspect(presentChildren);
$effect(() => {
console.log("effect");
list;
isInitialRender = false;
pendingPresentChildren = presentChildren;
/**
* Update complete status of exiting children.
*/
for (let i = 0; i < renderedChildren.length; i++) {
const key = getChildKey(renderedChildren[i]);
if (!presentKeys.includes(key)) {
if (exitComplete.get(key) !== true) {
exitComplete.set(key, false);
}
} else {
exitComplete.delete(key);
}
}
});
const exitingChildren = $state<(ConditionalGeneric<T> | { key: number })[]>(
[],
let renderedChildren = $state(
presentChildren.map((v) => ({
present: true,
item: v,
key: v.key,
onExit: undefined,
})),
);
if (presentChildren !== diffedChildren) {
let nextChildren = [...presentChildren];
/**
* Loop through all the currently rendered components and decide which
* are exiting.
*/
for (let i = 0; i < renderedChildren.length; i++) {
const child = renderedChildren[i];
const key = getChildKey(child);
if (!presentKeys.includes(key)) {
nextChildren.splice(i, 0, child);
exitingChildren.push(child);
}
}
/**
* If we're in "wait" mode, and we have exiting children, we want to
* only render these until they've all exited.
*/
if (mode === "wait" && exitingChildren.length) {
nextChildren = exitingChildren;
}
renderedChildren = nextChildren;
diffedChildren = presentChildren;
/**
* Early return to ensure once we've set state with the latest diffed
* children, we can immediately re-render.
*/
// return
}
if (
process.env.NODE_ENV !== "production" &&
mode === "wait" &&
renderedChildren.length > 1
) {
console.warn(
`You're attempting to animate multiple children within AnimatePresence, but its mode is set to "wait". This will lead to odd visual behaviour.`,
);
}
let exitComplete = new SvelteMap<ComponentKey, boolean>(
_list.map(getChildKey).map((key) => {
return [key, !!key];
}),
);
const exitingChildren = new SvelteSet<number>();
const layoutContext = fromStore(
useContext(LayoutGroupContext, isCustom),
Expand All @@ -125,67 +63,113 @@ Copyright (c) 2018 Framer B.V. -->
layoutContext.forceRender?.();
_list = [..._list];
});
</script>
{#each renderedChildren.map((child) => {
const key = getChildKey(child);
const isPresent = presentChildren === renderedChildren || presentKeys.includes(key);
return { key, isPresent, item: child, onExit() {
console.log("exit");
if (exitComplete.has(key)) {
exitComplete.set(key, true);
} else {
return;
$effect.pre(() => {
if (!isInitialRender) {
/**
* Update complete status of exiting children.
*/
for (let i = 0; i < presentKeys.length; i++) {
const key = presentKeys[i];
if (!presentKeys.includes(key)) {
if (exitComplete.has(key)) {
exitingChildren.add(key!);
}
} else {
exitingChildren.delete(key!);
}
}
let isEveryExitComplete = true;
exitComplete.forEach((isExitComplete) => {
if (!isExitComplete) isEveryExitComplete = false;
});
let nextChildren = [...presentChildren];
/**
* Loop through all the currently rendered components and decide which
* are exiting.
*/
for (let i = 0; i < renderedChildren.length; i++) {
const child = renderedChildren[i];
const key = getChildKey(child);
if (isEveryExitComplete) {
forceRender?.();
renderedChildren = pendingPresentChildren;
if (!presentKeys.includes(key)) {
nextChildren.splice(i, 0, child);
exitingChildren.add(key!);
}
}
onExitComplete && onExitComplete();
/**
* If we're in "wait" mode, and we have exiting children, we want to
* only render these until they've all exited.
*/
if (mode === "wait" && exitingChildren.size) {
nextChildren = [...exitingChildren].map((key) => ({ key }));
}
// allChildren.delete(key);
// exiting.delete(key);

// // Remove this child from the present children
// const removeIndex = presentChildren.findIndex(
// (presentChild) => presentChild.key === key,
// );

// if (removeIndex < 0) {
// return;
// }
// untrack(() => presentChildren).splice(removeIndex, 1);

// // Defer re-rendering until all exiting children have indeed left
// if (!exiting.size) {
// presentChildren = [...filteredChildren];
// forceRender?.();
// onExitComplete && onExitComplete();
// }
// };

// untrack(() => childrenToRender).splice(insertionIndex, 0, {
// present: false,
// item: child,
// key: getChildKey(child),
// onExit,
// });
} };
}) as child (getChildKey(child))}
exitingChildren.forEach((key) => {
const child = presentChildren.find((e) => e.key === key);
renderedChildren.splice(presentKeys.indexOf(key), 0, {
present: false,
item: child,
key: getChildKey(child),
onExit:
!isInitialRender &&
exitComplete.has(key) &&
!_list.includes(child)
? () => {
exitingChildren.delete(key!);
// Remove this child from the present children
const removeIndex = presentChildren.findIndex(
(presentChild) =>
presentChild.key === key,
);
if (removeIndex < 0) {
return;
}
presentChildren.splice(removeIndex, 1);
// Defer re-rendering until all exiting children have indeed left
if (!exitingChildren.size) {
renderedChildren = [..._list];
forceRender?.();
onExitComplete && onExitComplete();
}
}
: undefined,
});
});
/**
* Early return to ensure once we've set state with the latest diffed
* children, we can immediately re-render.
*/
presentChildren = renderedChildren;
return;
} else {
isInitialRender = false;
}
if (
process.env.NODE_ENV !== "production" &&
mode === "wait" &&
renderedChildren.length > 1
) {
console.warn(
`You're attempting to animate multiple children within AnimatePresence, but its mode is set to "wait". This will lead to odd visual behaviour.`,
);
}
});
</script>

{#each renderedChildren as child (child.key)}
<PresenceChild
isPresent={child.isPresent}
{mode}
isPresent={child.present}
initial={!isInitialRender || initial ? undefined : false}
custom={child.isPresent ? custom : undefined}
custom={child.onExit ? custom : undefined}
{presenceAffectsLayout}
{mode}
onExitComplete={child.isPresent ? undefined : child.onExit}
onExitComplete={child.onExit}
{isCustom}
>
{@render children?.(child.item)}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@ Copyright (c) 2018 Framer B.V. -->
import { useContext } from "$lib/motion-start/context/utils/context.svelte.js";
import { useId } from "$lib/motion-start/utils/useId.js";
import { fromStore } from "svelte/store";
import { tick, untrack } from "svelte";
interface Props extends PresenceChildProps {
isCustom?: boolean;
Expand All @@ -37,7 +38,7 @@ Copyright (c) 2018 Framer B.V. -->
const refresh = $derived(presenceAffectsLayout ? undefined : isPresent);
const memoContext = (flag?: boolean) => {
const memoContext = $derived((flag?: boolean) => {
return {
id,
initial,
Expand All @@ -57,34 +58,41 @@ Copyright (c) 2018 Framer B.V. -->
return () => presenceChildren.delete(childId);
},
};
};
});
let context = fromStore(useContext(PresenceContext, isCustom)).current;
$effect(() => {
if (presenceAffectsLayout) {
context = memoContext();
context = untrack(() => memoContext());
return;
}
context = memoContext(refresh);
context = untrack(() => memoContext(refresh));
});
const keyset = (flag?: boolean) => {
presenceChildren.forEach((_, key) => presenceChildren.set(key, false));
};
$effect(() => {
keyset(isPresent);
!isPresent && !presenceChildren.size && onExitComplete?.();
keyset(untrack(() => isPresent));
untrack(() => !isPresent) &&
!presenceChildren.size &&
onExitComplete?.();
});
$effect(() => {
PresenceContext["_c"] = isCustom;
PresenceContext.Provider = context;
});
</script>

{#if mode === "popLayout"}
<PopChild {isPresent}>
{@render children?.()}
{#if isPresent}
{@render children?.()}
{/if}
</PopChild>
{:else}
{:else if isPresent}
{@render children?.()}
{/if}
Loading

0 comments on commit 1897412

Please sign in to comment.