anim: remove hero signal
* BottomSheet: remove hero support * use StackedRouter's hero support instead
This commit is contained in:
		
							parent
							
								
									8588a17bd0
								
							
						
					
					
						commit
						15974af792
					
				
					 3 changed files with 3 additions and 144 deletions
				
			
		| 
						 | 
				
			
			@ -9,12 +9,10 @@ import {
 | 
			
		|||
  type ResolvedChildren,
 | 
			
		||||
} from "solid-js";
 | 
			
		||||
import "./BottomSheet.css";
 | 
			
		||||
import { useHeroSignal } from "../platform/anim";
 | 
			
		||||
import material from "./material.module.css";
 | 
			
		||||
import {
 | 
			
		||||
  ANIM_CURVE_ACELERATION,
 | 
			
		||||
  ANIM_CURVE_DECELERATION,
 | 
			
		||||
  ANIM_CURVE_STD,
 | 
			
		||||
} from "./theme";
 | 
			
		||||
import {
 | 
			
		||||
  animateSlideInFromRight,
 | 
			
		||||
| 
						 | 
				
			
			@ -28,32 +26,11 @@ export type BottomSheetProps = {
 | 
			
		|||
  onClose?(reason: "backdrop"): void;
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
export const HERO = Symbol("BottomSheet Hero Symbol");
 | 
			
		||||
 | 
			
		||||
function composeAnimationFrame(
 | 
			
		||||
  {
 | 
			
		||||
    top,
 | 
			
		||||
    left,
 | 
			
		||||
    height,
 | 
			
		||||
    width,
 | 
			
		||||
  }: Record<"top" | "left" | "height" | "width", number>,
 | 
			
		||||
  x: Record<string, unknown>,
 | 
			
		||||
) {
 | 
			
		||||
  return {
 | 
			
		||||
    top: `${top}px`,
 | 
			
		||||
    left: `${left}px`,
 | 
			
		||||
    height: `${height}px`,
 | 
			
		||||
    width: `${width}px`,
 | 
			
		||||
    ...x,
 | 
			
		||||
  };
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
const MOVE_SPEED = 1600;
 | 
			
		||||
 | 
			
		||||
const BottomSheet: ParentComponent<BottomSheetProps> = (props) => {
 | 
			
		||||
  let element: HTMLDialogElement;
 | 
			
		||||
  let animation: Animation | undefined;
 | 
			
		||||
  const [hero, setHero] = useHeroSignal(HERO);
 | 
			
		||||
  const [cache, setCache] = createSignal<ResolvedChildren | undefined>();
 | 
			
		||||
  const ochildren = children(() => props.children);
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -74,24 +51,11 @@ const BottomSheet: ParentComponent<BottomSheetProps> = (props) => {
 | 
			
		|||
  });
 | 
			
		||||
 | 
			
		||||
  const onClose = () => {
 | 
			
		||||
    const srcElement = hero();
 | 
			
		||||
    if (srcElement) {
 | 
			
		||||
      srcElement.style.visibility = "unset";
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    element.close();
 | 
			
		||||
    setHero();
 | 
			
		||||
  };
 | 
			
		||||
 | 
			
		||||
  const animatedClose = () => {
 | 
			
		||||
    const srcElement = hero();
 | 
			
		||||
    const endRect = srcElement?.getBoundingClientRect();
 | 
			
		||||
    if (endRect) {
 | 
			
		||||
      const startRect = element.getBoundingClientRect();
 | 
			
		||||
      const animation = animateHero(startRect, endRect, element, true);
 | 
			
		||||
      animation.addEventListener("finish", onClose);
 | 
			
		||||
      animation.addEventListener("cancel", onClose);
 | 
			
		||||
    } else {
 | 
			
		||||
 | 
			
		||||
      if (window.innerWidth > 560 && !props.bottomUp) {
 | 
			
		||||
        onClose();
 | 
			
		||||
        return;
 | 
			
		||||
| 
						 | 
				
			
			@ -106,21 +70,12 @@ const BottomSheet: ParentComponent<BottomSheetProps> = (props) => {
 | 
			
		|||
        : animateSlideOutToRight(element, { easing: ANIM_CURVE_ACELERATION });
 | 
			
		||||
      animation.addEventListener("finish", onAnimationEnd);
 | 
			
		||||
      animation.addEventListener("cancel", onAnimationEnd);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
  };
 | 
			
		||||
 | 
			
		||||
  const animatedOpen = () => {
 | 
			
		||||
    element.showModal();
 | 
			
		||||
    const srcElement = hero();
 | 
			
		||||
    const startRect = srcElement?.getBoundingClientRect();
 | 
			
		||||
    if (!startRect) {
 | 
			
		||||
      console.debug("no source element");
 | 
			
		||||
    }
 | 
			
		||||
    if (startRect) {
 | 
			
		||||
      srcElement!.style.visibility = "hidden";
 | 
			
		||||
      const endRect = element.getBoundingClientRect();
 | 
			
		||||
      animateHero(startRect, endRect, element);
 | 
			
		||||
    } else if (props.bottomUp) {
 | 
			
		||||
    if (props.bottomUp) {
 | 
			
		||||
      animateSlideInFromBottom(element);
 | 
			
		||||
    } else if (window.innerWidth <= 560) {
 | 
			
		||||
      element.classList.add("animated");
 | 
			
		||||
| 
						 | 
				
			
			@ -165,41 +120,6 @@ const BottomSheet: ParentComponent<BottomSheetProps> = (props) => {
 | 
			
		|||
    return animation;
 | 
			
		||||
  };
 | 
			
		||||
 | 
			
		||||
  const animateHero = (
 | 
			
		||||
    startRect: DOMRect,
 | 
			
		||||
    endRect: DOMRect,
 | 
			
		||||
    element: HTMLElement,
 | 
			
		||||
    reserve?: boolean,
 | 
			
		||||
  ) => {
 | 
			
		||||
    const easing = ANIM_CURVE_STD;
 | 
			
		||||
    element.classList.add("animated");
 | 
			
		||||
    // distance_lt = (|top_start - top_end|^2 + |left_end - left_end|^2)^(-2)
 | 
			
		||||
    const distancelt = Math.sqrt(
 | 
			
		||||
      Math.pow(Math.abs(startRect.top - endRect.top), 2) +
 | 
			
		||||
        Math.pow(Math.abs(startRect.left - endRect.left), 2),
 | 
			
		||||
    );
 | 
			
		||||
    const distancerb = Math.sqrt(
 | 
			
		||||
      Math.pow(Math.abs(startRect.bottom - endRect.bottom), 2) +
 | 
			
		||||
        Math.pow(Math.abs(startRect.right - endRect.right), 2),
 | 
			
		||||
    );
 | 
			
		||||
    const distance = distancelt + distancerb;
 | 
			
		||||
    const duration = distance / 1.6;
 | 
			
		||||
    animation = element.animate(
 | 
			
		||||
      [
 | 
			
		||||
        composeAnimationFrame(startRect, { transform: "none" }),
 | 
			
		||||
        composeAnimationFrame(endRect, { transform: "none" }),
 | 
			
		||||
      ],
 | 
			
		||||
      { easing, duration },
 | 
			
		||||
    );
 | 
			
		||||
    const onAnimationEnd = () => {
 | 
			
		||||
      element.classList.remove("animated");
 | 
			
		||||
      animation = undefined;
 | 
			
		||||
    };
 | 
			
		||||
    animation.addEventListener("finish", onAnimationEnd);
 | 
			
		||||
    animation.addEventListener("cancel", onAnimationEnd);
 | 
			
		||||
    return animation;
 | 
			
		||||
  };
 | 
			
		||||
 | 
			
		||||
  onCleanup(() => {
 | 
			
		||||
    if (animation) {
 | 
			
		||||
      animation.cancel();
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -1,58 +1,3 @@
 | 
			
		|||
import {
 | 
			
		||||
  createContext,
 | 
			
		||||
  createRenderEffect,
 | 
			
		||||
  createSignal,
 | 
			
		||||
  untrack,
 | 
			
		||||
  useContext,
 | 
			
		||||
  type Accessor,
 | 
			
		||||
  type Signal,
 | 
			
		||||
} from "solid-js";
 | 
			
		||||
 | 
			
		||||
export type HeroSource = {
 | 
			
		||||
  [key: string | symbol | number]: HTMLElement | undefined;
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
const HeroSourceContext = createContext<Signal<HeroSource>>(
 | 
			
		||||
  /* __@PURE__ */ undefined,
 | 
			
		||||
);
 | 
			
		||||
 | 
			
		||||
export const HeroSourceProvider = HeroSourceContext.Provider;
 | 
			
		||||
 | 
			
		||||
export function useHeroSource() {
 | 
			
		||||
  return useContext(HeroSourceContext);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * Use hero value for the {@link key}.
 | 
			
		||||
 *
 | 
			
		||||
 * Note: the setter here won't set the value of the hero source.
 | 
			
		||||
 * To set hero source, use {@link useHeroSource} and set the corresponding key.
 | 
			
		||||
 */
 | 
			
		||||
export function useHeroSignal(
 | 
			
		||||
  key: string | symbol | number,
 | 
			
		||||
): Signal<HTMLElement | undefined> {
 | 
			
		||||
  const source = useHeroSource();
 | 
			
		||||
  if (source) {
 | 
			
		||||
    const [get, set] = createSignal<HTMLElement>();
 | 
			
		||||
 | 
			
		||||
    createRenderEffect(() => {
 | 
			
		||||
      const value = source[0]();
 | 
			
		||||
      if (value[key]) {
 | 
			
		||||
        set(value[key]);
 | 
			
		||||
        source[1]((x) => {
 | 
			
		||||
          const cpy = Object.assign({}, x);
 | 
			
		||||
          delete cpy[key];
 | 
			
		||||
          return cpy;
 | 
			
		||||
        });
 | 
			
		||||
      }
 | 
			
		||||
    });
 | 
			
		||||
 | 
			
		||||
    return [get, set];
 | 
			
		||||
  } else {
 | 
			
		||||
    console.debug("no hero source");
 | 
			
		||||
    return [() => undefined, () => undefined];
 | 
			
		||||
  }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
export function animateRollOutFromTop(
 | 
			
		||||
  root: HTMLElement,
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -10,8 +10,6 @@ import {
 | 
			
		|||
import { type mastodon } from "masto";
 | 
			
		||||
import { vibrate } from "../platform/hardware";
 | 
			
		||||
import { useDefaultSession } from "../masto/clients";
 | 
			
		||||
import { useHeroSource } from "../platform/anim";
 | 
			
		||||
import { HERO as BOTTOM_SHEET_HERO } from "../material/BottomSheet";
 | 
			
		||||
import { setCache as setTootBottomSheetCache } from "./TootBottomSheet";
 | 
			
		||||
import RegularToot, {
 | 
			
		||||
  findElementActionable,
 | 
			
		||||
| 
						 | 
				
			
			@ -53,7 +51,6 @@ const TootList: Component<{
 | 
			
		|||
  onChangeToot: (id: string, value: mastodon.v1.Status) => void;
 | 
			
		||||
}> = (props) => {
 | 
			
		||||
  const session = useDefaultSession();
 | 
			
		||||
  const heroSrc = useHeroSource();
 | 
			
		||||
  const [expandedThreadId, setExpandedThreadId] = createSignal<string>();
 | 
			
		||||
  const { push } = useNavigator();
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -124,9 +121,6 @@ const TootList: Component<{
 | 
			
		|||
      console.warn("no account info?");
 | 
			
		||||
      return;
 | 
			
		||||
    }
 | 
			
		||||
    if (heroSrc) {
 | 
			
		||||
      heroSrc[1]((x) => ({ ...x, [BOTTOM_SHEET_HERO]: srcElement }));
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    const acct = `${inf.username}@${p.site}`;
 | 
			
		||||
    setTootBottomSheetCache(acct, toot);
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
		Loading…
	
	Add table
		Add a link
		
	
		Reference in a new issue