mirror of
https://github.com/enricoros/big-AGI.git
synced 2026-05-10 21:50:14 -07:00
Optima: portals
This commit is contained in:
@@ -0,0 +1,18 @@
|
||||
import * as React from 'react';
|
||||
import { createPortal } from 'react-dom';
|
||||
|
||||
import { OptimaPortalId, usePortalElement } from './store-optima-portals';
|
||||
|
||||
|
||||
export function OptimaPortalIn(props: {
|
||||
targetPortalId: OptimaPortalId;
|
||||
children: React.ReactNode;
|
||||
}) {
|
||||
|
||||
// react to the portal being made available
|
||||
const portalElement = usePortalElement(props.targetPortalId);
|
||||
if (!portalElement)
|
||||
return null;
|
||||
|
||||
return createPortal(props.children, portalElement);
|
||||
}
|
||||
@@ -0,0 +1,57 @@
|
||||
import { create } from 'zustand';
|
||||
|
||||
|
||||
// module configuration
|
||||
const DEBUG_OPTIMA_PORTALS = false;
|
||||
|
||||
|
||||
export type OptimaPortalId =
|
||||
| 'optima-portal-drawer'
|
||||
| 'optima-portal-properties'
|
||||
| 'optima-portal-toolbar'
|
||||
;
|
||||
|
||||
interface PortalState {
|
||||
portalElements: Map<OptimaPortalId, HTMLElement>;
|
||||
}
|
||||
|
||||
interface PortalActions {
|
||||
addPortal: (id: OptimaPortalId, element: HTMLElement) => void;
|
||||
removePortal: (id: OptimaPortalId) => void;
|
||||
}
|
||||
|
||||
type PortalStore = PortalState & PortalActions;
|
||||
|
||||
|
||||
const useOptimaPortalsStore = create<PortalStore>((set, get) => ({
|
||||
|
||||
// init state
|
||||
portalElements: new Map(),
|
||||
|
||||
// actions
|
||||
addPortal: (id, element) => set((state) => {
|
||||
const newPortals = new Map(state.portalElements);
|
||||
newPortals.set(id, element);
|
||||
if (DEBUG_OPTIMA_PORTALS)
|
||||
console.log(' > store.addPortal', id, !!element);
|
||||
return { portalElements: newPortals };
|
||||
}),
|
||||
|
||||
removePortal: (id) => set((state) => {
|
||||
const newPortals = new Map(state.portalElements);
|
||||
newPortals.delete(id);
|
||||
if (DEBUG_OPTIMA_PORTALS)
|
||||
console.log(' < store.removePortal', id);
|
||||
return { portalElements: newPortals };
|
||||
}),
|
||||
|
||||
}));
|
||||
|
||||
|
||||
export function optimaPortalsActions(): PortalActions {
|
||||
return useOptimaPortalsStore.getState();
|
||||
}
|
||||
|
||||
export function usePortalElement(id: OptimaPortalId) {
|
||||
return useOptimaPortalsStore((state) => state.portalElements.get(id) || null);
|
||||
}
|
||||
@@ -0,0 +1,45 @@
|
||||
import * as React from 'react';
|
||||
|
||||
import { OptimaPortalId, optimaPortalsActions } from './store-optima-portals';
|
||||
|
||||
|
||||
/**
|
||||
* Note: this hook assumes that the ref is created by when useLayoutEffect is called,
|
||||
* and will warn otherwise.
|
||||
*/
|
||||
export function useOptimaPortalOut(portalTargetId: OptimaPortalId, debugCallerName: string) {
|
||||
|
||||
// state
|
||||
const ref = React.useRef<HTMLElement>(null);
|
||||
|
||||
React.useLayoutEffect(() => {
|
||||
const { addPortal, removePortal } = optimaPortalsActions();
|
||||
if (!ref.current) {
|
||||
console.warn(`useOptimaPortalOut: ref.current is null for type ${portalTargetId} (called by ${debugCallerName})`);
|
||||
} else {
|
||||
addPortal(portalTargetId, ref.current);
|
||||
}
|
||||
return () => removePortal(portalTargetId);
|
||||
}, [debugCallerName, portalTargetId]);
|
||||
|
||||
return ref;
|
||||
}
|
||||
|
||||
/*
|
||||
// This version will add the portal only when really getting the ref
|
||||
export function useOptimaPortalOut(portalTargetId: OptimaPortalId, debugCallerName: string) {
|
||||
|
||||
const setRef = React.useCallback((node: HTMLElement | null) => {
|
||||
const { addPortal, removePortal } = optimaPortalsActions();
|
||||
console.log('useOptimaPortalOut.setRef', portalTargetId, node);
|
||||
if (node) {
|
||||
console.log(' - useOptimaPortalOut call AddPortal', portalTargetId);
|
||||
addPortal(portalTargetId, node);
|
||||
} else {
|
||||
removePortal(portalTargetId);
|
||||
}
|
||||
}, [portalTargetId]);
|
||||
|
||||
return setRef;
|
||||
}
|
||||
*/
|
||||
Reference in New Issue
Block a user