UNPKG

reblend-ui

Version:

Utilities for creating robust overlay components

121 lines (119 loc) 3.65 kB
"use strict"; exports.__esModule = true; exports.default = void 0; exports.renderTransition = renderTransition; exports.useTransition = useTransition; var _reblendHooks = require("reblend-hooks"); var _reblendjs = require("reblendjs"); var _NoopTransition = require("./NoopTransition"); var _RTGTransition = require("./RTGTransition"); var _utils = require("./utils"); function useTransition({ in: inProp, onTransition }) { const ref = (0, _reblendjs.useRef)(null); const isInitialRef = (0, _reblendjs.useRef)(true); const handleTransition = (0, _reblendHooks.useEventCallback)(onTransition); useIsomorphicEffect(() => { if (!ref.current) { return undefined; } let stale = false; handleTransition({ in: inProp, element: ref.current, initial: isInitialRef.current, isStale: () => stale }); return () => { stale = true; }; }, [inProp, handleTransition]); useIsomorphicEffect(() => { isInitialRef.current = false; // this is for strict mode return () => { isInitialRef.current = true; }; }, []); return ref; } /** * Adapts an imperative transition function to a subset of the RTG `<Transition>` component API. * * ImperativeTransition does not support mounting options or `appear` at the moment, meaning * that it always acts like: `mountOnEnter={true} unmountOnExit={true} appear={true}` */ class ImperativeTransition extends Reblend { static ELEMENT_NAME = "ImperativeTransition"; constructor() { super(); } async initState() { const [exited, setExited] = _reblendjs.useState.bind(this)(!this.props.inProp, "exited"); // TODO: I think this needs to be in an effect this.state.exited = exited; this.state.setExited = setExited; if (this.props.inProp && this.state.exited) { this.state.setExited(false); } const ref = useTransition.bind(this)({ in: !!this.props.inProp, onTransition: options => { const onFinish = () => { if (options.isStale()) return; if (options.in) { this.props.onEntered?.(options.element, options.initial); } else { this.state.setExited(true); this.props.onExited?.(options.element); } }; Promise.resolve(this.props.transition(options)).then(onFinish, error => { if (!options.in) this.state.setExited(true); throw error; }); } }); this.state.ref = ref; const combinedRef = _reblendHooks.useMergedRefs.bind(this)(this.state.ref, (0, _utils.getChildRef)(this.props.children)); this.state.combinedRef = combinedRef; } async initProps({ children, in: inProp, onExited, onEntered, transition }) { this.props = {}; this.props.children = children; this.props.inProp = inProp; this.props.onExited = onExited; this.props.onEntered = onEntered; this.props.transition = transition; } async html() { return this.state.exited && !this.props.inProp ? null : (0, _reblendjs.cloneElement)(this.props.children, { ref: this.state.combinedRef }); } } /* @Reblend: Transformed from function to class */ exports.default = ImperativeTransition; function renderTransition(component, runTransition, props) { if (component) { return Reblend.construct.bind(this)(_RTGTransition.default, { ...props, component: component }); } if (runTransition) { return Reblend.construct.bind(this)(ImperativeTransition, { ...props, transition: runTransition }); } return Reblend.construct.bind(this)(_NoopTransition.default, props); }