From c9690a4b211034a64c14145a6f889516ff715b1e Mon Sep 17 00:00:00 2001 From: psychedelicious <4822129+psychedelicious@users.noreply.github.com> Date: Wed, 21 Aug 2024 19:01:28 +1000 Subject: [PATCH] feat(ui): add contexts/hooks to access entity adapters directly --- .../components/ControlLayer/ControlLayer.tsx | 25 +++++++------ .../components/InpaintMask/InpaintMask.tsx | 19 ++++++---- .../components/RasterLayer/RasterLayer.tsx | 19 ++++++---- .../RegionalGuidance/RegionalGuidance.tsx | 27 ++++++++------ .../contexts/CanvasManagerProviderGate.tsx | 12 +++--- .../controlLayers/hooks/useEntityAdapter.ts | 20 +++++++--- .../hooks/useEntityLayerAdapter.tsx | 37 +++++++++++++++++++ .../hooks/useEntityMaskAdapter.tsx | 37 +++++++++++++++++++ 8 files changed, 146 insertions(+), 50 deletions(-) create mode 100644 invokeai/frontend/web/src/features/controlLayers/hooks/useEntityLayerAdapter.tsx create mode 100644 invokeai/frontend/web/src/features/controlLayers/hooks/useEntityMaskAdapter.tsx diff --git a/invokeai/frontend/web/src/features/controlLayers/components/ControlLayer/ControlLayer.tsx b/invokeai/frontend/web/src/features/controlLayers/components/ControlLayer/ControlLayer.tsx index 17791d76dd..84a23e8346 100644 --- a/invokeai/frontend/web/src/features/controlLayers/components/ControlLayer/ControlLayer.tsx +++ b/invokeai/frontend/web/src/features/controlLayers/components/ControlLayer/ControlLayer.tsx @@ -7,6 +7,7 @@ import { CanvasEntitySettingsWrapper } from 'features/controlLayers/components/c import { CanvasEntityEditableTitle } from 'features/controlLayers/components/common/CanvasEntityTitleEdit'; import { ControlLayerControlAdapter } from 'features/controlLayers/components/ControlLayer/ControlLayerControlAdapter'; import { EntityIdentifierContext } from 'features/controlLayers/contexts/EntityIdentifierContext'; +import { EntityLayerAdapterProviderGate } from 'features/controlLayers/hooks/useEntityLayerAdapter'; import type { CanvasEntityIdentifier } from 'features/controlLayers/store/types'; import { memo, useMemo } from 'react'; @@ -19,17 +20,19 @@ export const ControlLayer = memo(({ id }: Props) => { return ( - - - - - - - - - - - + + + + + + + + + + + + + ); }); diff --git a/invokeai/frontend/web/src/features/controlLayers/components/InpaintMask/InpaintMask.tsx b/invokeai/frontend/web/src/features/controlLayers/components/InpaintMask/InpaintMask.tsx index 02a5a64807..c36ca16f6f 100644 --- a/invokeai/frontend/web/src/features/controlLayers/components/InpaintMask/InpaintMask.tsx +++ b/invokeai/frontend/web/src/features/controlLayers/components/InpaintMask/InpaintMask.tsx @@ -4,6 +4,7 @@ import { CanvasEntityEnabledToggle } from 'features/controlLayers/components/com import { CanvasEntityHeader } from 'features/controlLayers/components/common/CanvasEntityHeader'; import { CanvasEntityEditableTitle } from 'features/controlLayers/components/common/CanvasEntityTitleEdit'; import { EntityIdentifierContext } from 'features/controlLayers/contexts/EntityIdentifierContext'; +import { EntityMaskAdapterProviderGate } from 'features/controlLayers/hooks/useEntityMaskAdapter'; import type { CanvasEntityIdentifier } from 'features/controlLayers/store/types'; import { memo, useMemo } from 'react'; @@ -18,14 +19,16 @@ export const InpaintMask = memo(({ id }: Props) => { return ( - - - - - - - - + + + + + + + + + + ); }); diff --git a/invokeai/frontend/web/src/features/controlLayers/components/RasterLayer/RasterLayer.tsx b/invokeai/frontend/web/src/features/controlLayers/components/RasterLayer/RasterLayer.tsx index b5ef0a4eee..400851b107 100644 --- a/invokeai/frontend/web/src/features/controlLayers/components/RasterLayer/RasterLayer.tsx +++ b/invokeai/frontend/web/src/features/controlLayers/components/RasterLayer/RasterLayer.tsx @@ -5,6 +5,7 @@ import { CanvasEntityEnabledToggle } from 'features/controlLayers/components/com import { CanvasEntityHeader } from 'features/controlLayers/components/common/CanvasEntityHeader'; import { CanvasEntityEditableTitle } from 'features/controlLayers/components/common/CanvasEntityTitleEdit'; import { EntityIdentifierContext } from 'features/controlLayers/contexts/EntityIdentifierContext'; +import { EntityLayerAdapterProviderGate } from 'features/controlLayers/hooks/useEntityLayerAdapter'; import type { CanvasEntityIdentifier } from 'features/controlLayers/store/types'; import { memo, useMemo } from 'react'; @@ -17,14 +18,16 @@ export const RasterLayer = memo(({ id }: Props) => { return ( - - - - - - - - + + + + + + + + + + ); }); diff --git a/invokeai/frontend/web/src/features/controlLayers/components/RegionalGuidance/RegionalGuidance.tsx b/invokeai/frontend/web/src/features/controlLayers/components/RegionalGuidance/RegionalGuidance.tsx index 4a4a56b3ee..12b545312a 100644 --- a/invokeai/frontend/web/src/features/controlLayers/components/RegionalGuidance/RegionalGuidance.tsx +++ b/invokeai/frontend/web/src/features/controlLayers/components/RegionalGuidance/RegionalGuidance.tsx @@ -7,6 +7,7 @@ import { CanvasEntityEditableTitle } from 'features/controlLayers/components/com import { RegionalGuidanceBadges } from 'features/controlLayers/components/RegionalGuidance/RegionalGuidanceBadges'; import { RegionalGuidanceSettings } from 'features/controlLayers/components/RegionalGuidance/RegionalGuidanceSettings'; import { EntityIdentifierContext } from 'features/controlLayers/contexts/EntityIdentifierContext'; +import { EntityMaskAdapterProviderGate } from 'features/controlLayers/hooks/useEntityMaskAdapter'; import type { CanvasEntityIdentifier } from 'features/controlLayers/store/types'; import { memo, useMemo } from 'react'; @@ -22,18 +23,20 @@ export const RegionalGuidance = memo(({ id }: Props) => { return ( - - - - - - - - - - - - + + + + + + + + + + + + + + ); }); diff --git a/invokeai/frontend/web/src/features/controlLayers/contexts/CanvasManagerProviderGate.tsx b/invokeai/frontend/web/src/features/controlLayers/contexts/CanvasManagerProviderGate.tsx index c94af94b92..51037d4e00 100644 --- a/invokeai/frontend/web/src/features/controlLayers/contexts/CanvasManagerProviderGate.tsx +++ b/invokeai/frontend/web/src/features/controlLayers/contexts/CanvasManagerProviderGate.tsx @@ -6,12 +6,6 @@ import { assert } from 'tsafe'; const CanvasManagerContext = createContext(null); -export const useCanvasManager = (): CanvasManager => { - const canvasManager = useContext(CanvasManagerContext); - assert(canvasManager, 'useCanvasManagerContext must be used within a CanvasManagerContext'); - return canvasManager; -}; - export const CanvasManagerProviderGate = memo(({ children }: PropsWithChildren) => { const canvasManager = useStore($canvasManager); @@ -23,3 +17,9 @@ export const CanvasManagerProviderGate = memo(({ children }: PropsWithChildren) }); CanvasManagerProviderGate.displayName = 'CanvasManagerProviderGate'; + +export const useCanvasManager = (): CanvasManager => { + const canvasManager = useContext(CanvasManagerContext); + assert(canvasManager, 'useCanvasManagerContext must be used within a CanvasManagerProviderGate'); + return canvasManager; +}; diff --git a/invokeai/frontend/web/src/features/controlLayers/hooks/useEntityAdapter.ts b/invokeai/frontend/web/src/features/controlLayers/hooks/useEntityAdapter.ts index 210c5cb092..63d93b85ca 100644 --- a/invokeai/frontend/web/src/features/controlLayers/hooks/useEntityAdapter.ts +++ b/invokeai/frontend/web/src/features/controlLayers/hooks/useEntityAdapter.ts @@ -1,8 +1,18 @@ -import { useStore } from '@nanostores/react'; -import { $canvasManager } from 'features/controlLayers/konva/CanvasManager'; +import { useCanvasManager } from 'features/controlLayers/contexts/CanvasManagerProviderGate'; +import type { CanvasLayerAdapter } from 'features/controlLayers/konva/CanvasLayerAdapter'; +import type { CanvasMaskAdapter } from 'features/controlLayers/konva/CanvasMaskAdapter'; import type { CanvasEntityIdentifier } from 'features/controlLayers/store/types'; +import { useMemo } from 'react'; +import { assert } from 'tsafe'; -export const useEntityAdapter = (entityIdentifier: CanvasEntityIdentifier) => { - const canvasManager = useStore($canvasManager); - console.log(canvasManager); +export const useEntityAdapter = (entityIdentifier: CanvasEntityIdentifier): CanvasLayerAdapter | CanvasMaskAdapter => { + const canvasManager = useCanvasManager(); + + const adapter = useMemo(() => { + const entity = canvasManager.stateApi.getEntity(entityIdentifier); + assert(entity, 'Entity adapter not found'); + return entity.adapter; + }, [canvasManager, entityIdentifier]); + + return adapter; }; diff --git a/invokeai/frontend/web/src/features/controlLayers/hooks/useEntityLayerAdapter.tsx b/invokeai/frontend/web/src/features/controlLayers/hooks/useEntityLayerAdapter.tsx new file mode 100644 index 0000000000..b572aa804b --- /dev/null +++ b/invokeai/frontend/web/src/features/controlLayers/hooks/useEntityLayerAdapter.tsx @@ -0,0 +1,37 @@ +import { useCanvasManager } from 'features/controlLayers/contexts/CanvasManagerProviderGate'; +import { useEntityIdentifierContext } from 'features/controlLayers/contexts/EntityIdentifierContext'; +import type { CanvasLayerAdapter } from 'features/controlLayers/konva/CanvasLayerAdapter'; +import type { PropsWithChildren } from 'react'; +import { createContext, memo, useContext, useMemo } from 'react'; +import { assert } from 'tsafe'; + +const EntityLayerAdapterContext = createContext(null); + +export const EntityLayerAdapterProviderGate = memo(({ children }: PropsWithChildren) => { + const entityIdentifier = useEntityIdentifierContext(); + const canvasManager = useCanvasManager(); + const adapter = useMemo(() => { + if (entityIdentifier.type === 'raster_layer') { + return canvasManager.rasterLayerAdapters.get(entityIdentifier.id) ?? null; + } else if (entityIdentifier.type === 'control_layer') { + return canvasManager.controlLayerAdapters.get(entityIdentifier.id) ?? null; + } + assert(false, 'EntityLayerAdapterProviderGate must be used with a valid EntityIdentifierContext'); + }, [canvasManager, entityIdentifier]); + + if (!canvasManager) { + return null; + } + + return {children}; +}); + +EntityLayerAdapterProviderGate.displayName = 'EntityLayerAdapterProviderGate'; + +export const useEntityLayerAdapter = (): CanvasLayerAdapter => { + const adapter = useContext(EntityLayerAdapterContext); + + assert(adapter, 'useEntityLayerAdapter must be used within a EntityLayerAdapterProviderGate'); + + return adapter; +}; diff --git a/invokeai/frontend/web/src/features/controlLayers/hooks/useEntityMaskAdapter.tsx b/invokeai/frontend/web/src/features/controlLayers/hooks/useEntityMaskAdapter.tsx new file mode 100644 index 0000000000..697d434c3b --- /dev/null +++ b/invokeai/frontend/web/src/features/controlLayers/hooks/useEntityMaskAdapter.tsx @@ -0,0 +1,37 @@ +import { useCanvasManager } from 'features/controlLayers/contexts/CanvasManagerProviderGate'; +import { useEntityIdentifierContext } from 'features/controlLayers/contexts/EntityIdentifierContext'; +import type { CanvasMaskAdapter } from 'features/controlLayers/konva/CanvasMaskAdapter'; +import type { PropsWithChildren } from 'react'; +import { createContext, memo, useContext, useMemo } from 'react'; +import { assert } from 'tsafe'; + +const EntityMaskAdapterContext = createContext(null); + +export const EntityMaskAdapterProviderGate = memo(({ children }: PropsWithChildren) => { + const entityIdentifier = useEntityIdentifierContext(); + const canvasManager = useCanvasManager(); + const adapter = useMemo(() => { + if (entityIdentifier.type === 'inpaint_mask') { + return canvasManager.inpaintMaskAdapters.get(entityIdentifier.id) ?? null; + } else if (entityIdentifier.type === 'regional_guidance') { + return canvasManager.regionalGuidanceAdapters.get(entityIdentifier.id) ?? null; + } + assert(false, 'EntityMaskAdapterProviderGate must be used with a valid EntityIdentifierContext'); + }, [canvasManager, entityIdentifier]); + + if (!canvasManager) { + return null; + } + + return {children}; +}); + +EntityMaskAdapterProviderGate.displayName = 'EntityMaskAdapterProviderGate'; + +export const useEntityMaskAdapter = (): CanvasMaskAdapter => { + const adapter = useContext(EntityMaskAdapterContext); + + assert(adapter, 'useEntityMaskAdapter must be used within a EntityLayerAdapterProviderGate'); + + return adapter; +};