feat(ui): iterate on builder (WIP)

This commit is contained in:
psychedelicious
2025-01-23 08:32:37 +11:00
parent d8c6531b70
commit 55973b4c66
8 changed files with 26 additions and 89 deletions

View File

@@ -1,42 +1,31 @@
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 { 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';
import { useElement } from 'features/nodes/types/workflow';
import { CONTAINER_CLASS_NAME, DIVIDER_CLASS_NAME, useElement } from 'features/nodes/types/workflow';
import { memo } from 'react';
import type { Equals } from 'tsafe';
import { assert } from 'tsafe';
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',
},
'> :last-child': {
flex: '1 0 0',
alignItems: 'flex-start',
},
},
'&[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',
},
},
[`& > .${DIVIDER_CLASS_NAME}`]: {
flex: '0 0 1px',
},
};
export const ContainerElementComponent = memo(({ id }: { id: string }) => {
@@ -59,34 +48,6 @@ export const ContainerElementComponent = memo(({ id }: { id: string }) => {
);
});
ContainerElementComponent.displayName = 'ContainerElementComponent';
// export const ContainerElementComponent = memo(({ id }: { id: string }) => {
// const element = useElement(id);
// if (!element || element.type !== 'container') {
// return null;
// }
// const { children, direction } = element.data;
// return (
// <GridItem
// as={Grid}
// id={id}
// gap={4}
// w="full"
// h="full"
// gridTemplateColumns={direction === 'row' ? fill(children.length, '1fr') : undefined}
// gridTemplateRows={direction === 'column' ? fill(children.length, 'min-content', '1fr') : undefined}
// gridAutoFlow={direction === 'column' ? 'row' : 'column'}
// alignItems="baseline"
// >
// {children.map((childId) => (
// <FormElementComponent key={childId} id={childId} />
// ))}
// </GridItem>
// );
// });
// ContainerElementComponent.displayName = 'ContainerElementComponent';
export const FormElementComponent = memo(({ id }: { id: string }) => {
const element = useElement(id);

View File

@@ -1,12 +1,9 @@
import type { SystemStyleObject } from '@invoke-ai/ui-library';
import { Flex } from '@invoke-ai/ui-library';
import { getPrefixedId } from 'features/controlLayers/konva/util';
import { DIVIDER_CLASS_NAME } from 'features/nodes/types/workflow';
import { memo } from 'react';
export const DIVIDER_CLASS_NAME = getPrefixedId('divider');
const sx: SystemStyleObject = {
flex: '0 0 1px',
bg: 'base.700',
flexShrink: 0,
};

View File

@@ -1,27 +0,0 @@
import type { FlexProps, SystemStyleObject } from '@invoke-ai/ui-library';
import { Flex } from '@invoke-ai/ui-library';
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 container = useContainerContext();
return (
<Flex
sx={sx}
// data-container-direction={container?.direction}
{...props}
/>
);
});
ElementWrapper.displayName = 'ElementWrapper';

View File

@@ -1,5 +1,5 @@
import { Flex, Heading } from '@invoke-ai/ui-library';
import { useElement } from 'features/nodes/types/workflow';
import { HEADING_CLASS_NAME, useElement } from 'features/nodes/types/workflow';
import { memo } from 'react';
const LEVEL_TO_SIZE = {
@@ -16,11 +16,11 @@ export const HeadingElementComponent = memo(({ id }: { id: string }) => {
if (!element || element.type !== 'heading') {
return null;
}
const { data } = element;
const { content, level } = data;
const { content, level } = element.data;
return (
<Flex id={id}>
<Flex id={id} className={HEADING_CLASS_NAME}>
<Heading size={LEVEL_TO_SIZE[level]}>{content}</Heading>
</Flex>
);

View File

@@ -1,7 +1,7 @@
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 { useElement } from 'features/nodes/types/workflow';
import { NODE_FIELD_CLASS_NAME, useElement } from 'features/nodes/types/workflow';
import { memo } from 'react';
export const NodeFieldElementComponent = memo(({ id }: { id: string }) => {
@@ -14,7 +14,7 @@ export const NodeFieldElementComponent = memo(({ id }: { id: string }) => {
const { fieldIdentifier } = data;
return (
<Flex id={id}>
<Flex id={id} className={NODE_FIELD_CLASS_NAME}>
<InputFieldGate nodeId={fieldIdentifier.nodeId} fieldName={fieldIdentifier.fieldName}>
<InputFieldViewMode nodeId={fieldIdentifier.nodeId} fieldName={fieldIdentifier.fieldName} />
</InputFieldGate>

View File

@@ -1,5 +1,5 @@
import { Flex, Text } from '@invoke-ai/ui-library';
import { useElement } from 'features/nodes/types/workflow';
import { TEXT_CLASS_NAME, useElement } from 'features/nodes/types/workflow';
import { memo } from 'react';
export const TextElementComponent = memo(({ id }: { id: string }) => {
@@ -12,7 +12,7 @@ export const TextElementComponent = memo(({ id }: { id: string }) => {
const { content, fontSize } = data;
return (
<Flex id={id}>
<Flex id={id} className={TEXT_CLASS_NAME}>
<Text fontSize={fontSize}>{content}</Text>
</Flex>
);

View File

@@ -7,8 +7,8 @@ import { memo } from 'react';
export const WorkflowBuilder = memo(() => {
return (
<ScrollableContent>
<Flex w="full" h="full" justifyContent="center">
<Flex w="full" h="full" maxW={512}>
<Flex w="full" justifyContent="center">
<Flex w="full" maxW={512}>
<FormElementComponent id={rootId} />
</Flex>
</Flex>

View File

@@ -113,6 +113,7 @@ const zElementBase = z.object({
});
const NODE_FIELD_TYPE = 'node-field';
export const NODE_FIELD_CLASS_NAME = getPrefixedId(NODE_FIELD_TYPE, '-');
const zNodeFieldElement = zElementBase.extend({
type: z.literal(NODE_FIELD_TYPE),
data: z.object({
@@ -136,6 +137,7 @@ const nodeField = (
};
const HEADING_TYPE = 'heading';
export const HEADING_CLASS_NAME = getPrefixedId(HEADING_TYPE, '-');
const zHeadingElement = zElementBase.extend({
type: z.literal(HEADING_TYPE),
data: z.object({
@@ -161,6 +163,7 @@ const heading = (
};
const TEXT_TYPE = 'text';
export const TEXT_CLASS_NAME = getPrefixedId(TEXT_TYPE, '-');
const zTextElement = zElementBase.extend({
type: z.literal(TEXT_TYPE),
data: z.object({
@@ -183,6 +186,7 @@ const text = (content: TextElement['data']['content'], fontSize: TextElement['da
};
const DIVIDER_TYPE = 'divider';
export const DIVIDER_CLASS_NAME = getPrefixedId(DIVIDER_TYPE, '-');
const zDividerElement = zElementBase.extend({
type: z.literal(DIVIDER_TYPE),
});
@@ -206,6 +210,7 @@ export type ContainerElement = {
};
const CONTAINER_TYPE = 'container';
export const CONTAINER_CLASS_NAME = getPrefixedId(CONTAINER_TYPE, '-');
const zContainerElement: z.ZodType<ContainerElement> = zElementBase.extend({
type: z.literal(CONTAINER_TYPE),
data: z.object({
@@ -239,6 +244,7 @@ export const rootId: string = container('column', [
divider().id,
heading('First Section', 2).id,
text('The first section includes fields relevant to the first section. This note describes that fact.', 'sm').id,
divider().id,
container('row', [
nodeField('7aed1a5f-7fd7-4184-abe8-ddea0ea5e706', 'image').id,
divider().id,