fix(ui): bump @invoke-ai/ui, fix TS issues

This commit is contained in:
psychedelicious 2024-01-20 20:03:12 +11:00
parent 580d29257c
commit be72765d02
40 changed files with 313 additions and 292 deletions

View File

@ -32,8 +32,8 @@
"fix": "eslint --fix . && prettier --log-level warn --write .", "fix": "eslint --fix . && prettier --log-level warn --write .",
"preinstall": "npx only-allow pnpm", "preinstall": "npx only-allow pnpm",
"postinstall": "pnpm run theme", "postinstall": "pnpm run theme",
"theme": "chakra-cli tokens --strict-component-types --strict-token-types node_modules/@invoke-ai/ui", "theme": "chakra-cli tokens node_modules/@invoke-ai/ui",
"theme:watch": "chakra-cli tokens --strict-component-types --strict-token-types node_modules/@invoke-ai/ui --watch", "theme:watch": "chakra-cli tokens node_modules/@invoke-ai/ui --watch",
"storybook": "storybook dev -p 6006", "storybook": "storybook dev -p 6006",
"build-storybook": "storybook build", "build-storybook": "storybook build",
"unimported": "npx unimported" "unimported": "npx unimported"
@ -66,7 +66,7 @@
"@emotion/react": "^11.11.3", "@emotion/react": "^11.11.3",
"@emotion/styled": "^11.11.0", "@emotion/styled": "^11.11.0",
"@fontsource-variable/inter": "^5.0.16", "@fontsource-variable/inter": "^5.0.16",
"@invoke-ai/ui": "file:/home/bat/Documents/Code/ui", "@invoke-ai/ui": "^0.0.8",
"@mantine/form": "6.0.21", "@mantine/form": "6.0.21",
"@nanostores/react": "^0.7.1", "@nanostores/react": "^0.7.1",
"@reduxjs/toolkit": "2.0.1", "@reduxjs/toolkit": "2.0.1",

View File

@ -53,8 +53,8 @@ dependencies:
specifier: ^5.0.16 specifier: ^5.0.16
version: 5.0.16 version: 5.0.16
'@invoke-ai/ui': '@invoke-ai/ui':
specifier: file:/home/bat/Documents/Code/ui specifier: ^0.0.8
version: file:../../../../ui(@chakra-ui/anatomy@2.2.2)(@chakra-ui/icons@2.1.1)(@chakra-ui/layout@2.3.1)(@chakra-ui/portal@2.1.0)(@chakra-ui/react@2.8.2)(@chakra-ui/styled-system@2.9.2)(@chakra-ui/theme-tools@2.1.2)(@emotion/react@11.11.3)(@emotion/styled@11.11.0)(@fontsource-variable/inter@5.0.16)(@nanostores/react@0.7.1)(chakra-react-select@4.7.6)(framer-motion@10.18.0)(lodash-es@4.17.21)(nanostores@0.9.5)(overlayscrollbars-react@0.5.3)(overlayscrollbars@2.4.6)(react-dom@18.2.0)(react-i18next@14.0.0)(react-select@5.8.0)(react@18.2.0) version: 0.0.8(@chakra-ui/anatomy@2.2.2)(@chakra-ui/icons@2.1.1)(@chakra-ui/layout@2.3.1)(@chakra-ui/portal@2.1.0)(@chakra-ui/react@2.8.2)(@chakra-ui/styled-system@2.9.2)(@chakra-ui/theme-tools@2.1.2)(@emotion/react@11.11.3)(@emotion/styled@11.11.0)(@fontsource-variable/inter@5.0.16)(@nanostores/react@0.7.1)(chakra-react-select@4.7.6)(framer-motion@10.18.0)(lodash-es@4.17.21)(nanostores@0.9.5)(overlayscrollbars-react@0.5.3)(overlayscrollbars@2.4.6)(react-dom@18.2.0)(react-i18next@14.0.0)(react-select@5.8.0)(react@18.2.0)
'@mantine/form': '@mantine/form':
specifier: 6.0.21 specifier: 6.0.21
version: 6.0.21(react@18.2.0) version: 6.0.21(react@18.2.0)
@ -3688,6 +3688,54 @@ packages:
resolution: {integrity: sha512-dvuCeX5fC9dXgJn9t+X5atfmgQAzUOWqS1254Gh0m6i8wKd10ebXkfNKiRK+1GWi/yTvvLDHpoxLr0xxxeslWw==} resolution: {integrity: sha512-dvuCeX5fC9dXgJn9t+X5atfmgQAzUOWqS1254Gh0m6i8wKd10ebXkfNKiRK+1GWi/yTvvLDHpoxLr0xxxeslWw==}
dev: true dev: true
/@invoke-ai/ui@0.0.8(@chakra-ui/anatomy@2.2.2)(@chakra-ui/icons@2.1.1)(@chakra-ui/layout@2.3.1)(@chakra-ui/portal@2.1.0)(@chakra-ui/react@2.8.2)(@chakra-ui/styled-system@2.9.2)(@chakra-ui/theme-tools@2.1.2)(@emotion/react@11.11.3)(@emotion/styled@11.11.0)(@fontsource-variable/inter@5.0.16)(@nanostores/react@0.7.1)(chakra-react-select@4.7.6)(framer-motion@10.18.0)(lodash-es@4.17.21)(nanostores@0.9.5)(overlayscrollbars-react@0.5.3)(overlayscrollbars@2.4.6)(react-dom@18.2.0)(react-i18next@14.0.0)(react-select@5.8.0)(react@18.2.0):
resolution: {integrity: sha512-FjW9rV2Bh1h+EDU5eMQH+oR4vpA77GBrAOdbuIezeDSVcmACU5tuJXIPxw121ZAsH2ioyhgGPMvfAsF1HkSigA==}
peerDependencies:
'@chakra-ui/anatomy': ^2.2.2
'@chakra-ui/icons': ^2.1.1
'@chakra-ui/layout': ^2.3.1
'@chakra-ui/portal': ^2.1.0
'@chakra-ui/react': ^2.8.2
'@chakra-ui/styled-system': ^2.9.2
'@chakra-ui/theme-tools': ^2.1.2
'@emotion/react': ^11.11.3
'@emotion/styled': ^11.11.0
'@fontsource-variable/inter': ^5.0.16
'@nanostores/react': ^0.7.1
chakra-react-select: ^4.7.6
framer-motion: ^10.18.0
lodash-es: ^4.17.21
nanostores: ^0.9.5
overlayscrollbars: ^2.4.6
overlayscrollbars-react: ^0.5.3
react: ^18.2.0
react-dom: ^18.2.0
react-i18next: ^14.0.0
react-select: ^5.8.0
dependencies:
'@chakra-ui/anatomy': 2.2.2
'@chakra-ui/icons': 2.1.1(@chakra-ui/system@2.6.2)(react@18.2.0)
'@chakra-ui/layout': 2.3.1(@chakra-ui/system@2.6.2)(react@18.2.0)
'@chakra-ui/portal': 2.1.0(react-dom@18.2.0)(react@18.2.0)
'@chakra-ui/react': 2.8.2(@emotion/react@11.11.3)(@emotion/styled@11.11.0)(@types/react@18.2.48)(framer-motion@10.18.0)(react-dom@18.2.0)(react@18.2.0)
'@chakra-ui/styled-system': 2.9.2
'@chakra-ui/theme-tools': 2.1.2(@chakra-ui/styled-system@2.9.2)
'@emotion/react': 11.11.3(@types/react@18.2.48)(react@18.2.0)
'@emotion/styled': 11.11.0(@emotion/react@11.11.3)(@types/react@18.2.48)(react@18.2.0)
'@fontsource-variable/inter': 5.0.16
'@nanostores/react': 0.7.1(nanostores@0.9.5)(react@18.2.0)
chakra-react-select: 4.7.6(@chakra-ui/form-control@2.2.0)(@chakra-ui/icon@3.2.0)(@chakra-ui/layout@2.3.1)(@chakra-ui/media-query@3.3.0)(@chakra-ui/menu@2.2.1)(@chakra-ui/spinner@2.1.0)(@chakra-ui/system@2.6.2)(@emotion/react@11.11.3)(@types/react@18.2.48)(react-dom@18.2.0)(react@18.2.0)
framer-motion: 10.18.0(react-dom@18.2.0)(react@18.2.0)
lodash-es: 4.17.21
nanostores: 0.9.5
overlayscrollbars: 2.4.6
overlayscrollbars-react: 0.5.3(overlayscrollbars@2.4.6)(react@18.2.0)
react: 18.2.0
react-dom: 18.2.0(react@18.2.0)
react-i18next: 14.0.0(i18next@23.7.16)(react-dom@18.2.0)(react@18.2.0)
react-select: 5.8.0(@types/react@18.2.48)(react-dom@18.2.0)(react@18.2.0)
dev: false
/@isaacs/cliui@8.0.2: /@isaacs/cliui@8.0.2:
resolution: {integrity: sha512-O8jcjabXaleOG9DQ0+ARXWZBTfnP4WNAqzuiJK7ll44AmxGKv/J2M4TPjxjY3znBCfvBXFzucm1twdyFybFqEA==} resolution: {integrity: sha512-O8jcjabXaleOG9DQ0+ARXWZBTfnP4WNAqzuiJK7ll44AmxGKv/J2M4TPjxjY3znBCfvBXFzucm1twdyFybFqEA==}
engines: {node: '>=12'} engines: {node: '>=12'}
@ -13745,53 +13793,3 @@ packages:
react: 18.2.0 react: 18.2.0
use-sync-external-store: 1.2.0(react@18.2.0) use-sync-external-store: 1.2.0(react@18.2.0)
dev: false dev: false
file:../../../../ui(@chakra-ui/anatomy@2.2.2)(@chakra-ui/icons@2.1.1)(@chakra-ui/layout@2.3.1)(@chakra-ui/portal@2.1.0)(@chakra-ui/react@2.8.2)(@chakra-ui/styled-system@2.9.2)(@chakra-ui/theme-tools@2.1.2)(@emotion/react@11.11.3)(@emotion/styled@11.11.0)(@fontsource-variable/inter@5.0.16)(@nanostores/react@0.7.1)(chakra-react-select@4.7.6)(framer-motion@10.18.0)(lodash-es@4.17.21)(nanostores@0.9.5)(overlayscrollbars-react@0.5.3)(overlayscrollbars@2.4.6)(react-dom@18.2.0)(react-i18next@14.0.0)(react-select@5.8.0)(react@18.2.0):
resolution: {directory: ../../../../ui, type: directory}
id: file:../../../../ui
name: '@invoke-ai/ui'
peerDependencies:
'@chakra-ui/anatomy': ^2.2.2
'@chakra-ui/icons': ^2.1.1
'@chakra-ui/layout': ^2.3.1
'@chakra-ui/portal': ^2.1.0
'@chakra-ui/react': ^2.8.2
'@chakra-ui/styled-system': ^2.9.2
'@chakra-ui/theme-tools': ^2.1.2
'@emotion/react': ^11.11.3
'@emotion/styled': ^11.11.0
'@fontsource-variable/inter': ^5.0.16
'@nanostores/react': ^0.7.1
chakra-react-select: ^4.7.6
framer-motion: ^10.18.0
lodash-es: ^4.17.21
nanostores: ^0.9.5
overlayscrollbars: ^2.4.6
overlayscrollbars-react: ^0.5.3
react: ^18.2.0
react-dom: ^18.2.0
react-i18next: ^14.0.0
react-select: ^5.8.0
dependencies:
'@chakra-ui/anatomy': 2.2.2
'@chakra-ui/icons': 2.1.1(@chakra-ui/system@2.6.2)(react@18.2.0)
'@chakra-ui/layout': 2.3.1(@chakra-ui/system@2.6.2)(react@18.2.0)
'@chakra-ui/portal': 2.1.0(react-dom@18.2.0)(react@18.2.0)
'@chakra-ui/react': 2.8.2(@emotion/react@11.11.3)(@emotion/styled@11.11.0)(@types/react@18.2.48)(framer-motion@10.18.0)(react-dom@18.2.0)(react@18.2.0)
'@chakra-ui/styled-system': 2.9.2
'@chakra-ui/theme-tools': 2.1.2(@chakra-ui/styled-system@2.9.2)
'@emotion/react': 11.11.3(@types/react@18.2.48)(react@18.2.0)
'@emotion/styled': 11.11.0(@emotion/react@11.11.3)(@types/react@18.2.48)(react@18.2.0)
'@fontsource-variable/inter': 5.0.16
'@nanostores/react': 0.7.1(nanostores@0.9.5)(react@18.2.0)
chakra-react-select: 4.7.6(@chakra-ui/form-control@2.2.0)(@chakra-ui/icon@3.2.0)(@chakra-ui/layout@2.3.1)(@chakra-ui/media-query@3.3.0)(@chakra-ui/menu@2.2.1)(@chakra-ui/spinner@2.1.0)(@chakra-ui/system@2.6.2)(@emotion/react@11.11.3)(@types/react@18.2.48)(react-dom@18.2.0)(react@18.2.0)
framer-motion: 10.18.0(react-dom@18.2.0)(react@18.2.0)
lodash-es: 4.17.21
nanostores: 0.9.5
overlayscrollbars: 2.4.6
overlayscrollbars-react: 0.5.3(overlayscrollbars@2.4.6)(react@18.2.0)
react: 18.2.0
react-dom: 18.2.0(react@18.2.0)
react-i18next: 14.0.0(i18next@23.7.16)(react-dom@18.2.0)(react@18.2.0)
react-select: 5.8.0(@types/react@18.2.48)(react-dom@18.2.0)(react@18.2.0)
dev: false

View File

@ -28,51 +28,48 @@ type Props = {
children: ReactElement; children: ReactElement;
}; };
const IAIInformationalPopover = ({ export const InformationalPopover = memo(
feature, ({ feature, children, inPortal = true, ...rest }: Props) => {
children, const shouldEnableInformationalPopovers = useAppSelector(
inPortal = true, (s) => s.system.shouldEnableInformationalPopovers
...rest );
}: Props) => {
const shouldEnableInformationalPopovers = useAppSelector(
(s) => s.system.shouldEnableInformationalPopovers
);
const data = useMemo(() => POPOVER_DATA[feature], [feature]); const data = useMemo(() => POPOVER_DATA[feature], [feature]);
const popoverProps = useMemo( const popoverProps = useMemo(
() => merge(omit(data, ['image', 'href', 'buttonLabel']), rest), () => merge(omit(data, ['image', 'href', 'buttonLabel']), rest),
[data, rest] [data, rest]
); );
if (!shouldEnableInformationalPopovers) { if (!shouldEnableInformationalPopovers) {
return children; return children;
} }
return ( return (
<Popover <Popover
isLazy isLazy
closeOnBlur={false} closeOnBlur={false}
trigger="hover" trigger="hover"
variant="informational" variant="informational"
openDelay={OPEN_DELAY} openDelay={OPEN_DELAY}
modifiers={POPPER_MODIFIERS} modifiers={POPPER_MODIFIERS}
placement="top" placement="top"
{...popoverProps} {...popoverProps}
> >
<PopoverTrigger>{children}</PopoverTrigger> <PopoverTrigger>{children}</PopoverTrigger>
{inPortal ? ( {inPortal ? (
<Portal> <Portal>
<Content data={data} feature={feature} />
</Portal>
) : (
<Content data={data} feature={feature} /> <Content data={data} feature={feature} />
</Portal> )}
) : ( </Popover>
<Content data={data} feature={feature} /> );
)} }
</Popover> );
);
};
export default memo(IAIInformationalPopover); InformationalPopover.displayName = 'InformationalPopover';
type ContentProps = { type ContentProps = {
data?: PopoverData; data?: PopoverData;

View File

@ -1,40 +0,0 @@
import { Box, forwardRef, Textarea as ChakraTextarea } from '@invoke-ai/ui';
import { useGlobalModifiersSetters } from 'common/hooks/useGlobalModifiers';
import { stopPastePropagation } from 'common/util/stopPastePropagation';
import type { KeyboardEvent } from 'react';
import { memo, useCallback } from 'react';
import ResizeTextarea from 'react-textarea-autosize';
import type { InvAutosizeTextareaProps } from './types';
export const InvAutosizeTextarea = memo(
forwardRef<InvAutosizeTextareaProps, typeof ResizeTextarea>(
(props: InvAutosizeTextareaProps, ref) => {
const { setShift } = useGlobalModifiersSetters();
const onKeyUpDown = useCallback(
(e: KeyboardEvent<HTMLTextAreaElement>) => {
setShift(e.shiftKey);
},
[setShift]
);
return (
<Box pos="relative">
<ChakraTextarea
as={ResizeTextarea}
ref={ref}
overflow="scroll"
w="100%"
minRows={3}
minH={20}
onPaste={stopPastePropagation}
onKeyUp={onKeyUpDown}
onKeyDown={onKeyUpDown}
{...props}
/>
</Box>
);
}
)
);
InvAutosizeTextarea.displayName = 'InvAutosizeTextarea';

View File

@ -1,21 +0,0 @@
import type { Meta, StoryObj } from '@storybook/react';
import { InvAutosizeTextarea } from './InvAutosizeTextarea';
import type { InvAutosizeTextareaProps } from './types';
const meta: Meta<typeof InvAutosizeTextarea> = {
title: 'Primitives/InvAutosizeTextarea',
tags: ['autodocs'],
component: InvAutosizeTextarea,
};
export default meta;
type Story = StoryObj<typeof InvAutosizeTextarea>;
const Component = (props: InvAutosizeTextareaProps) => {
return <InvAutosizeTextarea {...props} />;
};
export const Default: Story = {
render: Component,
};

View File

@ -1,7 +0,0 @@
import type { TextareaProps as ChakraTextareaProps } from '@invoke-ai/ui';
import type { TextareaAutosizeProps } from 'react-textarea-autosize';
export type InvAutosizeTextareaProps = Omit<
ChakraTextareaProps & TextareaAutosizeProps,
'resize'
>;

View File

@ -1,6 +1,7 @@
import type { ComboboxOnChange } from '@invoke-ai/ui'; import type { ComboboxOnChange } from '@invoke-ai/ui';
import { Combobox, FormControl, FormLabel } from '@invoke-ai/ui'; import { Combobox, FormControl, FormLabel } from '@invoke-ai/ui';
import { useAppDispatch } from 'app/store/storeHooks'; import { useAppDispatch } from 'app/store/storeHooks';
import { InformationalPopover } from 'common/components/InformationalPopover/InformationalPopover';
import { useControlAdapterControlMode } from 'features/controlAdapters/hooks/useControlAdapterControlMode'; import { useControlAdapterControlMode } from 'features/controlAdapters/hooks/useControlAdapterControlMode';
import { useControlAdapterIsEnabled } from 'features/controlAdapters/hooks/useControlAdapterIsEnabled'; import { useControlAdapterIsEnabled } from 'features/controlAdapters/hooks/useControlAdapterIsEnabled';
import { controlAdapterControlModeChanged } from 'features/controlAdapters/store/controlAdaptersSlice'; import { controlAdapterControlModeChanged } from 'features/controlAdapters/store/controlAdaptersSlice';
@ -53,8 +54,10 @@ const ParamControlAdapterControlMode = ({ id }: Props) => {
} }
return ( return (
<FormControl isDisabled={!isEnabled} feature="controlNetControlMode"> <FormControl isDisabled={!isEnabled}>
<FormLabel>{t('controlnet.controlMode')}</FormLabel> <InformationalPopover feature="controlNetControlMode">
<FormLabel>{t('controlnet.controlMode')}</FormLabel>
</InformationalPopover>
<Combobox <Combobox
value={value} value={value}
options={CONTROL_MODE_DATA} options={CONTROL_MODE_DATA}

View File

@ -1,6 +1,7 @@
import type { ComboboxOnChange } from '@invoke-ai/ui'; import type { ComboboxOnChange } from '@invoke-ai/ui';
import { Combobox, FormControl, FormLabel } from '@invoke-ai/ui'; import { Combobox, FormControl, FormLabel } from '@invoke-ai/ui';
import { useAppDispatch } from 'app/store/storeHooks'; import { useAppDispatch } from 'app/store/storeHooks';
import { InformationalPopover } from 'common/components/InformationalPopover/InformationalPopover';
import { useControlAdapterIsEnabled } from 'features/controlAdapters/hooks/useControlAdapterIsEnabled'; import { useControlAdapterIsEnabled } from 'features/controlAdapters/hooks/useControlAdapterIsEnabled';
import { useControlAdapterResizeMode } from 'features/controlAdapters/hooks/useControlAdapterResizeMode'; import { useControlAdapterResizeMode } from 'features/controlAdapters/hooks/useControlAdapterResizeMode';
import { controlAdapterResizeModeChanged } from 'features/controlAdapters/store/controlAdaptersSlice'; import { controlAdapterResizeModeChanged } from 'features/controlAdapters/store/controlAdaptersSlice';
@ -54,8 +55,10 @@ const ParamControlAdapterResizeMode = ({ id }: Props) => {
} }
return ( return (
<FormControl feature="controlNetResizeMode"> <FormControl>
<FormLabel>{t('controlnet.resizeMode')}</FormLabel> <InformationalPopover feature="controlNetResizeMode">
<FormLabel>{t('controlnet.resizeMode')}</FormLabel>
</InformationalPopover>
<Combobox <Combobox
value={value} value={value}
options={options} options={options}

View File

@ -5,6 +5,7 @@ import {
FormLabel, FormLabel,
} from '@invoke-ai/ui'; } from '@invoke-ai/ui';
import { useAppDispatch, useAppSelector } from 'app/store/storeHooks'; import { useAppDispatch, useAppSelector } from 'app/store/storeHooks';
import { InformationalPopover } from 'common/components/InformationalPopover/InformationalPopover';
import { useControlAdapterIsEnabled } from 'features/controlAdapters/hooks/useControlAdapterIsEnabled'; import { useControlAdapterIsEnabled } from 'features/controlAdapters/hooks/useControlAdapterIsEnabled';
import { useControlAdapterWeight } from 'features/controlAdapters/hooks/useControlAdapterWeight'; import { useControlAdapterWeight } from 'features/controlAdapters/hooks/useControlAdapterWeight';
import { controlAdapterWeightChanged } from 'features/controlAdapters/store/controlAdaptersSlice'; import { controlAdapterWeightChanged } from 'features/controlAdapters/store/controlAdaptersSlice';
@ -48,8 +49,10 @@ const ParamControlAdapterWeight = ({ id }: ParamControlAdapterWeightProps) => {
} }
return ( return (
<FormControl isDisabled={!isEnabled} feature="controlNetWeight"> <FormControl isDisabled={!isEnabled}>
<FormLabel>{t('controlnet.weight')}</FormLabel> <InformationalPopover feature="controlNetWeight">
<FormLabel>{t('controlnet.weight')}</FormLabel>
</InformationalPopover>
<CompositeSlider <CompositeSlider
value={weight} value={weight}
onChange={onChange} onChange={onChange}

View File

@ -25,7 +25,7 @@ export const DynamicPromptsModal = memo(() => {
<ModalContent w="80vw" h="80vh" maxW="unset" maxH="unset"> <ModalContent w="80vw" h="80vh" maxW="unset" maxH="unset">
<ModalHeader>{t('dynamicPrompts.dynamicPrompts')}</ModalHeader> <ModalHeader>{t('dynamicPrompts.dynamicPrompts')}</ModalHeader>
<ModalCloseButton /> <ModalCloseButton />
<ModalBody as={Flex} flexDir="column" gap={2} w="full" h="full" pb={4}> <ModalBody as={Flex} flexDir="column" gap={4} w="full" h="full" pb={4}>
<Flex gap={4}> <Flex gap={4}>
<ParamDynamicPromptsSeedBehaviour /> <ParamDynamicPromptsSeedBehaviour />
<ParamDynamicPromptsMaxPrompts /> <ParamDynamicPromptsMaxPrompts />

View File

@ -5,6 +5,7 @@ import {
FormLabel, FormLabel,
} from '@invoke-ai/ui'; } from '@invoke-ai/ui';
import { useAppDispatch, useAppSelector } from 'app/store/storeHooks'; import { useAppDispatch, useAppSelector } from 'app/store/storeHooks';
import { InformationalPopover } from 'common/components/InformationalPopover/InformationalPopover';
import { maxPromptsChanged } from 'features/dynamicPrompts/store/dynamicPromptsSlice'; import { maxPromptsChanged } from 'features/dynamicPrompts/store/dynamicPromptsSlice';
import { memo, useCallback } from 'react'; import { memo, useCallback } from 'react';
import { useTranslation } from 'react-i18next'; import { useTranslation } from 'react-i18next';
@ -38,12 +39,10 @@ const ParamDynamicPromptsMaxPrompts = () => {
); );
return ( return (
<FormControl <FormControl isDisabled={isDisabled}>
isDisabled={isDisabled} <InformationalPopover feature="dynamicPromptsMaxPrompts" inPortal={false}>
feature="dynamicPromptsMaxPrompts" <FormLabel>{t('dynamicPrompts.maxPrompts')}</FormLabel>
renderInfoPopoverInPortal={false} </InformationalPopover>
>
<FormLabel>{t('dynamicPrompts.maxPrompts')}</FormLabel>
<CompositeSlider <CompositeSlider
min={sliderMin} min={sliderMin}
max={sliderMax} max={sliderMax}

View File

@ -1,9 +1,17 @@
import type { ChakraProps } from '@invoke-ai/ui'; import type { ChakraProps } from '@invoke-ai/ui';
import { Flex, ListItem, OrderedList, Spinner, Text } from '@invoke-ai/ui'; import {
Flex,
FormControl,
FormLabel,
ListItem,
OrderedList,
Spinner,
Text,
} from '@invoke-ai/ui';
import { createMemoizedSelector } from 'app/store/createMemoizedSelector'; import { createMemoizedSelector } from 'app/store/createMemoizedSelector';
import { useAppSelector } from 'app/store/storeHooks'; import { useAppSelector } from 'app/store/storeHooks';
import { IAINoContentFallback } from 'common/components/IAIImageFallback'; import { IAINoContentFallback } from 'common/components/IAIImageFallback';
import IAIInformationalPopover from 'common/components/IAIInformationalPopover/IAIInformationalPopover'; import { InformationalPopover } from 'common/components/InformationalPopover/InformationalPopover';
import ScrollableContent from 'common/components/OverlayScrollbars/ScrollableContent'; import ScrollableContent from 'common/components/OverlayScrollbars/ScrollableContent';
import { selectDynamicPromptsSlice } from 'features/dynamicPrompts/store/dynamicPromptsSlice'; import { selectDynamicPromptsSlice } from 'features/dynamicPrompts/store/dynamicPromptsSlice';
import { memo, useMemo } from 'react'; import { memo, useMemo } from 'react';
@ -36,29 +44,27 @@ const ParamDynamicPromptsPreview = () => {
if (isError) { if (isError) {
return ( return (
<IAIInformationalPopover feature="dynamicPrompts"> <Flex
<Flex w="full"
w="full" h="full"
h="full" layerStyle="second"
layerStyle="second" alignItems="center"
alignItems="center" justifyContent="center"
justifyContent="center" p={8}
p={8} >
> <IAINoContentFallback
<IAINoContentFallback icon={PiWarningCircleBold}
icon={PiWarningCircleBold} label="Problem generating prompts"
label="Problem generating prompts" />
/> </Flex>
</Flex>
</IAIInformationalPopover>
); );
} }
return ( return (
<> <FormControl orientation="vertical" w="full" h="full">
<Text fontSize="sm" fontWeight="bold"> <InformationalPopover feature="dynamicPrompts" inPortal={false}>
{label} <FormLabel>{label}</FormLabel>
</Text> </InformationalPopover>
<Flex <Flex
w="full" w="full"
h="full" h="full"
@ -96,7 +102,7 @@ const ParamDynamicPromptsPreview = () => {
</Flex> </Flex>
)} )}
</Flex> </Flex>
</> </FormControl>
); );
}; };

View File

@ -1,6 +1,7 @@
import type { ComboboxOnChange, ComboboxOption } from '@invoke-ai/ui'; import type { ComboboxOnChange, ComboboxOption } from '@invoke-ai/ui';
import { Combobox, FormControl, FormLabel } from '@invoke-ai/ui'; import { Combobox, FormControl, FormLabel } from '@invoke-ai/ui';
import { useAppDispatch, useAppSelector } from 'app/store/storeHooks'; import { useAppDispatch, useAppSelector } from 'app/store/storeHooks';
import { InformationalPopover } from 'common/components/InformationalPopover/InformationalPopover';
import { import {
isSeedBehaviour, isSeedBehaviour,
seedBehaviourChanged, seedBehaviourChanged,
@ -44,11 +45,13 @@ const ParamDynamicPromptsSeedBehaviour = () => {
); );
return ( return (
<FormControl <FormControl>
feature="dynamicPromptsSeedBehaviour" <InformationalPopover
renderInfoPopoverInPortal={false} feature="dynamicPromptsSeedBehaviour"
> inPortal={false}
<FormLabel>{t('dynamicPrompts.seedBehaviour.label')}</FormLabel> >
<FormLabel>{t('dynamicPrompts.seedBehaviour.label')}</FormLabel>
</InformationalPopover>
<Combobox value={value} options={options} onChange={handleChange} /> <Combobox value={value} options={options} onChange={handleChange} />
</FormControl> </FormControl>
); );

View File

@ -3,6 +3,7 @@ import {
Checkbox, Checkbox,
Flex, Flex,
FormControl, FormControl,
FormErrorMessage,
FormLabel, FormLabel,
Input, Input,
} from '@invoke-ai/ui'; } from '@invoke-ai/ui';
@ -120,10 +121,7 @@ const AdvancedAddCheckpoint = (props: AdvancedAddCheckpointProps) => {
return ( return (
<form onSubmit={handleSubmit(onSubmit)} style={formStyles}> <form onSubmit={handleSubmit(onSubmit)} style={formStyles}>
<Flex flexDirection="column" gap={2}> <Flex flexDirection="column" gap={2}>
<FormControl <FormControl isInvalid={Boolean(errors.model_name)}>
isInvalid={Boolean(errors.model_name)}
error={errors.model_name?.message}
>
<FormLabel>{t('modelManager.model')}</FormLabel> <FormLabel>{t('modelManager.model')}</FormLabel>
<Input <Input
{...register('model_name', { {...register('model_name', {
@ -131,15 +129,15 @@ const AdvancedAddCheckpoint = (props: AdvancedAddCheckpointProps) => {
value.trim().length > 3 || 'Must be at least 3 characters', value.trim().length > 3 || 'Must be at least 3 characters',
})} })}
/> />
{errors.model_name?.message && (
<FormErrorMessage>{errors.model_name?.message}</FormErrorMessage>
)}
</FormControl> </FormControl>
<BaseModelSelect<CheckpointModelConfig> <BaseModelSelect<CheckpointModelConfig>
control={control} control={control}
name="base_model" name="base_model"
/> />
<FormControl <FormControl isInvalid={Boolean(errors.path)}>
isInvalid={Boolean(errors.path)}
error={errors.path?.message}
>
<FormLabel>{t('modelManager.modelLocation')}</FormLabel> <FormLabel>{t('modelManager.modelLocation')}</FormLabel>
<Input <Input
{...register('path', { {...register('path', {
@ -148,6 +146,9 @@ const AdvancedAddCheckpoint = (props: AdvancedAddCheckpointProps) => {
onBlur, onBlur,
})} })}
/> />
{errors.path?.message && (
<FormErrorMessage>{errors.path?.message}</FormErrorMessage>
)}
</FormControl> </FormControl>
<FormControl> <FormControl>
<FormLabel>{t('modelManager.description')}</FormLabel> <FormLabel>{t('modelManager.description')}</FormLabel>

View File

@ -1,4 +1,11 @@
import { Button, Flex, FormControl, FormLabel, Input } from '@invoke-ai/ui'; import {
Button,
Flex,
FormControl,
FormErrorMessage,
FormLabel,
Input,
} from '@invoke-ai/ui';
import { useAppDispatch } from 'app/store/storeHooks'; import { useAppDispatch } from 'app/store/storeHooks';
import { setAdvancedAddScanModel } from 'features/modelManager/store/modelManagerSlice'; import { setAdvancedAddScanModel } from 'features/modelManager/store/modelManagerSlice';
import BaseModelSelect from 'features/modelManager/subpanels/shared/BaseModelSelect'; import BaseModelSelect from 'features/modelManager/subpanels/shared/BaseModelSelect';
@ -103,10 +110,7 @@ const AdvancedAddDiffusers = (props: AdvancedAddDiffusersProps) => {
return ( return (
<form onSubmit={handleSubmit(onSubmit)} style={formStyles}> <form onSubmit={handleSubmit(onSubmit)} style={formStyles}>
<Flex flexDirection="column" gap={2}> <Flex flexDirection="column" gap={2}>
<FormControl <FormControl isInvalid={Boolean(errors.model_name)}>
isInvalid={Boolean(errors.model_name)}
error={errors.model_name?.message}
>
<FormLabel>{t('modelManager.name')}</FormLabel> <FormLabel>{t('modelManager.name')}</FormLabel>
<Input <Input
{...register('model_name', { {...register('model_name', {
@ -114,6 +118,9 @@ const AdvancedAddDiffusers = (props: AdvancedAddDiffusersProps) => {
value.trim().length > 3 || 'Must be at least 3 characters', value.trim().length > 3 || 'Must be at least 3 characters',
})} })}
/> />
{errors.model_name?.message && (
<FormErrorMessage>{errors.model_name?.message}</FormErrorMessage>
)}
</FormControl> </FormControl>
<FormControl> <FormControl>
<FormLabel>{t('modelManager.baseModel')}</FormLabel> <FormLabel>{t('modelManager.baseModel')}</FormLabel>
@ -122,10 +129,7 @@ const AdvancedAddDiffusers = (props: AdvancedAddDiffusersProps) => {
name="base_model" name="base_model"
/> />
</FormControl> </FormControl>
<FormControl <FormControl isInvalid={Boolean(errors.path)}>
isInvalid={Boolean(errors.path)}
error={errors.path?.message}
>
<FormLabel>{t('modelManager.modelLocation')}</FormLabel> <FormLabel>{t('modelManager.modelLocation')}</FormLabel>
<Input <Input
{...register('path', { {...register('path', {
@ -133,7 +137,10 @@ const AdvancedAddDiffusers = (props: AdvancedAddDiffusersProps) => {
value.trim().length > 0 || 'Must provide a path', value.trim().length > 0 || 'Must provide a path',
onBlur, onBlur,
})} })}
/> />{' '}
{errors.path?.message && (
<FormErrorMessage>{errors.path?.message}</FormErrorMessage>
)}
</FormControl> </FormControl>
<FormControl> <FormControl>
<FormLabel>{t('modelManager.description')}</FormLabel> <FormLabel>{t('modelManager.description')}</FormLabel>

View File

@ -7,6 +7,7 @@ import {
CompositeSlider, CompositeSlider,
Flex, Flex,
FormControl, FormControl,
FormHelperText,
FormLabel, FormLabel,
Input, Input,
Radio, Radio,
@ -318,7 +319,7 @@ const MergeModelsPanel = () => {
gap={4} gap={4}
bg="base.800" bg="base.800"
> >
<FormControl helperText={t('modelManager.modelMergeAlphaHelp')}> <FormControl>
<FormLabel>{t('modelManager.alpha')}</FormLabel> <FormLabel>{t('modelManager.alpha')}</FormLabel>
<CompositeSlider <CompositeSlider
min={0.01} min={0.01}
@ -337,6 +338,9 @@ const MergeModelsPanel = () => {
onChange={handleChangeModelMergeAlpha} onChange={handleChangeModelMergeAlpha}
onReset={handleResetModelMergeAlpha} onReset={handleResetModelMergeAlpha}
/> />
<FormHelperText>
{t('modelManager.modelMergeAlphaHelp')}
</FormHelperText>
</FormControl> </FormControl>
</Flex> </Flex>

View File

@ -5,6 +5,7 @@ import {
Divider, Divider,
Flex, Flex,
FormControl, FormControl,
FormErrorMessage,
FormLabel, FormLabel,
Input, Input,
Text, Text,
@ -139,10 +140,7 @@ const CheckpointModelEdit = (props: CheckpointModelEditProps) => {
> >
<form onSubmit={handleSubmit(onSubmit)}> <form onSubmit={handleSubmit(onSubmit)}>
<Flex flexDirection="column" overflowY="scroll" gap={4}> <Flex flexDirection="column" overflowY="scroll" gap={4}>
<FormControl <FormControl isInvalid={Boolean(errors.model_name)}>
isInvalid={Boolean(errors.model_name)}
error={errors.model_name?.message}
>
<FormLabel>{t('modelManager.name')}</FormLabel> <FormLabel>{t('modelManager.name')}</FormLabel>
<Input <Input
{...register('model_name', { {...register('model_name', {
@ -150,6 +148,11 @@ const CheckpointModelEdit = (props: CheckpointModelEditProps) => {
value.trim().length > 3 || 'Must be at least 3 characters', value.trim().length > 3 || 'Must be at least 3 characters',
})} })}
/> />
{errors.model_name?.message && (
<FormErrorMessage>
{errors.model_name?.message}
</FormErrorMessage>
)}
</FormControl> </FormControl>
<FormControl> <FormControl>
<FormLabel>{t('modelManager.description')}</FormLabel> <FormLabel>{t('modelManager.description')}</FormLabel>
@ -163,10 +166,7 @@ const CheckpointModelEdit = (props: CheckpointModelEditProps) => {
control={control} control={control}
name="variant" name="variant"
/> />
<FormControl <FormControl isInvalid={Boolean(errors.path)}>
isInvalid={Boolean(errors.path)}
error={errors.path?.message}
>
<FormLabel>{t('modelManager.modelLocation')}</FormLabel> <FormLabel>{t('modelManager.modelLocation')}</FormLabel>
<Input <Input
{...register('path', { {...register('path', {
@ -174,6 +174,9 @@ const CheckpointModelEdit = (props: CheckpointModelEditProps) => {
value.trim().length > 0 || 'Must provide a path', value.trim().length > 0 || 'Must provide a path',
})} })}
/> />
{errors.path?.message && (
<FormErrorMessage>{errors.path?.message}</FormErrorMessage>
)}
</FormControl> </FormControl>
<FormControl> <FormControl>
<FormLabel>{t('modelManager.vaeLocation')}</FormLabel> <FormLabel>{t('modelManager.vaeLocation')}</FormLabel>

View File

@ -3,6 +3,7 @@ import {
Divider, Divider,
Flex, Flex,
FormControl, FormControl,
FormErrorMessage,
FormLabel, FormLabel,
Input, Input,
Text, Text,
@ -103,10 +104,7 @@ const DiffusersModelEdit = (props: DiffusersModelEditProps) => {
<form onSubmit={handleSubmit(onSubmit)}> <form onSubmit={handleSubmit(onSubmit)}>
<Flex flexDirection="column" overflowY="scroll" gap={4}> <Flex flexDirection="column" overflowY="scroll" gap={4}>
<FormControl <FormControl isInvalid={Boolean(errors.model_name)}>
isInvalid={Boolean(errors.model_name)}
error={errors.model_name?.message}
>
<FormLabel>{t('modelManager.name')}</FormLabel> <FormLabel>{t('modelManager.name')}</FormLabel>
<Input <Input
{...register('model_name', { {...register('model_name', {
@ -114,6 +112,9 @@ const DiffusersModelEdit = (props: DiffusersModelEditProps) => {
value.trim().length > 3 || 'Must be at least 3 characters', value.trim().length > 3 || 'Must be at least 3 characters',
})} })}
/> />
{errors.model_name?.message && (
<FormErrorMessage>{errors.model_name?.message}</FormErrorMessage>
)}
</FormControl> </FormControl>
<FormControl> <FormControl>
<FormLabel>{t('modelManager.description')}</FormLabel> <FormLabel>{t('modelManager.description')}</FormLabel>
@ -127,10 +128,7 @@ const DiffusersModelEdit = (props: DiffusersModelEditProps) => {
control={control} control={control}
name="variant" name="variant"
/> />
<FormControl <FormControl isInvalid={Boolean(errors.path)}>
isInvalid={Boolean(errors.path)}
error={errors.path?.message}
>
<FormLabel>{t('modelManager.modelLocation')}</FormLabel> <FormLabel>{t('modelManager.modelLocation')}</FormLabel>
<Input <Input
{...register('path', { {...register('path', {
@ -138,6 +136,9 @@ const DiffusersModelEdit = (props: DiffusersModelEditProps) => {
value.trim().length > 0 || 'Must provide a path', value.trim().length > 0 || 'Must provide a path',
})} })}
/> />
{errors.path?.message && (
<FormErrorMessage>{errors.path?.message}</FormErrorMessage>
)}
</FormControl> </FormControl>
<FormControl> <FormControl>
<FormLabel>{t('modelManager.vaeLocation')}</FormLabel> <FormLabel>{t('modelManager.vaeLocation')}</FormLabel>

View File

@ -3,6 +3,7 @@ import {
Divider, Divider,
Flex, Flex,
FormControl, FormControl,
FormErrorMessage,
FormLabel, FormLabel,
Input, Input,
Text, Text,
@ -104,10 +105,7 @@ const LoRAModelEdit = (props: LoRAModelEditProps) => {
<form onSubmit={handleSubmit(onSubmit)}> <form onSubmit={handleSubmit(onSubmit)}>
<Flex flexDirection="column" overflowY="scroll" gap={4}> <Flex flexDirection="column" overflowY="scroll" gap={4}>
<FormControl <FormControl isInvalid={Boolean(errors.model_name)}>
isInvalid={Boolean(errors.model_name)}
error={errors.model_name?.message}
>
<FormLabel>{t('modelManager.name')}</FormLabel> <FormLabel>{t('modelManager.name')}</FormLabel>
<Input <Input
{...register('model_name', { {...register('model_name', {
@ -115,6 +113,9 @@ const LoRAModelEdit = (props: LoRAModelEditProps) => {
value.trim().length > 3 || 'Must be at least 3 characters', value.trim().length > 3 || 'Must be at least 3 characters',
})} })}
/> />
{errors.model_name?.message && (
<FormErrorMessage>{errors.model_name?.message}</FormErrorMessage>
)}
</FormControl> </FormControl>
<FormControl> <FormControl>
<FormLabel>{t('modelManager.description')}</FormLabel> <FormLabel>{t('modelManager.description')}</FormLabel>
@ -125,10 +126,7 @@ const LoRAModelEdit = (props: LoRAModelEditProps) => {
name="base_model" name="base_model"
/> />
<FormControl <FormControl isInvalid={Boolean(errors.path)}>
isInvalid={Boolean(errors.path)}
error={errors.path?.message}
>
<FormLabel>{t('modelManager.modelLocation')}</FormLabel> <FormLabel>{t('modelManager.modelLocation')}</FormLabel>
<Input <Input
{...register('path', { {...register('path', {
@ -136,6 +134,9 @@ const LoRAModelEdit = (props: LoRAModelEditProps) => {
value.trim().length > 0 || 'Must provide a path', value.trim().length > 0 || 'Must provide a path',
})} })}
/> />
{errors.path?.message && (
<FormErrorMessage>{errors.path?.message}</FormErrorMessage>
)}
</FormControl> </FormControl>
<Button type="submit" isLoading={isLoading}> <Button type="submit" isLoading={isLoading}>
{t('modelManager.updateModel')} {t('modelManager.updateModel')}

View File

@ -2,6 +2,7 @@ import {
Divider, Divider,
Flex, Flex,
FormControl, FormControl,
FormHelperText,
FormLabel, FormLabel,
Heading, Heading,
Modal, Modal,
@ -110,46 +111,55 @@ const WorkflowEditorSettings = ({ children }: Props) => {
<ModalBody> <ModalBody>
<Flex flexDirection="column" gap={4} py={4}> <Flex flexDirection="column" gap={4} py={4}>
<Heading size="sm">{t('parameters.general')}</Heading> <Heading size="sm">{t('parameters.general')}</Heading>
<FormControl helperText={t('nodes.animatedEdgesHelp')}> <FormControl>
<FormLabel>{t('nodes.animatedEdges')}</FormLabel> <FormLabel>{t('nodes.animatedEdges')}</FormLabel>
<Switch <Switch
onChange={handleChangeShouldAnimate} onChange={handleChangeShouldAnimate}
isChecked={shouldAnimateEdges} isChecked={shouldAnimateEdges}
/> />
<FormHelperText>{t('nodes.animatedEdgesHelp')}</FormHelperText>
</FormControl> </FormControl>
<Divider /> <Divider />
<FormControl helperText={t('nodes.snapToGridHelp')}> <FormControl>
<FormLabel>{t('nodes.snapToGrid')}</FormLabel> <FormLabel>{t('nodes.snapToGrid')}</FormLabel>
<Switch <Switch
isChecked={shouldSnapToGrid} isChecked={shouldSnapToGrid}
onChange={handleChangeShouldSnap} onChange={handleChangeShouldSnap}
/> />
<FormHelperText>{t('nodes.snapToGridHelp')}</FormHelperText>
</FormControl> </FormControl>
<Divider /> <Divider />
<FormControl helperText={t('nodes.colorCodeEdgesHelp')}> <FormControl>
<FormLabel>{t('nodes.colorCodeEdges')}</FormLabel> <FormLabel>{t('nodes.colorCodeEdges')}</FormLabel>
<Switch <Switch
isChecked={shouldColorEdges} isChecked={shouldColorEdges}
onChange={handleChangeShouldColor} onChange={handleChangeShouldColor}
/> />
<FormHelperText>{t('nodes.colorCodeEdgesHelp')}</FormHelperText>
</FormControl> </FormControl>
<Divider /> <Divider />
<FormControl helperText={t('nodes.fullyContainNodesHelp')}> <FormControl>
<FormLabel>{t('nodes.fullyContainNodes')}</FormLabel> <FormLabel>{t('nodes.fullyContainNodes')}</FormLabel>
<Switch <Switch
isChecked={selectionModeIsChecked} isChecked={selectionModeIsChecked}
onChange={handleChangeSelectionMode} onChange={handleChangeSelectionMode}
/> />
<FormHelperText>
{t('nodes.fullyContainNodesHelp')}
</FormHelperText>
</FormControl> </FormControl>
<Heading size="sm" pt={4}> <Heading size="sm" pt={4}>
{t('common.advanced')} {t('common.advanced')}
</Heading> </Heading>
<FormControl helperText={t('nodes.validateConnectionsHelp')}> <FormControl>
<FormLabel>{t('nodes.validateConnections')}</FormLabel> <FormLabel>{t('nodes.validateConnections')}</FormLabel>
<Switch <Switch
isChecked={shouldValidateGraph} isChecked={shouldValidateGraph}
onChange={handleChangeShouldValidate} onChange={handleChangeShouldValidate}
/> />
<FormHelperText>
{t('nodes.validateConnectionsHelp')}
</FormHelperText>
</FormControl> </FormControl>
<ReloadNodeTemplatesButton /> <ReloadNodeTemplatesButton />
</Flex> </Flex>

View File

@ -5,6 +5,7 @@ import {
FormLabel, FormLabel,
} from '@invoke-ai/ui'; } from '@invoke-ai/ui';
import { useAppDispatch, useAppSelector } from 'app/store/storeHooks'; import { useAppDispatch, useAppSelector } from 'app/store/storeHooks';
import { InformationalPopover } from 'common/components/InformationalPopover/InformationalPopover';
import { setCfgRescaleMultiplier } from 'features/parameters/store/generationSlice'; import { setCfgRescaleMultiplier } from 'features/parameters/store/generationSlice';
import { memo, useCallback } from 'react'; import { memo, useCallback } from 'react';
import { useTranslation } from 'react-i18next'; import { useTranslation } from 'react-i18next';
@ -44,8 +45,10 @@ const ParamCFGRescaleMultiplier = () => {
); );
return ( return (
<FormControl feature="paramCFGRescaleMultiplier"> <FormControl>
<FormLabel>{t('parameters.cfgRescaleMultiplier')}</FormLabel> <InformationalPopover feature="paramCFGRescaleMultiplier">
<FormLabel>{t('parameters.cfgRescaleMultiplier')}</FormLabel>
</InformationalPopover>
<CompositeSlider <CompositeSlider
value={cfgRescaleMultiplier} value={cfgRescaleMultiplier}
defaultValue={initial} defaultValue={initial}

View File

@ -5,6 +5,7 @@ import {
FormLabel, FormLabel,
} from '@invoke-ai/ui'; } from '@invoke-ai/ui';
import { useAppDispatch, useAppSelector } from 'app/store/storeHooks'; import { useAppDispatch, useAppSelector } from 'app/store/storeHooks';
import { InformationalPopover } from 'common/components/InformationalPopover/InformationalPopover';
import { setClipSkip } from 'features/parameters/store/generationSlice'; import { setClipSkip } from 'features/parameters/store/generationSlice';
import { CLIP_SKIP_MAP } from 'features/parameters/types/constants'; import { CLIP_SKIP_MAP } from 'features/parameters/types/constants';
import { memo, useCallback, useMemo } from 'react'; import { memo, useCallback, useMemo } from 'react';
@ -50,8 +51,10 @@ const ParamClipSkip = () => {
} }
return ( return (
<FormControl feature="clipSkip"> <FormControl>
<FormLabel>{t('parameters.clipSkip')}</FormLabel> <InformationalPopover feature="clipSkip">
<FormLabel>{t('parameters.clipSkip')}</FormLabel>
</InformationalPopover>
<CompositeSlider <CompositeSlider
value={clipSkip} value={clipSkip}
defaultValue={initial} defaultValue={initial}

View File

@ -1,6 +1,7 @@
import type { ComboboxOnChange, ComboboxOption } from '@invoke-ai/ui'; import type { ComboboxOnChange, ComboboxOption } from '@invoke-ai/ui';
import { Combobox, FormControl, FormLabel } from '@invoke-ai/ui'; import { Combobox, FormControl, FormLabel } from '@invoke-ai/ui';
import { useAppDispatch, useAppSelector } from 'app/store/storeHooks'; import { useAppDispatch, useAppSelector } from 'app/store/storeHooks';
import { InformationalPopover } from 'common/components/InformationalPopover/InformationalPopover';
import { setCanvasCoherenceMode } from 'features/parameters/store/generationSlice'; import { setCanvasCoherenceMode } from 'features/parameters/store/generationSlice';
import { isParameterCanvasCoherenceMode } from 'features/parameters/types/parameterSchemas'; import { isParameterCanvasCoherenceMode } from 'features/parameters/types/parameterSchemas';
import { memo, useCallback, useMemo } from 'react'; import { memo, useCallback, useMemo } from 'react';
@ -39,8 +40,10 @@ const ParamCanvasCoherenceMode = () => {
); );
return ( return (
<FormControl feature="compositingCoherenceMode"> <FormControl>
<FormLabel>{t('parameters.coherenceMode')}</FormLabel> <InformationalPopover feature="compositingCoherenceMode">
<FormLabel>{t('parameters.coherenceMode')}</FormLabel>
</InformationalPopover>
<Combobox options={options} value={value} onChange={onChange} /> <Combobox options={options} value={value} onChange={onChange} />
</FormControl> </FormControl>
); );

View File

@ -5,6 +5,7 @@ import {
FormLabel, FormLabel,
} from '@invoke-ai/ui'; } from '@invoke-ai/ui';
import { useAppDispatch, useAppSelector } from 'app/store/storeHooks'; import { useAppDispatch, useAppSelector } from 'app/store/storeHooks';
import { InformationalPopover } from 'common/components/InformationalPopover/InformationalPopover';
import { setCanvasCoherenceSteps } from 'features/parameters/store/generationSlice'; import { setCanvasCoherenceSteps } from 'features/parameters/store/generationSlice';
import { memo, useCallback } from 'react'; import { memo, useCallback } from 'react';
import { useTranslation } from 'react-i18next'; import { useTranslation } from 'react-i18next';
@ -46,8 +47,10 @@ const ParamCanvasCoherenceSteps = () => {
); );
return ( return (
<FormControl feature="compositingCoherenceSteps"> <FormControl>
<FormLabel>{t('parameters.coherenceSteps')}</FormLabel> <InformationalPopover feature="compositingCoherenceSteps">
<FormLabel>{t('parameters.coherenceSteps')}</FormLabel>
</InformationalPopover>
<CompositeSlider <CompositeSlider
min={sliderMin} min={sliderMin}
max={sliderMax} max={sliderMax}

View File

@ -5,6 +5,7 @@ import {
FormLabel, FormLabel,
} from '@invoke-ai/ui'; } from '@invoke-ai/ui';
import { useAppDispatch, useAppSelector } from 'app/store/storeHooks'; import { useAppDispatch, useAppSelector } from 'app/store/storeHooks';
import { InformationalPopover } from 'common/components/InformationalPopover/InformationalPopover';
import { setCanvasCoherenceStrength } from 'features/parameters/store/generationSlice'; import { setCanvasCoherenceStrength } from 'features/parameters/store/generationSlice';
import { memo, useCallback } from 'react'; import { memo, useCallback } from 'react';
import { useTranslation } from 'react-i18next'; import { useTranslation } from 'react-i18next';
@ -24,8 +25,10 @@ const ParamCanvasCoherenceStrength = () => {
); );
return ( return (
<FormControl feature="compositingStrength"> <FormControl>
<FormLabel>{t('parameters.coherenceStrength')}</FormLabel> <InformationalPopover feature="compositingStrength">
<FormLabel>{t('parameters.coherenceStrength')}</FormLabel>
</InformationalPopover>
<CompositeSlider <CompositeSlider
min={0} min={0}
max={1} max={1}

View File

@ -5,6 +5,7 @@ import {
FormLabel, FormLabel,
} from '@invoke-ai/ui'; } from '@invoke-ai/ui';
import { useAppDispatch, useAppSelector } from 'app/store/storeHooks'; import { useAppDispatch, useAppSelector } from 'app/store/storeHooks';
import { InformationalPopover } from 'common/components/InformationalPopover/InformationalPopover';
import { setMaskBlur } from 'features/parameters/store/generationSlice'; import { setMaskBlur } from 'features/parameters/store/generationSlice';
import { memo, useCallback } from 'react'; import { memo, useCallback } from 'react';
import { useTranslation } from 'react-i18next'; import { useTranslation } from 'react-i18next';
@ -33,8 +34,10 @@ const ParamMaskBlur = () => {
); );
return ( return (
<FormControl feature="compositingBlur"> <FormControl>
<FormLabel>{t('parameters.maskBlur')}</FormLabel> <InformationalPopover feature="compositingBlur">
<FormLabel>{t('parameters.maskBlur')}</FormLabel>
</InformationalPopover>
<CompositeSlider <CompositeSlider
min={sliderMin} min={sliderMin}
max={sliderMax} max={sliderMax}

View File

@ -1,6 +1,7 @@
import type { ComboboxOnChange, ComboboxOption } from '@invoke-ai/ui'; import type { ComboboxOnChange, ComboboxOption } from '@invoke-ai/ui';
import { Combobox, FormControl, FormLabel } from '@invoke-ai/ui'; import { Combobox, FormControl, FormLabel } from '@invoke-ai/ui';
import { useAppDispatch, useAppSelector } from 'app/store/storeHooks'; import { useAppDispatch, useAppSelector } from 'app/store/storeHooks';
import { InformationalPopover } from 'common/components/InformationalPopover/InformationalPopover';
import { setMaskBlurMethod } from 'features/parameters/store/generationSlice'; import { setMaskBlurMethod } from 'features/parameters/store/generationSlice';
import { isParameterMaskBlurMethod } from 'features/parameters/types/parameterSchemas'; import { isParameterMaskBlurMethod } from 'features/parameters/types/parameterSchemas';
import { memo, useCallback, useMemo } from 'react'; import { memo, useCallback, useMemo } from 'react';
@ -32,8 +33,10 @@ const ParamMaskBlurMethod = () => {
); );
return ( return (
<FormControl feature="compositingBlurMethod"> <FormControl>
<FormLabel>{t('parameters.maskBlurMethod')}</FormLabel> <InformationalPopover feature="compositingBlurMethod">
<FormLabel>{t('parameters.maskBlurMethod')}</FormLabel>
</InformationalPopover>
<Combobox value={value} onChange={onChange} options={options} /> <Combobox value={value} onChange={onChange} options={options} />
</FormControl> </FormControl>
); );

View File

@ -1,6 +1,7 @@
import type { ComboboxOnChange, ComboboxOption } from '@invoke-ai/ui'; import type { ComboboxOnChange, ComboboxOption } from '@invoke-ai/ui';
import { Combobox, FormControl, FormLabel } from '@invoke-ai/ui'; import { Combobox, FormControl, FormLabel } from '@invoke-ai/ui';
import { useAppDispatch, useAppSelector } from 'app/store/storeHooks'; import { useAppDispatch, useAppSelector } from 'app/store/storeHooks';
import { InformationalPopover } from 'common/components/InformationalPopover/InformationalPopover';
import { setInfillMethod } from 'features/parameters/store/generationSlice'; import { setInfillMethod } from 'features/parameters/store/generationSlice';
import { memo, useCallback, useMemo } from 'react'; import { memo, useCallback, useMemo } from 'react';
import { useTranslation } from 'react-i18next'; import { useTranslation } from 'react-i18next';
@ -38,8 +39,10 @@ const ParamInfillMethod = () => {
); );
return ( return (
<FormControl isDisabled={options.length === 0} feature="infillMethod"> <FormControl isDisabled={options.length === 0}>
<FormLabel>{t('parameters.infillMethod')}</FormLabel> <InformationalPopover feature="infillMethod">
<FormLabel>{t('parameters.infillMethod')}</FormLabel>
</InformationalPopover>
<Combobox value={value} options={options} onChange={onChange} /> <Combobox value={value} options={options} onChange={onChange} />
</FormControl> </FormControl>
); );

View File

@ -1,6 +1,7 @@
import type { ComboboxOnChange, ComboboxOption } from '@invoke-ai/ui'; import type { ComboboxOnChange, ComboboxOption } from '@invoke-ai/ui';
import { Combobox, FormControl, FormLabel } from '@invoke-ai/ui'; import { Combobox, FormControl, FormLabel } from '@invoke-ai/ui';
import { useAppDispatch, useAppSelector } from 'app/store/storeHooks'; import { useAppDispatch, useAppSelector } from 'app/store/storeHooks';
import { InformationalPopover } from 'common/components/InformationalPopover/InformationalPopover';
import { setBoundingBoxScaleMethod } from 'features/canvas/store/canvasSlice'; import { setBoundingBoxScaleMethod } from 'features/canvas/store/canvasSlice';
import { isBoundingBoxScaleMethod } from 'features/canvas/store/canvasTypes'; import { isBoundingBoxScaleMethod } from 'features/canvas/store/canvasTypes';
import { selectOptimalDimension } from 'features/parameters/store/generationSlice'; import { selectOptimalDimension } from 'features/parameters/store/generationSlice';
@ -37,8 +38,10 @@ const ParamScaleBeforeProcessing = () => {
); );
return ( return (
<FormControl feature="scaleBeforeProcessing"> <FormControl>
<FormLabel>{t('parameters.scaleBeforeProcessing')}</FormLabel> <InformationalPopover feature="scaleBeforeProcessing">
<FormLabel>{t('parameters.scaleBeforeProcessing')}</FormLabel>
</InformationalPopover>
<Combobox value={value} options={OPTIONS} onChange={onChange} /> <Combobox value={value} options={OPTIONS} onChange={onChange} />
</FormControl> </FormControl>
); );

View File

@ -5,6 +5,7 @@ import {
FormLabel, FormLabel,
} from '@invoke-ai/ui'; } from '@invoke-ai/ui';
import { useAppDispatch, useAppSelector } from 'app/store/storeHooks'; import { useAppDispatch, useAppSelector } from 'app/store/storeHooks';
import { InformationalPopover } from 'common/components/InformationalPopover/InformationalPopover';
import { setCfgScale } from 'features/parameters/store/generationSlice'; import { setCfgScale } from 'features/parameters/store/generationSlice';
import { memo, useCallback, useMemo } from 'react'; import { memo, useCallback, useMemo } from 'react';
import { useTranslation } from 'react-i18next'; import { useTranslation } from 'react-i18next';
@ -34,8 +35,10 @@ const ParamCFGScale = () => {
); );
return ( return (
<FormControl feature="paramCFGScale"> <FormControl>
<FormLabel>{t('parameters.cfgScale')}</FormLabel> <InformationalPopover feature="paramCFGScale">
<FormLabel>{t('parameters.cfgScale')}</FormLabel>
</InformationalPopover>
<CompositeSlider <CompositeSlider
value={cfgScale} value={cfgScale}
defaultValue={initial} defaultValue={initial}

View File

@ -1,6 +1,7 @@
import type { ComboboxOnChange } from '@invoke-ai/ui'; import type { ComboboxOnChange } from '@invoke-ai/ui';
import { Combobox, FormControl, FormLabel } from '@invoke-ai/ui'; import { Combobox, FormControl, FormLabel } from '@invoke-ai/ui';
import { useAppDispatch, useAppSelector } from 'app/store/storeHooks'; import { useAppDispatch, useAppSelector } from 'app/store/storeHooks';
import { InformationalPopover } from 'common/components/InformationalPopover/InformationalPopover';
import { setScheduler } from 'features/parameters/store/generationSlice'; import { setScheduler } from 'features/parameters/store/generationSlice';
import { SCHEDULER_OPTIONS } from 'features/parameters/types/constants'; import { SCHEDULER_OPTIONS } from 'features/parameters/types/constants';
import { isParameterScheduler } from 'features/parameters/types/parameterSchemas'; import { isParameterScheduler } from 'features/parameters/types/parameterSchemas';
@ -28,8 +29,10 @@ const ParamScheduler = () => {
); );
return ( return (
<FormControl feature="paramScheduler"> <FormControl>
<FormLabel>{t('parameters.scheduler')}</FormLabel> <InformationalPopover feature="paramScheduler">
<FormLabel>{t('parameters.scheduler')}</FormLabel>
</InformationalPopover>
<Combobox value={value} options={SCHEDULER_OPTIONS} onChange={onChange} /> <Combobox value={value} options={SCHEDULER_OPTIONS} onChange={onChange} />
</FormControl> </FormControl>
); );

View File

@ -5,6 +5,7 @@ import {
FormLabel, FormLabel,
} from '@invoke-ai/ui'; } from '@invoke-ai/ui';
import { useAppDispatch, useAppSelector } from 'app/store/storeHooks'; import { useAppDispatch, useAppSelector } from 'app/store/storeHooks';
import { InformationalPopover } from 'common/components/InformationalPopover/InformationalPopover';
import { setSteps } from 'features/parameters/store/generationSlice'; import { setSteps } from 'features/parameters/store/generationSlice';
import { memo, useCallback, useMemo } from 'react'; import { memo, useCallback, useMemo } from 'react';
import { useTranslation } from 'react-i18next'; import { useTranslation } from 'react-i18next';
@ -36,8 +37,10 @@ const ParamSteps = () => {
); );
return ( return (
<FormControl feature="paramSteps"> <FormControl>
<FormLabel>{t('parameters.steps')}</FormLabel> <InformationalPopover feature="paramSteps">
<FormLabel>{t('parameters.steps')}</FormLabel>
</InformationalPopover>
<CompositeSlider <CompositeSlider
value={steps} value={steps}
defaultValue={initial} defaultValue={initial}

View File

@ -5,6 +5,7 @@ import {
FormLabel, FormLabel,
} from '@invoke-ai/ui'; } from '@invoke-ai/ui';
import { useAppDispatch, useAppSelector } from 'app/store/storeHooks'; import { useAppDispatch, useAppSelector } from 'app/store/storeHooks';
import { InformationalPopover } from 'common/components/InformationalPopover/InformationalPopover';
import { setImg2imgStrength } from 'features/parameters/store/generationSlice'; import { setImg2imgStrength } from 'features/parameters/store/generationSlice';
import { memo, useCallback } from 'react'; import { memo, useCallback } from 'react';
import { useTranslation } from 'react-i18next'; import { useTranslation } from 'react-i18next';
@ -39,8 +40,10 @@ const ImageToImageStrength = () => {
); );
return ( return (
<FormControl feature="paramDenoisingStrength"> <FormControl>
<FormLabel>{`${t('parameters.denoisingStrength')}`}</FormLabel> <InformationalPopover feature="paramDenoisingStrength">
<FormLabel>{`${t('parameters.denoisingStrength')}`}</FormLabel>
</InformationalPopover>
<CompositeSlider <CompositeSlider
step={coarseStep} step={coarseStep}
fineStep={fineStep} fineStep={fineStep}

View File

@ -1,6 +1,7 @@
import { CompositeNumberInput, FormControl, FormLabel } from '@invoke-ai/ui'; import { CompositeNumberInput, FormControl, FormLabel } from '@invoke-ai/ui';
import { NUMPY_RAND_MAX, NUMPY_RAND_MIN } from 'app/constants'; import { NUMPY_RAND_MAX, NUMPY_RAND_MIN } from 'app/constants';
import { useAppDispatch, useAppSelector } from 'app/store/storeHooks'; import { useAppDispatch, useAppSelector } from 'app/store/storeHooks';
import { InformationalPopover } from 'common/components/InformationalPopover/InformationalPopover';
import { setSeed } from 'features/parameters/store/generationSlice'; import { setSeed } from 'features/parameters/store/generationSlice';
import { memo, useCallback } from 'react'; import { memo, useCallback } from 'react';
import { useTranslation } from 'react-i18next'; import { useTranslation } from 'react-i18next';
@ -21,8 +22,10 @@ export const ParamSeedNumberInput = memo(() => {
); );
return ( return (
<FormControl flexGrow={1} feature="paramSeed"> <FormControl flexGrow={1}>
<FormLabel>{t('parameters.seed')}</FormLabel> <InformationalPopover feature="paramSeed">
<FormLabel>{t('parameters.seed')}</FormLabel>
</InformationalPopover>
<CompositeNumberInput <CompositeNumberInput
step={1} step={1}
min={NUMPY_RAND_MIN} min={NUMPY_RAND_MIN}

View File

@ -1,6 +1,7 @@
import { Combobox, FormControl, FormLabel } from '@invoke-ai/ui'; import { Combobox, FormControl, FormLabel } from '@invoke-ai/ui';
import { createMemoizedSelector } from 'app/store/createMemoizedSelector'; import { createMemoizedSelector } from 'app/store/createMemoizedSelector';
import { useAppDispatch, useAppSelector } from 'app/store/storeHooks'; import { useAppDispatch, useAppSelector } from 'app/store/storeHooks';
import { InformationalPopover } from 'common/components/InformationalPopover/InformationalPopover';
import { useGroupedModelCombobox } from 'common/hooks/useGroupedModelCombobox'; import { useGroupedModelCombobox } from 'common/hooks/useGroupedModelCombobox';
import { import {
selectGenerationSlice, selectGenerationSlice,
@ -46,12 +47,10 @@ const ParamVAEModelSelect = () => {
}); });
return ( return (
<FormControl <FormControl isDisabled={!options.length} isInvalid={!options.length}>
isDisabled={!options.length} <InformationalPopover feature="paramVAE">
isInvalid={!options.length} <FormLabel>{t('modelManager.vae')}</FormLabel>
feature="paramVAE" </InformationalPopover>
>
<FormLabel>{t('modelManager.vae')}</FormLabel>
<Combobox <Combobox
isClearable isClearable
value={value} value={value}

View File

@ -1,6 +1,7 @@
import type { ComboboxOnChange } from '@invoke-ai/ui'; import type { ComboboxOnChange } from '@invoke-ai/ui';
import { Combobox, FormControl, FormLabel } from '@invoke-ai/ui'; import { Combobox, FormControl, FormLabel } from '@invoke-ai/ui';
import { useAppDispatch, useAppSelector } from 'app/store/storeHooks'; import { useAppDispatch, useAppSelector } from 'app/store/storeHooks';
import { InformationalPopover } from 'common/components/InformationalPopover/InformationalPopover';
import { vaePrecisionChanged } from 'features/parameters/store/generationSlice'; import { vaePrecisionChanged } from 'features/parameters/store/generationSlice';
import { isParameterPrecision } from 'features/parameters/types/parameterSchemas'; import { isParameterPrecision } from 'features/parameters/types/parameterSchemas';
import { memo, useCallback, useMemo } from 'react'; import { memo, useCallback, useMemo } from 'react';
@ -33,8 +34,10 @@ const ParamVAEModelSelect = () => {
); );
return ( return (
<FormControl feature="paramVAEPrecision" w="14rem" flexShrink={0}> <FormControl w="14rem" flexShrink={0}>
<FormLabel>{t('modelManager.vaePrecision')}</FormLabel> <InformationalPopover feature="paramVAEPrecision">
<FormLabel>{t('modelManager.vaePrecision')}</FormLabel>
</InformationalPopover>
<Combobox value={value} options={options} onChange={onChange} /> <Combobox value={value} options={options} onChange={onChange} />
</FormControl> </FormControl>
); );

View File

@ -1,6 +1,6 @@
import { CompositeNumberInput } from '@invoke-ai/ui'; import { CompositeNumberInput } from '@invoke-ai/ui';
import { useAppDispatch, useAppSelector } from 'app/store/storeHooks'; import { useAppDispatch, useAppSelector } from 'app/store/storeHooks';
import IAIInformationalPopover from 'common/components/IAIInformationalPopover/IAIInformationalPopover'; import { InformationalPopover } from 'common/components/InformationalPopover/InformationalPopover';
import { setIterations } from 'features/parameters/store/generationSlice'; import { setIterations } from 'features/parameters/store/generationSlice';
import { memo, useCallback } from 'react'; import { memo, useCallback } from 'react';
@ -17,7 +17,7 @@ export const QueueIterationsNumberInput = memo(() => {
); );
return ( return (
<IAIInformationalPopover feature="paramIterations"> <InformationalPopover feature="paramIterations">
<CompositeNumberInput <CompositeNumberInput
step={coarseStep} step={coarseStep}
fineStep={fineStep} fineStep={fineStep}
@ -34,7 +34,7 @@ export const QueueIterationsNumberInput = memo(() => {
flexShrink={0} flexShrink={0}
variant="iterations" variant="iterations"
/> />
</IAIInformationalPopover> </InformationalPopover>
); );
}); });

View File

@ -15,6 +15,7 @@ import {
useDisclosure, useDisclosure,
} from '@invoke-ai/ui'; } from '@invoke-ai/ui';
import { useAppDispatch, useAppSelector } from 'app/store/storeHooks'; import { useAppDispatch, useAppSelector } from 'app/store/storeHooks';
import { InformationalPopover } from 'common/components/InformationalPopover/InformationalPopover';
import ScrollableContent from 'common/components/OverlayScrollbars/ScrollableContent'; import ScrollableContent from 'common/components/OverlayScrollbars/ScrollableContent';
import { useClearStorage } from 'common/hooks/useClearStorage'; import { useClearStorage } from 'common/hooks/useClearStorage';
import { shouldUseCpuNoiseChanged } from 'features/parameters/store/generationSlice'; import { shouldUseCpuNoiseChanged } from 'features/parameters/store/generationSlice';
@ -261,8 +262,13 @@ const SettingsModal = ({ children, config }: SettingsModalProps) => {
onChange={handleChangeShouldAntialiasProgressImage} onChange={handleChangeShouldAntialiasProgressImage}
/> />
</FormControl> </FormControl>
<FormControl feature="noiseUseCPU"> <FormControl>
<FormLabel>{t('parameters.useCpuNoise')}</FormLabel> <InformationalPopover
feature="noiseUseCPU"
inPortal={false}
>
<FormLabel>{t('parameters.useCpuNoise')}</FormLabel>
</InformationalPopover>
<Switch <Switch
isChecked={shouldUseCpuNoise} isChecked={shouldUseCpuNoise}
onChange={handleChangeShouldUseCpuNoise} onChange={handleChangeShouldUseCpuNoise}

View File

@ -65,7 +65,7 @@ const WorkflowLibraryPagination = ({ page, setPage, data }: Props) => {
w={10} w={10}
isDisabled={data.pages === 1} isDisabled={data.pages === 1}
onClick={p.page === page ? undefined : p.onClick} onClick={p.page === page ? undefined : p.onClick}
variant={p.page === page ? 'invokeAI' : 'ghost'} variant={p.page === page ? 'solid' : 'ghost'}
key={p.page} key={p.page}
transitionDuration="0s" // the delay in animation looks jank transitionDuration="0s" // the delay in animation looks jank
> >