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;
+};