import useStore from "@/shared/hook/useStore";
import hoistNonReactStatic from "hoist-non-react-statics";
import { forwardRef, useEffect, useMemo } from "@/import/react";
import getStore, { useStoreId } from "@/shared/store/index";
import { useFormStateIsLoaded } from "@/shared/helper/store";
import StoreValuesContext from "@/shared/context/storeValues";
function getDisplayName(WrappedComponent) {
return WrappedComponent.displayName || WrappedComponent.name || "Element";
}
export const useLinkToParentStore = ({ parentStoreId, parentStoreType, parentStoreRef, storeType, storeId }) => {
const currentStoreId = useStoreId(storeType, storeId);
const parentStoreIsLoaded = useFormStateIsLoaded(parentStoreType, parentStoreId);
useEffect(() => {
// TODO: handle delete case
if (currentStoreId && typeof currentStoreId !== "symbol" && parentStoreId && parentStoreType && parentStoreRef && parentStoreIsLoaded) {
// Currently assuming the parent is loaded within React.
const parentStore = getStore(parentStoreType, parentStoreId, { createInstance: false });
const correctedParentStoreRef = !parentStoreRef.startsWith("formState") || !parentStoreRef.startsWith("declarationState") ? `formState.${parentStoreRef}` : parentStoreRef;
if (parentStore && parentStore.getSnapshot(correctedParentStoreRef) !== currentStoreId) {
parentStore.updateStoreValue(correctedParentStoreRef, currentStoreId);
}
}
}, [parentStoreIsLoaded, currentStoreId, parentStoreId, parentStoreType, parentStoreRef]);
};
function LinkToParentStore(props) {
useLinkToParentStore(props);
return null;
}
const defaultOptions = {
registerAtCentralStore: true,
};
/**
* @param Component
* @returns {function({readOnly: *, [p: string]: *}): *}
*/
function withStore(Component, opts = {}) {
const options = {
...defaultOptions,
...opts,
};
function WithStore(
{
parentStoreId,
parentStoreType,
parentStoreRef,
storeType = options.type,
storeId = options.id,
storeMetaData = options.metaData,
storeInstanceOptions = options.instanceOptions,
registerAtCentralStore = options.registerAtCentralStore,
storeRef,
...props
},
ref
) {
const defaultMetaData = useMemo(() => {
return {
...options.metaData,
...storeMetaData,
};
}, [storeMetaData]);
const storeDefaults = useStore({
type: storeType,
id: storeId,
defaultMetaData,
registerAtCentralStore,
instanceOptions: storeInstanceOptions,
});
useEffect(() => {
if (storeRef) {
storeRef.current = storeDefaults;
}
}, [storeDefaults]);
return (
<StoreValuesContext.Provider value={storeDefaults}>
{parentStoreId && parentStoreType && parentStoreRef && (
<LinkToParentStore parentStoreId={parentStoreId} parentStoreType={parentStoreType} parentStoreRef={parentStoreRef} {...storeDefaults} />
)}
<Component {...storeDefaults} {...props} ref={ref} />
</StoreValuesContext.Provider>
);
}
hoistNonReactStatic(WithStore, Component);
WithStore.displayName = `WithStore(${getDisplayName(Component)})`;
return forwardRef(WithStore);
}
export default withStore;