mirror of
https://github.com/invoke-ai/InvokeAI.git
synced 2026-04-23 03:00:31 -04:00
feat(ui): iterate on builder (WIP)
This commit is contained in:
@@ -1,8 +1,9 @@
|
||||
import type { ContainerElement } from 'features/nodes/types/workflow';
|
||||
import { createContext, useContext } from 'react';
|
||||
|
||||
export const ContainerDirectionContext = createContext<'row' | 'column' | null>(null);
|
||||
export const ContainerContext = createContext<ContainerElement['data'] | null>(null);
|
||||
|
||||
export const useContainerDirectionContext = () => {
|
||||
const containerDirection = useContext(ContainerDirectionContext);
|
||||
export const useContainerContext = () => {
|
||||
const containerDirection = useContext(ContainerContext);
|
||||
return containerDirection;
|
||||
};
|
||||
|
||||
@@ -1,6 +1,10 @@
|
||||
import { ContainerDirectionContext } from 'features/nodes/components/sidePanel/builder/ContainerContext';
|
||||
import { DividerElementComponent } from 'features/nodes/components/sidePanel/builder/DividerElementComponent';
|
||||
import { ElementWrapper } from 'features/nodes/components/sidePanel/builder/ElementWrapper';
|
||||
import { Flex, type SystemStyleObject } from '@invoke-ai/ui-library';
|
||||
import { getPrefixedId } from 'features/controlLayers/konva/util';
|
||||
import { ContainerContext } from 'features/nodes/components/sidePanel/builder/ContainerContext';
|
||||
import {
|
||||
DIVIDER_CLASS_NAME,
|
||||
DividerElementComponent,
|
||||
} from 'features/nodes/components/sidePanel/builder/DividerElementComponent';
|
||||
import { HeadingElementComponent } from 'features/nodes/components/sidePanel/builder/HeadingElementComponent';
|
||||
import { NodeFieldElementComponent } from 'features/nodes/components/sidePanel/builder/NodeFieldElementComponent';
|
||||
import { TextElementComponent } from 'features/nodes/components/sidePanel/builder/TextElementComponent';
|
||||
@@ -9,16 +13,30 @@ import { memo } from 'react';
|
||||
import type { Equals } from 'tsafe';
|
||||
import { assert } from 'tsafe';
|
||||
|
||||
const getGridTemplateColumns = (count: number) => {
|
||||
return Array.from({ length: count }, () => '1fr').join(' ');
|
||||
};
|
||||
const fill = (count: number, val: string, last?: string) => {
|
||||
return Array.from({ length: count }, (_, i) => {
|
||||
if (last && i === count - 1) {
|
||||
return last;
|
||||
}
|
||||
return val;
|
||||
}).join(' ');
|
||||
const CONTAINER_CLASS_NAME = getPrefixedId('container');
|
||||
|
||||
const sx: SystemStyleObject = {
|
||||
gap: 4,
|
||||
'&[data-container-direction="column"]': {
|
||||
flexDir: 'column',
|
||||
flex: '1 1 0',
|
||||
// Select all non-divider children (dividers have a fixed width that they define on their own)
|
||||
[`> *:not(.${DIVIDER_CLASS_NAME})`]: {
|
||||
// By default, all children should take up the same amount of space
|
||||
flex: '0 1 0',
|
||||
// The last child should take up the remaining space
|
||||
'&:last-child': {
|
||||
flex: '1 1 auto',
|
||||
},
|
||||
},
|
||||
},
|
||||
'&[data-container-direction="row"]': {
|
||||
// Select all non-divider children (dividers have a fixed width that they define on their own)
|
||||
[`> *:not(.${DIVIDER_CLASS_NAME})`]: {
|
||||
// By default, all children should take up the same amount of space
|
||||
flex: '1 1 0',
|
||||
},
|
||||
},
|
||||
};
|
||||
|
||||
export const ContainerElementComponent = memo(({ id }: { id: string }) => {
|
||||
@@ -31,13 +49,13 @@ export const ContainerElementComponent = memo(({ id }: { id: string }) => {
|
||||
const { children, direction } = element.data;
|
||||
|
||||
return (
|
||||
<ContainerDirectionContext.Provider value={direction}>
|
||||
<ElementWrapper id={id} gap={4} flexDir={direction}>
|
||||
<ContainerContext.Provider value={element.data}>
|
||||
<Flex id={id} className={CONTAINER_CLASS_NAME} sx={sx} data-container-direction={direction}>
|
||||
{children.map((childId) => (
|
||||
<FormElementComponent key={childId} id={childId} />
|
||||
))}
|
||||
</ElementWrapper>
|
||||
</ContainerDirectionContext.Provider>
|
||||
</Flex>
|
||||
</ContainerContext.Provider>
|
||||
);
|
||||
});
|
||||
ContainerElementComponent.displayName = 'ContainerElementComponent';
|
||||
|
||||
@@ -1,20 +1,18 @@
|
||||
import type { SystemStyleObject } from '@invoke-ai/ui-library';
|
||||
import { Flex } from '@invoke-ai/ui-library';
|
||||
import { useContainerDirectionContext } from 'features/nodes/components/sidePanel/builder/ContainerContext';
|
||||
import { getPrefixedId } from 'features/controlLayers/konva/util';
|
||||
import { memo } from 'react';
|
||||
|
||||
export const DividerElementComponent = memo(({ id }: { id: string }) => {
|
||||
const containerDirection = useContainerDirectionContext();
|
||||
export const DIVIDER_CLASS_NAME = getPrefixedId('divider');
|
||||
|
||||
return (
|
||||
<Flex
|
||||
flex="0 0 auto"
|
||||
id={id}
|
||||
h={containerDirection === 'column' ? '1px' : undefined}
|
||||
w={containerDirection === 'column' ? undefined : '1px'}
|
||||
bg="base.700"
|
||||
flexShrink={0}
|
||||
/>
|
||||
);
|
||||
const sx: SystemStyleObject = {
|
||||
flex: '0 0 1px',
|
||||
bg: 'base.700',
|
||||
flexShrink: 0,
|
||||
};
|
||||
|
||||
export const DividerElementComponent = memo(({ id }: { id: string }) => {
|
||||
return <Flex id={id} className={DIVIDER_CLASS_NAME} sx={sx} />;
|
||||
});
|
||||
|
||||
DividerElementComponent.displayName = 'DividerElementComponent';
|
||||
|
||||
@@ -1,12 +1,27 @@
|
||||
import type { FlexProps } from '@invoke-ai/ui-library';
|
||||
import type { FlexProps, SystemStyleObject } from '@invoke-ai/ui-library';
|
||||
import { Flex } from '@invoke-ai/ui-library';
|
||||
import { useContainerDirectionContext } from 'features/nodes/components/sidePanel/builder/ContainerContext';
|
||||
import { useContainerContext } from 'features/nodes/components/sidePanel/builder/ContainerContext';
|
||||
import type { PropsWithChildren } from 'react';
|
||||
import { memo } from 'react';
|
||||
|
||||
const sx: SystemStyleObject = {
|
||||
// '&[data-container-direction="column"]': {
|
||||
// flex: '1 1 auto',
|
||||
// },
|
||||
// '&[data-container-direction="column"] > :not(:last-child)': {
|
||||
// bg: 'red',
|
||||
// },
|
||||
};
|
||||
|
||||
export const ElementWrapper = memo((props: PropsWithChildren<FlexProps>) => {
|
||||
const containerDirection = useContainerDirectionContext();
|
||||
return <Flex flex={containerDirection === 'column' ? '1 1 0' : undefined} {...props} />;
|
||||
const container = useContainerContext();
|
||||
return (
|
||||
<Flex
|
||||
sx={sx}
|
||||
// data-container-direction={container?.direction}
|
||||
{...props}
|
||||
/>
|
||||
);
|
||||
});
|
||||
|
||||
ElementWrapper.displayName = 'ElementWrapper';
|
||||
|
||||
@@ -1,5 +1,4 @@
|
||||
import { Heading } from '@invoke-ai/ui-library';
|
||||
import { ElementWrapper } from 'features/nodes/components/sidePanel/builder/ElementWrapper';
|
||||
import { Flex, Heading } from '@invoke-ai/ui-library';
|
||||
import { useElement } from 'features/nodes/types/workflow';
|
||||
import { memo } from 'react';
|
||||
|
||||
@@ -21,9 +20,9 @@ export const HeadingElementComponent = memo(({ id }: { id: string }) => {
|
||||
const { content, level } = data;
|
||||
|
||||
return (
|
||||
<ElementWrapper id={id}>
|
||||
<Flex id={id}>
|
||||
<Heading size={LEVEL_TO_SIZE[level]}>{content}</Heading>
|
||||
</ElementWrapper>
|
||||
</Flex>
|
||||
);
|
||||
});
|
||||
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
import { Flex } from '@invoke-ai/ui-library';
|
||||
import { InputFieldGate } from 'features/nodes/components/flow/nodes/Invocation/fields/InputFieldGate';
|
||||
import { InputFieldViewMode } from 'features/nodes/components/flow/nodes/Invocation/fields/InputFieldViewMode';
|
||||
import { ElementWrapper } from 'features/nodes/components/sidePanel/builder/ElementWrapper';
|
||||
import { useElement } from 'features/nodes/types/workflow';
|
||||
import { memo } from 'react';
|
||||
|
||||
@@ -14,11 +14,11 @@ export const NodeFieldElementComponent = memo(({ id }: { id: string }) => {
|
||||
const { fieldIdentifier } = data;
|
||||
|
||||
return (
|
||||
<ElementWrapper id={id}>
|
||||
<Flex id={id}>
|
||||
<InputFieldGate nodeId={fieldIdentifier.nodeId} fieldName={fieldIdentifier.fieldName}>
|
||||
<InputFieldViewMode nodeId={fieldIdentifier.nodeId} fieldName={fieldIdentifier.fieldName} />
|
||||
</InputFieldGate>
|
||||
</ElementWrapper>
|
||||
</Flex>
|
||||
);
|
||||
});
|
||||
|
||||
|
||||
@@ -1,5 +1,4 @@
|
||||
import { Text } from '@invoke-ai/ui-library';
|
||||
import { ElementWrapper } from 'features/nodes/components/sidePanel/builder/ElementWrapper';
|
||||
import { Flex, Text } from '@invoke-ai/ui-library';
|
||||
import { useElement } from 'features/nodes/types/workflow';
|
||||
import { memo } from 'react';
|
||||
|
||||
@@ -13,9 +12,9 @@ export const TextElementComponent = memo(({ id }: { id: string }) => {
|
||||
const { content, fontSize } = data;
|
||||
|
||||
return (
|
||||
<ElementWrapper id={id}>
|
||||
<Flex id={id}>
|
||||
<Text fontSize={fontSize}>{content}</Text>
|
||||
</ElementWrapper>
|
||||
</Flex>
|
||||
);
|
||||
});
|
||||
|
||||
|
||||
Reference in New Issue
Block a user