mirror of
https://github.com/invoke-ai/InvokeAI
synced 2024-08-30 20:32:17 +00:00
feat(ui): migrate to @invoke-ai/ui
This commit is contained in:
parent
8e2ccab1f0
commit
5d068c1da1
@ -93,6 +93,27 @@ module.exports = {
|
|||||||
'@typescript-eslint/no-import-type-side-effects': 'error',
|
'@typescript-eslint/no-import-type-side-effects': 'error',
|
||||||
'simple-import-sort/imports': 'error',
|
'simple-import-sort/imports': 'error',
|
||||||
'simple-import-sort/exports': 'error',
|
'simple-import-sort/exports': 'error',
|
||||||
|
// Prefer @invoke-ai/ui components over chakra
|
||||||
|
'no-restricted-imports': 'off',
|
||||||
|
'@typescript-eslint/no-restricted-imports': [
|
||||||
|
'warn',
|
||||||
|
{
|
||||||
|
paths: [
|
||||||
|
{
|
||||||
|
name: '@chakra-ui/react',
|
||||||
|
message: "Please import from '@invoke-ai/ui' instead.",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: '@chakra-ui/layout',
|
||||||
|
message: "Please import from '@invoke-ai/ui' instead.",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: '@chakra-ui/portal',
|
||||||
|
message: "Please import from '@invoke-ai/ui' instead.",
|
||||||
|
},
|
||||||
|
],
|
||||||
|
},
|
||||||
|
],
|
||||||
},
|
},
|
||||||
overrides: [
|
overrides: [
|
||||||
{
|
{
|
||||||
|
@ -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 src/theme/theme.ts",
|
"theme": "chakra-cli tokens --strict-component-types --strict-token-types node_modules/@invoke-ai/ui",
|
||||||
"theme:watch": "chakra-cli tokens src/theme/theme.ts --watch",
|
"theme:watch": "chakra-cli tokens --strict-component-types --strict-token-types 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": "^0.0.3",
|
"@invoke-ai/ui": "file:/home/bat/Documents/Code/ui",
|
||||||
"@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",
|
||||||
|
@ -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: ^0.0.3
|
specifier: file:/home/bat/Documents/Code/ui
|
||||||
version: 0.0.3(@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-use-size@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)(framer-motion@10.18.0)(lodash-es@4.17.21)(nanostores@0.9.5)(react-dom@18.2.0)(react-i18next@14.0.0)(react@18.2.0)
|
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)
|
||||||
'@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,48 +3688,6 @@ packages:
|
|||||||
resolution: {integrity: sha512-dvuCeX5fC9dXgJn9t+X5atfmgQAzUOWqS1254Gh0m6i8wKd10ebXkfNKiRK+1GWi/yTvvLDHpoxLr0xxxeslWw==}
|
resolution: {integrity: sha512-dvuCeX5fC9dXgJn9t+X5atfmgQAzUOWqS1254Gh0m6i8wKd10ebXkfNKiRK+1GWi/yTvvLDHpoxLr0xxxeslWw==}
|
||||||
dev: true
|
dev: true
|
||||||
|
|
||||||
/@invoke-ai/ui@0.0.3(@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-use-size@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)(framer-motion@10.18.0)(lodash-es@4.17.21)(nanostores@0.9.5)(react-dom@18.2.0)(react-i18next@14.0.0)(react@18.2.0):
|
|
||||||
resolution: {integrity: sha512-EFh30NPTIWXJKNTgUghrbeB7hB59fD+cm6DIoOYMlMQOQGfHTu+6aOOx6hBoj7fse2UWWhL/dEhannz6homoCw==}
|
|
||||||
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/react-use-size': ^2.1.0
|
|
||||||
'@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
|
|
||||||
framer-motion: ^10.18.0
|
|
||||||
lodash-es: ^4.17.21
|
|
||||||
nanostores: ^0.9.5
|
|
||||||
react: ^18.2.0
|
|
||||||
react-dom: ^18.2.0
|
|
||||||
react-i18next: ^14.0.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/react-use-size': 2.1.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)
|
|
||||||
framer-motion: 10.18.0(react-dom@18.2.0)(react@18.2.0)
|
|
||||||
lodash-es: 4.17.21
|
|
||||||
nanostores: 0.9.5
|
|
||||||
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)
|
|
||||||
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'}
|
||||||
@ -13787,3 +13745,53 @@ 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
|
||||||
|
@ -1,4 +1,4 @@
|
|||||||
import { Box } from '@chakra-ui/react';
|
import { Box } from '@invoke-ai/ui';
|
||||||
import { useSocketIO } from 'app/hooks/useSocketIO';
|
import { useSocketIO } from 'app/hooks/useSocketIO';
|
||||||
import { useLogger } from 'app/logging/useLogger';
|
import { useLogger } from 'app/logging/useLogger';
|
||||||
import { appStarted } from 'app/store/middleware/listenerMiddleware/listeners/appStarted';
|
import { appStarted } from 'app/store/middleware/listenerMiddleware/listeners/appStarted';
|
||||||
|
@ -1,6 +1,4 @@
|
|||||||
import { Flex, Heading, Link, useToast } from '@chakra-ui/react';
|
import { Button, Flex, Heading, Link, Text, useToast } from '@invoke-ai/ui';
|
||||||
import { InvButton } from 'common/components/InvButton/InvButton';
|
|
||||||
import { InvText } from 'common/components/InvText/wrapper';
|
|
||||||
import newGithubIssueUrl from 'new-github-issue-url';
|
import newGithubIssueUrl from 'new-github-issue-url';
|
||||||
import { memo, useCallback, useMemo } from 'react';
|
import { memo, useCallback, useMemo } from 'react';
|
||||||
import { useTranslation } from 'react-i18next';
|
import { useTranslation } from 'react-i18next';
|
||||||
@ -65,24 +63,24 @@ const AppErrorBoundaryFallback = ({ error, resetErrorBoundary }: Props) => {
|
|||||||
justifyContent="space-between"
|
justifyContent="space-between"
|
||||||
alignItems="center"
|
alignItems="center"
|
||||||
>
|
>
|
||||||
<InvText fontWeight="semibold" color="error.400">
|
<Text fontWeight="semibold" color="error.400">
|
||||||
{error.name}: {error.message}
|
{error.name}: {error.message}
|
||||||
</InvText>
|
</Text>
|
||||||
</Flex>
|
</Flex>
|
||||||
<Flex gap={4}>
|
<Flex gap={4}>
|
||||||
<InvButton
|
<Button
|
||||||
leftIcon={<PiArrowCounterClockwiseBold />}
|
leftIcon={<PiArrowCounterClockwiseBold />}
|
||||||
onClick={resetErrorBoundary}
|
onClick={resetErrorBoundary}
|
||||||
>
|
>
|
||||||
{t('accessibility.resetUI')}
|
{t('accessibility.resetUI')}
|
||||||
</InvButton>
|
</Button>
|
||||||
<InvButton leftIcon={<PiCopyBold />} onClick={handleCopy}>
|
<Button leftIcon={<PiCopyBold />} onClick={handleCopy}>
|
||||||
{t('common.copyError')}
|
{t('common.copyError')}
|
||||||
</InvButton>
|
</Button>
|
||||||
<Link href={url} isExternal>
|
<Link href={url} isExternal>
|
||||||
<InvButton leftIcon={<PiArrowSquareOutBold />}>
|
<Button leftIcon={<PiArrowSquareOutBold />}>
|
||||||
{t('accessibility.createIssue')}
|
{t('accessibility.createIssue')}
|
||||||
</InvButton>
|
</Button>
|
||||||
</Link>
|
</Link>
|
||||||
</Flex>
|
</Flex>
|
||||||
</Flex>
|
</Flex>
|
||||||
|
@ -1,12 +1,16 @@
|
|||||||
import '@fontsource-variable/inter';
|
import '@fontsource-variable/inter';
|
||||||
import 'overlayscrollbars/overlayscrollbars.css';
|
import 'overlayscrollbars/overlayscrollbars.css';
|
||||||
import 'common/components/OverlayScrollbars/overlayscrollbars.css';
|
|
||||||
|
|
||||||
import { ChakraProvider, DarkMode, extendTheme } from '@chakra-ui/react';
|
import {
|
||||||
|
ChakraProvider,
|
||||||
|
DarkMode,
|
||||||
|
extendTheme,
|
||||||
|
theme as _theme,
|
||||||
|
TOAST_OPTIONS,
|
||||||
|
} from '@invoke-ai/ui';
|
||||||
import type { ReactNode } from 'react';
|
import type { ReactNode } from 'react';
|
||||||
import { memo, useEffect, useMemo } from 'react';
|
import { memo, useEffect, useMemo } from 'react';
|
||||||
import { useTranslation } from 'react-i18next';
|
import { useTranslation } from 'react-i18next';
|
||||||
import { theme as invokeAITheme, TOAST_OPTIONS } from 'theme/theme';
|
|
||||||
|
|
||||||
type ThemeLocaleProviderProps = {
|
type ThemeLocaleProviderProps = {
|
||||||
children: ReactNode;
|
children: ReactNode;
|
||||||
@ -19,7 +23,7 @@ function ThemeLocaleProvider({ children }: ThemeLocaleProviderProps) {
|
|||||||
|
|
||||||
const theme = useMemo(() => {
|
const theme = useMemo(() => {
|
||||||
return extendTheme({
|
return extendTheme({
|
||||||
...invokeAITheme,
|
..._theme,
|
||||||
direction,
|
direction,
|
||||||
});
|
});
|
||||||
}, [direction]);
|
}, [direction]);
|
||||||
|
@ -1,4 +1,4 @@
|
|||||||
import { useToast } from '@chakra-ui/react';
|
import { useToast } from '@invoke-ai/ui';
|
||||||
import { useAppDispatch, useAppSelector } from 'app/store/storeHooks';
|
import { useAppDispatch, useAppSelector } from 'app/store/storeHooks';
|
||||||
import { addToast, clearToastQueue } from 'features/system/store/systemSlice';
|
import { addToast, clearToastQueue } from 'features/system/store/systemSlice';
|
||||||
import type { MakeToastArg } from 'features/system/util/makeToast';
|
import type { MakeToastArg } from 'features/system/util/makeToast';
|
||||||
|
@ -1,11 +1,10 @@
|
|||||||
import { createStandaloneToast } from '@chakra-ui/react';
|
import { createStandaloneToast, theme, TOAST_OPTIONS } from '@invoke-ai/ui';
|
||||||
import { logger } from 'app/logging/logger';
|
import { logger } from 'app/logging/logger';
|
||||||
import { parseify } from 'common/util/serialize';
|
import { parseify } from 'common/util/serialize';
|
||||||
import { zPydanticValidationError } from 'features/system/store/zodSchemas';
|
import { zPydanticValidationError } from 'features/system/store/zodSchemas';
|
||||||
import { t } from 'i18next';
|
import { t } from 'i18next';
|
||||||
import { truncate, upperFirst } from 'lodash-es';
|
import { truncate, upperFirst } from 'lodash-es';
|
||||||
import { queueApi } from 'services/api/endpoints/queue';
|
import { queueApi } from 'services/api/endpoints/queue';
|
||||||
import { theme, TOAST_OPTIONS } from 'theme/theme';
|
|
||||||
|
|
||||||
import { startAppListening } from '..';
|
import { startAppListening } from '..';
|
||||||
|
|
||||||
|
@ -1,4 +1,4 @@
|
|||||||
import type { UseToastOptions } from '@chakra-ui/react';
|
import type { UseToastOptions } from '@invoke-ai/ui';
|
||||||
import { logger } from 'app/logging/logger';
|
import { logger } from 'app/logging/logger';
|
||||||
import { setInitialCanvasImage } from 'features/canvas/store/canvasSlice';
|
import { setInitialCanvasImage } from 'features/canvas/store/canvasSlice';
|
||||||
import {
|
import {
|
||||||
|
@ -1,4 +1,4 @@
|
|||||||
import type { MenuItemProps } from '@chakra-ui/react';
|
import type { MenuItemProps } from '@invoke-ai/ui';
|
||||||
import { atom } from 'nanostores';
|
import { atom } from 'nanostores';
|
||||||
|
|
||||||
export type CustomStarUi = {
|
export type CustomStarUi = {
|
||||||
|
@ -1,5 +1,10 @@
|
|||||||
import type { ChakraProps } from '@chakra-ui/react';
|
import type { ChakraProps } from '@invoke-ai/ui';
|
||||||
import { Flex } from '@chakra-ui/react';
|
import {
|
||||||
|
CompositeNumberInput,
|
||||||
|
Flex,
|
||||||
|
FormControl,
|
||||||
|
FormLabel,
|
||||||
|
} from '@invoke-ai/ui';
|
||||||
import type { CSSProperties } from 'react';
|
import type { CSSProperties } from 'react';
|
||||||
import { memo, useCallback } from 'react';
|
import { memo, useCallback } from 'react';
|
||||||
import { RgbaColorPicker } from 'react-colorful';
|
import { RgbaColorPicker } from 'react-colorful';
|
||||||
@ -8,9 +13,6 @@ import type {
|
|||||||
RgbaColor,
|
RgbaColor,
|
||||||
} from 'react-colorful/dist/types';
|
} from 'react-colorful/dist/types';
|
||||||
|
|
||||||
import { InvControl } from './InvControl/InvControl';
|
|
||||||
import { InvNumberInput } from './InvNumberInput/InvNumberInput';
|
|
||||||
|
|
||||||
type IAIColorPickerProps = ColorPickerBaseProps<RgbaColor> & {
|
type IAIColorPickerProps = ColorPickerBaseProps<RgbaColor> & {
|
||||||
withNumberInput?: boolean;
|
withNumberInput?: boolean;
|
||||||
};
|
};
|
||||||
@ -61,8 +63,9 @@ const IAIColorPicker = (props: IAIColorPickerProps) => {
|
|||||||
/>
|
/>
|
||||||
{withNumberInput && (
|
{withNumberInput && (
|
||||||
<Flex>
|
<Flex>
|
||||||
<InvControl label="Red">
|
<FormControl>
|
||||||
<InvNumberInput
|
<FormLabel>Red</FormLabel>
|
||||||
|
<CompositeNumberInput
|
||||||
value={color.r}
|
value={color.r}
|
||||||
onChange={handleChangeR}
|
onChange={handleChangeR}
|
||||||
min={0}
|
min={0}
|
||||||
@ -71,9 +74,10 @@ const IAIColorPicker = (props: IAIColorPickerProps) => {
|
|||||||
w={numberInputWidth}
|
w={numberInputWidth}
|
||||||
defaultValue={90}
|
defaultValue={90}
|
||||||
/>
|
/>
|
||||||
</InvControl>
|
</FormControl>
|
||||||
<InvControl label="Green">
|
<FormControl>
|
||||||
<InvNumberInput
|
<FormLabel>Green</FormLabel>
|
||||||
|
<CompositeNumberInput
|
||||||
value={color.g}
|
value={color.g}
|
||||||
onChange={handleChangeG}
|
onChange={handleChangeG}
|
||||||
min={0}
|
min={0}
|
||||||
@ -82,9 +86,10 @@ const IAIColorPicker = (props: IAIColorPickerProps) => {
|
|||||||
w={numberInputWidth}
|
w={numberInputWidth}
|
||||||
defaultValue={90}
|
defaultValue={90}
|
||||||
/>
|
/>
|
||||||
</InvControl>
|
</FormControl>
|
||||||
<InvControl label="Blue">
|
<FormControl>
|
||||||
<InvNumberInput
|
<FormLabel>Blue</FormLabel>
|
||||||
|
<CompositeNumberInput
|
||||||
value={color.b}
|
value={color.b}
|
||||||
onChange={handleChangeB}
|
onChange={handleChangeB}
|
||||||
min={0}
|
min={0}
|
||||||
@ -93,9 +98,10 @@ const IAIColorPicker = (props: IAIColorPickerProps) => {
|
|||||||
w={numberInputWidth}
|
w={numberInputWidth}
|
||||||
defaultValue={255}
|
defaultValue={255}
|
||||||
/>
|
/>
|
||||||
</InvControl>
|
</FormControl>
|
||||||
<InvControl label="Alpha">
|
<FormControl>
|
||||||
<InvNumberInput
|
<FormLabel>Alpha</FormLabel>
|
||||||
|
<CompositeNumberInput
|
||||||
value={color.a}
|
value={color.a}
|
||||||
onChange={handleChangeA}
|
onChange={handleChangeA}
|
||||||
step={0.1}
|
step={0.1}
|
||||||
@ -104,7 +110,7 @@ const IAIColorPicker = (props: IAIColorPickerProps) => {
|
|||||||
w={numberInputWidth}
|
w={numberInputWidth}
|
||||||
defaultValue={1}
|
defaultValue={1}
|
||||||
/>
|
/>
|
||||||
</InvControl>
|
</FormControl>
|
||||||
</Flex>
|
</Flex>
|
||||||
)}
|
)}
|
||||||
</Flex>
|
</Flex>
|
||||||
|
@ -1,9 +1,5 @@
|
|||||||
import type {
|
import type { ChakraProps, FlexProps, SystemStyleObject } from '@invoke-ai/ui';
|
||||||
ChakraProps,
|
import { Flex, Icon, Image } from '@invoke-ai/ui';
|
||||||
FlexProps,
|
|
||||||
SystemStyleObject,
|
|
||||||
} from '@chakra-ui/react';
|
|
||||||
import { Flex, Icon, Image } from '@chakra-ui/react';
|
|
||||||
import {
|
import {
|
||||||
IAILoadingImageFallback,
|
IAILoadingImageFallback,
|
||||||
IAINoContentFallback,
|
IAINoContentFallback,
|
||||||
|
@ -1,9 +1,8 @@
|
|||||||
import type { SystemStyleObject } from '@chakra-ui/react';
|
import type { SystemStyleObject } from '@invoke-ai/ui';
|
||||||
|
import { IconButton } from '@invoke-ai/ui';
|
||||||
import type { MouseEvent, ReactElement } from 'react';
|
import type { MouseEvent, ReactElement } from 'react';
|
||||||
import { memo, useMemo } from 'react';
|
import { memo, useMemo } from 'react';
|
||||||
|
|
||||||
import { InvIconButton } from './InvIconButton/InvIconButton';
|
|
||||||
|
|
||||||
type Props = {
|
type Props = {
|
||||||
onClick: (event: MouseEvent<HTMLButtonElement>) => void;
|
onClick: (event: MouseEvent<HTMLButtonElement>) => void;
|
||||||
tooltip: string;
|
tooltip: string;
|
||||||
@ -26,7 +25,7 @@ const IAIDndImageIcon = (props: Props) => {
|
|||||||
transitionDuration: 'normal',
|
transitionDuration: 'normal',
|
||||||
fill: 'base.100',
|
fill: 'base.100',
|
||||||
_hover: { fill: 'base.50' },
|
_hover: { fill: 'base.50' },
|
||||||
filter: 'drop-shadow(0px 0px 0.1rem var(--invokeai-colors-base-800))',
|
filter: 'drop-shadow(0px 0px 0.1rem var(--invoke-colors-base-800))',
|
||||||
},
|
},
|
||||||
...styleOverrides,
|
...styleOverrides,
|
||||||
}),
|
}),
|
||||||
@ -34,7 +33,7 @@ const IAIDndImageIcon = (props: Props) => {
|
|||||||
);
|
);
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<InvIconButton
|
<IconButton
|
||||||
onClick={onClick}
|
onClick={onClick}
|
||||||
aria-label={tooltip}
|
aria-label={tooltip}
|
||||||
tooltip={tooltip}
|
tooltip={tooltip}
|
||||||
|
@ -1,5 +1,5 @@
|
|||||||
import type { BoxProps } from '@chakra-ui/react';
|
import type { BoxProps } from '@invoke-ai/ui';
|
||||||
import { Box } from '@chakra-ui/react';
|
import { Box } from '@invoke-ai/ui';
|
||||||
import { useDraggableTypesafe } from 'features/dnd/hooks/typesafeHooks';
|
import { useDraggableTypesafe } from 'features/dnd/hooks/typesafeHooks';
|
||||||
import type { TypesafeDraggableData } from 'features/dnd/types';
|
import type { TypesafeDraggableData } from 'features/dnd/types';
|
||||||
import { memo, useRef } from 'react';
|
import { memo, useRef } from 'react';
|
||||||
|
@ -1,4 +1,4 @@
|
|||||||
import { Box, Flex } from '@chakra-ui/react';
|
import { Box, Flex } from '@invoke-ai/ui';
|
||||||
import type { AnimationProps } from 'framer-motion';
|
import type { AnimationProps } from 'framer-motion';
|
||||||
import { motion } from 'framer-motion';
|
import { motion } from 'framer-motion';
|
||||||
import type { ReactNode } from 'react';
|
import type { ReactNode } from 'react';
|
||||||
|
@ -1,4 +1,4 @@
|
|||||||
import { Box } from '@chakra-ui/react';
|
import { Box } from '@invoke-ai/ui';
|
||||||
import { useDroppableTypesafe } from 'features/dnd/hooks/typesafeHooks';
|
import { useDroppableTypesafe } from 'features/dnd/hooks/typesafeHooks';
|
||||||
import type { TypesafeDroppableData } from 'features/dnd/types';
|
import type { TypesafeDroppableData } from 'features/dnd/types';
|
||||||
import { isValidDrop } from 'features/dnd/util/isValidDrop';
|
import { isValidDrop } from 'features/dnd/util/isValidDrop';
|
||||||
|
@ -1,5 +1,5 @@
|
|||||||
import type { SystemStyleObject } from '@chakra-ui/react';
|
import type { SystemStyleObject } from '@invoke-ai/ui';
|
||||||
import { Box, Skeleton } from '@chakra-ui/react';
|
import { Box, Skeleton } from '@invoke-ai/ui';
|
||||||
import { memo } from 'react';
|
import { memo } from 'react';
|
||||||
|
|
||||||
const skeletonStyles: SystemStyleObject = {
|
const skeletonStyles: SystemStyleObject = {
|
||||||
|
@ -1,11 +1,9 @@
|
|||||||
import type { As, FlexProps, StyleProps } from '@chakra-ui/react';
|
import type { As, ChakraProps, FlexProps } from '@invoke-ai/ui';
|
||||||
import { Flex, Icon, Skeleton, Spinner } from '@chakra-ui/react';
|
import { Flex, Icon, Skeleton, Spinner, Text } from '@invoke-ai/ui';
|
||||||
import { memo, useMemo } from 'react';
|
import { memo, useMemo } from 'react';
|
||||||
import { PiImageBold } from 'react-icons/pi';
|
import { PiImageBold } from 'react-icons/pi';
|
||||||
import type { ImageDTO } from 'services/api/types';
|
import type { ImageDTO } from 'services/api/types';
|
||||||
|
|
||||||
import { InvText } from './InvText/wrapper';
|
|
||||||
|
|
||||||
type Props = { image: ImageDTO | undefined };
|
type Props = { image: ImageDTO | undefined };
|
||||||
|
|
||||||
export const IAILoadingImageFallback = memo((props: Props) => {
|
export const IAILoadingImageFallback = memo((props: Props) => {
|
||||||
@ -39,7 +37,7 @@ IAILoadingImageFallback.displayName = 'IAILoadingImageFallback';
|
|||||||
type IAINoImageFallbackProps = FlexProps & {
|
type IAINoImageFallbackProps = FlexProps & {
|
||||||
label?: string;
|
label?: string;
|
||||||
icon?: As | null;
|
icon?: As | null;
|
||||||
boxSize?: StyleProps['boxSize'];
|
boxSize?: ChakraProps['boxSize'];
|
||||||
};
|
};
|
||||||
|
|
||||||
export const IAINoContentFallback = memo((props: IAINoImageFallbackProps) => {
|
export const IAINoContentFallback = memo((props: IAINoImageFallbackProps) => {
|
||||||
@ -66,9 +64,9 @@ export const IAINoContentFallback = memo((props: IAINoImageFallbackProps) => {
|
|||||||
<Flex sx={styles} {...rest}>
|
<Flex sx={styles} {...rest}>
|
||||||
{icon && <Icon as={icon} boxSize={boxSize} opacity={0.7} />}
|
{icon && <Icon as={icon} boxSize={boxSize} opacity={0.7} />}
|
||||||
{props.label && (
|
{props.label && (
|
||||||
<InvText textAlign="center" fontSize="md">
|
<Text textAlign="center" fontSize="md">
|
||||||
{props.label}
|
{props.label}
|
||||||
</InvText>
|
</Text>
|
||||||
)}
|
)}
|
||||||
</Flex>
|
</Flex>
|
||||||
);
|
);
|
||||||
@ -102,7 +100,7 @@ export const IAINoContentFallbackWithSpinner = memo(
|
|||||||
return (
|
return (
|
||||||
<Flex sx={styles} {...rest}>
|
<Flex sx={styles} {...rest}>
|
||||||
<Spinner size="xl" />
|
<Spinner size="xl" />
|
||||||
{props.label && <InvText textAlign="center">{props.label}</InvText>}
|
{props.label && <Text textAlign="center">{props.label}</Text>}
|
||||||
</Flex>
|
</Flex>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
@ -1,15 +1,18 @@
|
|||||||
import { Divider, Flex, Image, Portal } from '@chakra-ui/react';
|
|
||||||
import { useAppSelector } from 'app/store/storeHooks';
|
|
||||||
import { InvButton } from 'common/components/InvButton/InvButton';
|
|
||||||
import { InvHeading } from 'common/components/InvHeading/wrapper';
|
|
||||||
import {
|
import {
|
||||||
InvPopover,
|
Button,
|
||||||
InvPopoverBody,
|
Divider,
|
||||||
InvPopoverCloseButton,
|
Flex,
|
||||||
InvPopoverContent,
|
Heading,
|
||||||
InvPopoverTrigger,
|
Image,
|
||||||
} from 'common/components/InvPopover/wrapper';
|
Popover,
|
||||||
import { InvText } from 'common/components/InvText/wrapper';
|
PopoverBody,
|
||||||
|
PopoverCloseButton,
|
||||||
|
PopoverContent,
|
||||||
|
PopoverTrigger,
|
||||||
|
Portal,
|
||||||
|
Text,
|
||||||
|
} from '@invoke-ai/ui';
|
||||||
|
import { useAppSelector } from 'app/store/storeHooks';
|
||||||
import { merge, omit } from 'lodash-es';
|
import { merge, omit } from 'lodash-es';
|
||||||
import type { ReactElement } from 'react';
|
import type { ReactElement } from 'react';
|
||||||
import { memo, useCallback, useMemo } from 'react';
|
import { memo, useCallback, useMemo } from 'react';
|
||||||
@ -47,7 +50,7 @@ const IAIInformationalPopover = ({
|
|||||||
}
|
}
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<InvPopover
|
<Popover
|
||||||
isLazy
|
isLazy
|
||||||
closeOnBlur={false}
|
closeOnBlur={false}
|
||||||
trigger="hover"
|
trigger="hover"
|
||||||
@ -57,26 +60,26 @@ const IAIInformationalPopover = ({
|
|||||||
placement="top"
|
placement="top"
|
||||||
{...popoverProps}
|
{...popoverProps}
|
||||||
>
|
>
|
||||||
<InvPopoverTrigger>{children}</InvPopoverTrigger>
|
<PopoverTrigger>{children}</PopoverTrigger>
|
||||||
{inPortal ? (
|
{inPortal ? (
|
||||||
<Portal>
|
<Portal>
|
||||||
<PopoverContent data={data} feature={feature} />
|
<Content data={data} feature={feature} />
|
||||||
</Portal>
|
</Portal>
|
||||||
) : (
|
) : (
|
||||||
<PopoverContent data={data} feature={feature} />
|
<Content data={data} feature={feature} />
|
||||||
)}
|
)}
|
||||||
</InvPopover>
|
</Popover>
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|
||||||
export default memo(IAIInformationalPopover);
|
export default memo(IAIInformationalPopover);
|
||||||
|
|
||||||
type PopoverContentProps = {
|
type ContentProps = {
|
||||||
data?: PopoverData;
|
data?: PopoverData;
|
||||||
feature: Feature;
|
feature: Feature;
|
||||||
};
|
};
|
||||||
|
|
||||||
const PopoverContent = ({ data, feature }: PopoverContentProps) => {
|
const Content = ({ data, feature }: ContentProps) => {
|
||||||
const { t } = useTranslation();
|
const { t } = useTranslation();
|
||||||
|
|
||||||
const heading = useMemo<string | undefined>(
|
const heading = useMemo<string | undefined>(
|
||||||
@ -100,13 +103,13 @@ const PopoverContent = ({ data, feature }: PopoverContentProps) => {
|
|||||||
}, [data?.href]);
|
}, [data?.href]);
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<InvPopoverContent w={96}>
|
<PopoverContent w={96}>
|
||||||
<InvPopoverCloseButton />
|
<PopoverCloseButton />
|
||||||
<InvPopoverBody>
|
<PopoverBody>
|
||||||
<Flex gap={2} flexDirection="column" alignItems="flex-start">
|
<Flex gap={2} flexDirection="column" alignItems="flex-start">
|
||||||
{heading && (
|
{heading && (
|
||||||
<>
|
<>
|
||||||
<InvHeading size="sm">{heading}</InvHeading>
|
<Heading size="sm">{heading}</Heading>
|
||||||
<Divider />
|
<Divider />
|
||||||
</>
|
</>
|
||||||
)}
|
)}
|
||||||
@ -124,12 +127,12 @@ const PopoverContent = ({ data, feature }: PopoverContentProps) => {
|
|||||||
</>
|
</>
|
||||||
)}
|
)}
|
||||||
{paragraphs.map((p) => (
|
{paragraphs.map((p) => (
|
||||||
<InvText key={p}>{p}</InvText>
|
<Text key={p}>{p}</Text>
|
||||||
))}
|
))}
|
||||||
{data?.href && (
|
{data?.href && (
|
||||||
<>
|
<>
|
||||||
<Divider />
|
<Divider />
|
||||||
<InvButton
|
<Button
|
||||||
pt={1}
|
pt={1}
|
||||||
onClick={handleClick}
|
onClick={handleClick}
|
||||||
leftIcon={<PiArrowSquareOutBold />}
|
leftIcon={<PiArrowSquareOutBold />}
|
||||||
@ -137,11 +140,11 @@ const PopoverContent = ({ data, feature }: PopoverContentProps) => {
|
|||||||
variant="link"
|
variant="link"
|
||||||
>
|
>
|
||||||
{t('common.learnMore') ?? heading}
|
{t('common.learnMore') ?? heading}
|
||||||
</InvButton>
|
</Button>
|
||||||
</>
|
</>
|
||||||
)}
|
)}
|
||||||
</Flex>
|
</Flex>
|
||||||
</InvPopoverBody>
|
</PopoverBody>
|
||||||
</InvPopoverContent>
|
</PopoverContent>
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
@ -1,4 +1,4 @@
|
|||||||
import type { PopoverProps } from '@chakra-ui/react';
|
import type { PopoverProps } from '@invoke-ai/ui';
|
||||||
|
|
||||||
export type Feature =
|
export type Feature =
|
||||||
| 'clipSkip'
|
| 'clipSkip'
|
||||||
|
@ -1,4 +1,4 @@
|
|||||||
import { Badge, Flex } from '@chakra-ui/react';
|
import { Badge, Flex } from '@invoke-ai/ui';
|
||||||
import { memo } from 'react';
|
import { memo } from 'react';
|
||||||
import type { ImageDTO } from 'services/api/types';
|
import type { ImageDTO } from 'services/api/types';
|
||||||
|
|
||||||
|
@ -1,4 +1,4 @@
|
|||||||
import { Box, Flex, Heading } from '@chakra-ui/react';
|
import { Box, Flex, Heading } from '@invoke-ai/ui';
|
||||||
import type { AnimationProps } from 'framer-motion';
|
import type { AnimationProps } from 'framer-motion';
|
||||||
import { motion } from 'framer-motion';
|
import { motion } from 'framer-motion';
|
||||||
import { memo } from 'react';
|
import { memo } from 'react';
|
||||||
|
@ -1,70 +0,0 @@
|
|||||||
import type { Meta, StoryObj } from '@storybook/react';
|
|
||||||
import { InvText } from 'common/components/InvText/wrapper';
|
|
||||||
|
|
||||||
import { InvAccordionButton } from './InvAccordionButton';
|
|
||||||
import type { InvAccordionProps } from './types';
|
|
||||||
import { InvAccordion, InvAccordionItem, InvAccordionPanel } from './wrapper';
|
|
||||||
|
|
||||||
const meta: Meta<typeof InvAccordion> = {
|
|
||||||
title: 'Primitives/InvAccordion',
|
|
||||||
tags: ['autodocs'],
|
|
||||||
component: InvAccordion,
|
|
||||||
args: {
|
|
||||||
colorScheme: 'base',
|
|
||||||
},
|
|
||||||
};
|
|
||||||
|
|
||||||
export default meta;
|
|
||||||
type Story = StoryObj<typeof InvAccordion>;
|
|
||||||
|
|
||||||
const Component = (props: InvAccordionProps) => {
|
|
||||||
return (
|
|
||||||
<InvAccordion {...props} defaultIndex={[0]} allowMultiple>
|
|
||||||
<InvAccordionItem>
|
|
||||||
<InvAccordionButton badges={['and', 'i', 'said']}>
|
|
||||||
Section 1 title
|
|
||||||
</InvAccordionButton>
|
|
||||||
<InvAccordionPanel p={4}>
|
|
||||||
<InvText>
|
|
||||||
25 years and my life is still Tryin' to get up that great big
|
|
||||||
hill of hope For a destination I realized quickly when I knew I
|
|
||||||
should That the world was made up of this brotherhood of man For
|
|
||||||
whatever that means
|
|
||||||
</InvText>
|
|
||||||
</InvAccordionPanel>
|
|
||||||
</InvAccordionItem>
|
|
||||||
|
|
||||||
<InvAccordionItem>
|
|
||||||
<InvAccordionButton badges={['heeeyyyyyy']}>
|
|
||||||
Section 1 title
|
|
||||||
</InvAccordionButton>
|
|
||||||
<InvAccordionPanel p={4}>
|
|
||||||
<InvText>
|
|
||||||
And so I cry sometimes when I'm lying in bed Just to get it all
|
|
||||||
out what's in my head And I, I am feeling a little peculiar And
|
|
||||||
so I wake in the morning and I step outside And I take a deep breath
|
|
||||||
and I get real high And I scream from the top of my lungs
|
|
||||||
"What's going on?"
|
|
||||||
</InvText>
|
|
||||||
</InvAccordionPanel>
|
|
||||||
</InvAccordionItem>
|
|
||||||
|
|
||||||
<InvAccordionItem>
|
|
||||||
<InvAccordionButton badges={["what's", 'goin', 'on', '?']}>
|
|
||||||
Section 2 title
|
|
||||||
</InvAccordionButton>
|
|
||||||
<InvAccordionPanel p={4}>
|
|
||||||
<InvText>
|
|
||||||
And I say, hey-ey-ey Hey-ey-ey I said "Hey, a-what's going
|
|
||||||
on?" And I say, hey-ey-ey Hey-ey-ey I said "Hey,
|
|
||||||
a-what's going on?"
|
|
||||||
</InvText>
|
|
||||||
</InvAccordionPanel>
|
|
||||||
</InvAccordionItem>
|
|
||||||
</InvAccordion>
|
|
||||||
);
|
|
||||||
};
|
|
||||||
|
|
||||||
export const Default: Story = {
|
|
||||||
render: Component,
|
|
||||||
};
|
|
@ -1,31 +0,0 @@
|
|||||||
import {
|
|
||||||
AccordionButton as ChakraAccordionButton,
|
|
||||||
Spacer,
|
|
||||||
} from '@chakra-ui/react';
|
|
||||||
import { InvBadge } from 'common/components/InvBadge/wrapper';
|
|
||||||
import { truncate } from 'lodash-es';
|
|
||||||
import { useMemo } from 'react';
|
|
||||||
|
|
||||||
import type { InvAccordionButtonProps } from './types';
|
|
||||||
import { InvAccordionIcon } from './wrapper';
|
|
||||||
|
|
||||||
export const InvAccordionButton = (props: InvAccordionButtonProps) => {
|
|
||||||
const { children, badges: _badges, ...rest } = props;
|
|
||||||
const badges = useMemo<string[] | undefined>(
|
|
||||||
() =>
|
|
||||||
_badges?.map((b) => truncate(String(b), { length: 24, omission: '...' })),
|
|
||||||
[_badges]
|
|
||||||
);
|
|
||||||
return (
|
|
||||||
<ChakraAccordionButton {...rest}>
|
|
||||||
{children}
|
|
||||||
<Spacer />
|
|
||||||
{badges?.map((b, i) => (
|
|
||||||
<InvBadge key={`${b}.${i}`} colorScheme="invokeBlue">
|
|
||||||
{b}
|
|
||||||
</InvBadge>
|
|
||||||
))}
|
|
||||||
<InvAccordionIcon />
|
|
||||||
</ChakraAccordionButton>
|
|
||||||
);
|
|
||||||
};
|
|
@ -1,71 +0,0 @@
|
|||||||
import { accordionAnatomy as parts } from '@chakra-ui/anatomy';
|
|
||||||
import {
|
|
||||||
createMultiStyleConfigHelpers,
|
|
||||||
defineStyle,
|
|
||||||
} from '@chakra-ui/styled-system';
|
|
||||||
|
|
||||||
const { definePartsStyle, defineMultiStyleConfig } =
|
|
||||||
createMultiStyleConfigHelpers(parts.keys);
|
|
||||||
|
|
||||||
const invokeAIContainer = defineStyle({
|
|
||||||
border: 'none',
|
|
||||||
bg: 'base.850',
|
|
||||||
borderRadius: 'base',
|
|
||||||
':has(&div &button:hover)': { bg: 'base.800' },
|
|
||||||
transitionProperty: 'common',
|
|
||||||
transitionDuration: '0.1s',
|
|
||||||
});
|
|
||||||
|
|
||||||
const invokeAIButton = defineStyle((_props) => {
|
|
||||||
return {
|
|
||||||
gap: 2,
|
|
||||||
fontWeight: 'semibold',
|
|
||||||
fontSize: 'sm',
|
|
||||||
border: 'none',
|
|
||||||
borderRadius: 'base',
|
|
||||||
color: 'base.300',
|
|
||||||
_hover: {},
|
|
||||||
_expanded: {
|
|
||||||
borderBottomRadius: 'none',
|
|
||||||
},
|
|
||||||
};
|
|
||||||
});
|
|
||||||
|
|
||||||
const invokeAIPanel = defineStyle((props) => {
|
|
||||||
const { colorScheme: c } = props;
|
|
||||||
return {
|
|
||||||
bg: `${c}.800`,
|
|
||||||
borderRadius: 'base',
|
|
||||||
p: 0,
|
|
||||||
transitionProperty: 'common',
|
|
||||||
transitionDuration: '0.1s',
|
|
||||||
};
|
|
||||||
});
|
|
||||||
|
|
||||||
const invokeAIIcon = defineStyle({
|
|
||||||
ms: 2,
|
|
||||||
});
|
|
||||||
|
|
||||||
const invokeAI = definePartsStyle((props) => ({
|
|
||||||
container: invokeAIContainer,
|
|
||||||
button: invokeAIButton(props),
|
|
||||||
panel: invokeAIPanel(props),
|
|
||||||
icon: invokeAIIcon,
|
|
||||||
}));
|
|
||||||
|
|
||||||
const baseStyle = definePartsStyle(() => ({
|
|
||||||
root: {
|
|
||||||
display: 'flex',
|
|
||||||
flexDirection: 'column',
|
|
||||||
gap: 4,
|
|
||||||
},
|
|
||||||
}));
|
|
||||||
|
|
||||||
export const accordionTheme = defineMultiStyleConfig({
|
|
||||||
baseStyle,
|
|
||||||
variants: { invokeAI },
|
|
||||||
defaultProps: {
|
|
||||||
variant: 'invokeAI',
|
|
||||||
colorScheme: 'base',
|
|
||||||
},
|
|
||||||
});
|
|
@ -1,11 +0,0 @@
|
|||||||
import type { AccordionButtonProps as ChakraAccordionButtonProps } from '@chakra-ui/react';
|
|
||||||
export type {
|
|
||||||
AccordionIconProps as InvAccordionIconProps,
|
|
||||||
AccordionItemProps as InvAccordionItemProps,
|
|
||||||
AccordionPanelProps as InvAccordionPanelProps,
|
|
||||||
AccordionProps as InvAccordionProps,
|
|
||||||
} from '@chakra-ui/react';
|
|
||||||
|
|
||||||
export type InvAccordionButtonProps = ChakraAccordionButtonProps & {
|
|
||||||
badges?: (string | number)[];
|
|
||||||
};
|
|
@ -1,6 +0,0 @@
|
|||||||
export {
|
|
||||||
Accordion as InvAccordion,
|
|
||||||
AccordionIcon as InvAccordionIcon,
|
|
||||||
AccordionItem as InvAccordionItem,
|
|
||||||
AccordionPanel as InvAccordionPanel,
|
|
||||||
} from '@chakra-ui/react';
|
|
@ -1,4 +0,0 @@
|
|||||||
/**
|
|
||||||
* AlertDialog is a chakra Modal internally and uses those props.
|
|
||||||
*/
|
|
||||||
export type { AlertDialogProps as InvAlertDialogProps } from '@chakra-ui/react';
|
|
@ -1,9 +0,0 @@
|
|||||||
export {
|
|
||||||
AlertDialog as InvAlertDialog,
|
|
||||||
AlertDialogBody as InvAlertDialogBody,
|
|
||||||
AlertDialogCloseButton as InvAlertDialogCloseButton,
|
|
||||||
AlertDialogContent as InvAlertDialogContent,
|
|
||||||
AlertDialogFooter as InvAlertDialogFooter,
|
|
||||||
AlertDialogHeader as InvAlertDialogHeader,
|
|
||||||
AlertDialogOverlay as InvAlertDialogOverlay,
|
|
||||||
} from '@chakra-ui/react';
|
|
@ -1,4 +1,4 @@
|
|||||||
import { Box, forwardRef, Textarea as ChakraTextarea } from '@chakra-ui/react';
|
import { Box, forwardRef, Textarea as ChakraTextarea } from '@invoke-ai/ui';
|
||||||
import { useGlobalModifiersSetters } from 'common/hooks/useGlobalModifiers';
|
import { useGlobalModifiersSetters } from 'common/hooks/useGlobalModifiers';
|
||||||
import { stopPastePropagation } from 'common/util/stopPastePropagation';
|
import { stopPastePropagation } from 'common/util/stopPastePropagation';
|
||||||
import type { KeyboardEvent } from 'react';
|
import type { KeyboardEvent } from 'react';
|
||||||
|
@ -1,4 +1,4 @@
|
|||||||
import type { TextareaProps as ChakraTextareaProps } from '@chakra-ui/react';
|
import type { TextareaProps as ChakraTextareaProps } from '@invoke-ai/ui';
|
||||||
import type { TextareaAutosizeProps } from 'react-textarea-autosize';
|
import type { TextareaAutosizeProps } from 'react-textarea-autosize';
|
||||||
|
|
||||||
export type InvAutosizeTextareaProps = Omit<
|
export type InvAutosizeTextareaProps = Omit<
|
||||||
|
@ -1,24 +0,0 @@
|
|||||||
import type { Meta, StoryObj } from '@storybook/react';
|
|
||||||
|
|
||||||
import type { InvBadgeProps } from './types';
|
|
||||||
import { InvBadge } from './wrapper';
|
|
||||||
|
|
||||||
const meta: Meta<typeof InvBadge> = {
|
|
||||||
title: 'Primitives/InvBadge',
|
|
||||||
tags: ['autodocs'],
|
|
||||||
component: InvBadge,
|
|
||||||
args: {
|
|
||||||
colorScheme: 'base',
|
|
||||||
},
|
|
||||||
};
|
|
||||||
|
|
||||||
export default meta;
|
|
||||||
type Story = StoryObj<typeof InvBadge>;
|
|
||||||
|
|
||||||
const Component = (props: InvBadgeProps) => {
|
|
||||||
return <InvBadge {...props}>Invoke</InvBadge>;
|
|
||||||
};
|
|
||||||
|
|
||||||
export const Default: Story = {
|
|
||||||
render: Component,
|
|
||||||
};
|
|
@ -1,25 +0,0 @@
|
|||||||
import { defineStyle, defineStyleConfig } from '@chakra-ui/react';
|
|
||||||
|
|
||||||
const baseStyle = defineStyle((props) => ({
|
|
||||||
fontSize: 9,
|
|
||||||
px: 2,
|
|
||||||
py: 1,
|
|
||||||
minW: 4,
|
|
||||||
lineHeight: 1,
|
|
||||||
borderRadius: 'sm',
|
|
||||||
bg: `${props.colorScheme}.200`,
|
|
||||||
color: 'base.900',
|
|
||||||
fontWeight: 'bold',
|
|
||||||
letterSpacing: 0.6,
|
|
||||||
wordBreak: 'break-all',
|
|
||||||
whiteSpace: 'nowrap',
|
|
||||||
textOverflow: 'ellipsis',
|
|
||||||
overflow: 'hidden',
|
|
||||||
}));
|
|
||||||
|
|
||||||
export const badgeTheme = defineStyleConfig({
|
|
||||||
baseStyle,
|
|
||||||
defaultProps: {
|
|
||||||
colorScheme: 'base',
|
|
||||||
},
|
|
||||||
});
|
|
@ -1,3 +0,0 @@
|
|||||||
import type { BadgeProps as ChakraBadgeProps } from '@chakra-ui/react';
|
|
||||||
|
|
||||||
export type InvBadgeProps = ChakraBadgeProps;
|
|
@ -1 +0,0 @@
|
|||||||
export { Badge as InvBadge } from '@chakra-ui/react';
|
|
@ -1,99 +0,0 @@
|
|||||||
import { Flex } from '@chakra-ui/layout';
|
|
||||||
import type { Meta, StoryObj } from '@storybook/react';
|
|
||||||
import { InvHeading } from 'common/components/InvHeading/wrapper';
|
|
||||||
import { IoSparkles } from 'react-icons/io5';
|
|
||||||
|
|
||||||
import { InvButton } from './InvButton';
|
|
||||||
import type { InvButtonProps } from './types';
|
|
||||||
|
|
||||||
const meta: Meta<typeof InvButton> = {
|
|
||||||
title: 'Primitives/InvButton',
|
|
||||||
tags: ['autodocs'],
|
|
||||||
component: InvButton,
|
|
||||||
parameters: {
|
|
||||||
controls: { expanded: true },
|
|
||||||
},
|
|
||||||
argTypes: {
|
|
||||||
isLoading: {
|
|
||||||
defaultValue: false,
|
|
||||||
control: { type: 'boolean' },
|
|
||||||
},
|
|
||||||
isDisabled: {
|
|
||||||
defaultValue: false,
|
|
||||||
control: { type: 'boolean' },
|
|
||||||
},
|
|
||||||
},
|
|
||||||
};
|
|
||||||
|
|
||||||
export default meta;
|
|
||||||
type Story = StoryObj<typeof InvButton>;
|
|
||||||
|
|
||||||
const colorSchemes = [
|
|
||||||
'base',
|
|
||||||
'invokeYellow',
|
|
||||||
'invokeRed',
|
|
||||||
'invokeGreen',
|
|
||||||
'invokeBlue',
|
|
||||||
] as const;
|
|
||||||
const variants = ['solid', 'outline', 'ghost', 'link'] as const;
|
|
||||||
const sizes = ['xs', 'sm', 'md', 'lg'] as const;
|
|
||||||
|
|
||||||
const Component = (props: InvButtonProps) => {
|
|
||||||
return (
|
|
||||||
<Flex gap={4} flexDir="column">
|
|
||||||
{sizes.map((size) => (
|
|
||||||
<>
|
|
||||||
<InvHeading>Size: {size}</InvHeading>
|
|
||||||
|
|
||||||
<Flex key={size} gap={4} flexDir="column">
|
|
||||||
{colorSchemes.map((colorScheme) => (
|
|
||||||
<Flex key={colorScheme} gap={4}>
|
|
||||||
{variants.map((variant) => (
|
|
||||||
<>
|
|
||||||
<InvButton
|
|
||||||
size={size}
|
|
||||||
key={`${variant}${colorScheme}`}
|
|
||||||
variant={variant}
|
|
||||||
colorScheme={colorScheme}
|
|
||||||
{...props}
|
|
||||||
>
|
|
||||||
{variant}
|
|
||||||
</InvButton>
|
|
||||||
{['solid', 'outline'].includes(variant) && (
|
|
||||||
<InvButton
|
|
||||||
size={size}
|
|
||||||
key={`${variant}${colorScheme}leftIcon`}
|
|
||||||
variant={variant}
|
|
||||||
colorScheme={colorScheme}
|
|
||||||
leftIcon={<IoSparkles />}
|
|
||||||
{...props}
|
|
||||||
>
|
|
||||||
{variant}
|
|
||||||
</InvButton>
|
|
||||||
)}
|
|
||||||
{['solid', 'outline'].includes(variant) && (
|
|
||||||
<InvButton
|
|
||||||
size={size}
|
|
||||||
key={`${variant}${colorScheme}rightIcon`}
|
|
||||||
variant={variant}
|
|
||||||
colorScheme={colorScheme}
|
|
||||||
rightIcon={<IoSparkles />}
|
|
||||||
{...props}
|
|
||||||
>
|
|
||||||
{variant}
|
|
||||||
</InvButton>
|
|
||||||
)}
|
|
||||||
</>
|
|
||||||
))}
|
|
||||||
</Flex>
|
|
||||||
))}
|
|
||||||
</Flex>
|
|
||||||
</>
|
|
||||||
))}
|
|
||||||
</Flex>
|
|
||||||
);
|
|
||||||
};
|
|
||||||
|
|
||||||
export const Default: Story = {
|
|
||||||
render: Component,
|
|
||||||
};
|
|
@ -1,37 +0,0 @@
|
|||||||
import { Button, forwardRef } from '@chakra-ui/react';
|
|
||||||
import { InvTooltip } from 'common/components/InvTooltip/InvTooltip';
|
|
||||||
import { memo } from 'react';
|
|
||||||
|
|
||||||
import type { InvButtonProps } from './types';
|
|
||||||
|
|
||||||
export const InvButton = memo(
|
|
||||||
forwardRef<InvButtonProps, typeof Button>(
|
|
||||||
({ isChecked, tooltip, children, ...rest }: InvButtonProps, ref) => {
|
|
||||||
if (tooltip) {
|
|
||||||
return (
|
|
||||||
<InvTooltip label={tooltip}>
|
|
||||||
<Button
|
|
||||||
ref={ref}
|
|
||||||
colorScheme={isChecked ? 'invokeBlue' : 'base'}
|
|
||||||
{...rest}
|
|
||||||
>
|
|
||||||
{children}
|
|
||||||
</Button>
|
|
||||||
</InvTooltip>
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
return (
|
|
||||||
<Button
|
|
||||||
ref={ref}
|
|
||||||
colorScheme={isChecked ? 'invokeBlue' : 'base'}
|
|
||||||
{...rest}
|
|
||||||
>
|
|
||||||
{children}
|
|
||||||
</Button>
|
|
||||||
);
|
|
||||||
}
|
|
||||||
)
|
|
||||||
);
|
|
||||||
|
|
||||||
InvButton.displayName = 'InvButton';
|
|
@ -1,228 +0,0 @@
|
|||||||
import type { StyleFunctionProps } from '@chakra-ui/react';
|
|
||||||
import { defineStyle, defineStyleConfig } from '@chakra-ui/react';
|
|
||||||
import { buttonVariantPromptOverlay } from 'features/parameters/components/Prompts/theme';
|
|
||||||
|
|
||||||
type Variant = `solid` | `outline` | `ghost` | `link`;
|
|
||||||
|
|
||||||
const getBorders = (
|
|
||||||
props: StyleFunctionProps,
|
|
||||||
variant: Variant
|
|
||||||
): { borderWidth: string; borderStyle: string } => {
|
|
||||||
if (variant !== 'outline') {
|
|
||||||
return {
|
|
||||||
borderWidth: '0px',
|
|
||||||
borderStyle: 'none',
|
|
||||||
};
|
|
||||||
}
|
|
||||||
if (props.size === 'lg') {
|
|
||||||
return {
|
|
||||||
borderWidth: '1px',
|
|
||||||
borderStyle: 'solid',
|
|
||||||
};
|
|
||||||
}
|
|
||||||
if (props.size === 'md') {
|
|
||||||
return {
|
|
||||||
borderWidth: '1px',
|
|
||||||
borderStyle: 'solid',
|
|
||||||
};
|
|
||||||
}
|
|
||||||
return {
|
|
||||||
borderWidth: '1px',
|
|
||||||
borderStyle: 'solid',
|
|
||||||
};
|
|
||||||
};
|
|
||||||
|
|
||||||
const getColors = (
|
|
||||||
props: StyleFunctionProps,
|
|
||||||
variant: Variant
|
|
||||||
): {
|
|
||||||
bg: string;
|
|
||||||
bgDisabled: string;
|
|
||||||
bgHover: string;
|
|
||||||
fg: string;
|
|
||||||
fgDisabled: string;
|
|
||||||
fgHover: string;
|
|
||||||
borderColor: string;
|
|
||||||
borderColorDisabled: string;
|
|
||||||
borderColorHover: string;
|
|
||||||
} => {
|
|
||||||
const { colorScheme: c } = props;
|
|
||||||
|
|
||||||
const bgBase = 'base.400';
|
|
||||||
const bgColor = c === 'invokeYellow' ? `${c}.500` : `${c}.400`;
|
|
||||||
const bgBaseHover = 'base.300';
|
|
||||||
const bgColorHover = c === 'invokeYellow' ? `${c}.300` : `${c}.300`;
|
|
||||||
|
|
||||||
const notSolidFg = {
|
|
||||||
fg: c === 'base' ? 'base.300' : bgColor,
|
|
||||||
fgHover: c === 'base' ? 'base.50' : bgColorHover,
|
|
||||||
fgDisabled: 'base.600',
|
|
||||||
};
|
|
||||||
const noBg = { bg: 'none', bgHover: 'none', bgDisabled: 'none' };
|
|
||||||
const noBorder = {
|
|
||||||
borderColor: 'none',
|
|
||||||
borderColorDisabled: 'none',
|
|
||||||
borderColorHover: 'none',
|
|
||||||
};
|
|
||||||
|
|
||||||
if (variant === 'ghost') {
|
|
||||||
return {
|
|
||||||
...notSolidFg,
|
|
||||||
...noBg,
|
|
||||||
...noBorder,
|
|
||||||
bgHover: 'baseAlpha.200',
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
if (variant === 'link') {
|
|
||||||
return {
|
|
||||||
...notSolidFg,
|
|
||||||
...noBg,
|
|
||||||
...noBorder,
|
|
||||||
};
|
|
||||||
}
|
|
||||||
if (variant === 'outline') {
|
|
||||||
return {
|
|
||||||
...notSolidFg,
|
|
||||||
...noBg,
|
|
||||||
borderColor: c === 'invokeYellow' ? `${c}Alpha.500` : `${c}Alpha.400`,
|
|
||||||
borderColorDisabled: 'base.600',
|
|
||||||
borderColorHover:
|
|
||||||
c === 'invokeYellow' ? `${c}Alpha.700` : `${c}Alpha.600`,
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
// solid
|
|
||||||
return {
|
|
||||||
bg: c === 'base' ? bgBase : bgColor,
|
|
||||||
bgHover: c === 'base' ? bgBaseHover : bgColorHover,
|
|
||||||
bgDisabled: 'base.600',
|
|
||||||
fg: 'base.900',
|
|
||||||
fgHover: 'base.900',
|
|
||||||
fgDisabled: 'base.750',
|
|
||||||
...noBorder,
|
|
||||||
};
|
|
||||||
};
|
|
||||||
|
|
||||||
const getStyles = (
|
|
||||||
props: StyleFunctionProps,
|
|
||||||
variant: 'ghost' | 'solid' | 'outline' | 'link'
|
|
||||||
) => {
|
|
||||||
const { borderWidth, borderStyle } = getBorders(props, variant);
|
|
||||||
const {
|
|
||||||
bg,
|
|
||||||
bgDisabled,
|
|
||||||
bgHover,
|
|
||||||
fg,
|
|
||||||
fgDisabled,
|
|
||||||
fgHover,
|
|
||||||
borderColor,
|
|
||||||
borderColorDisabled,
|
|
||||||
borderColorHover,
|
|
||||||
} = getColors(props, variant);
|
|
||||||
|
|
||||||
const _disabled = {
|
|
||||||
bg: bgDisabled,
|
|
||||||
color: fgDisabled,
|
|
||||||
opacity: 1,
|
|
||||||
borderColor: borderColorDisabled,
|
|
||||||
svg: {
|
|
||||||
fill: fgDisabled,
|
|
||||||
},
|
|
||||||
_hover: {
|
|
||||||
bg: bgDisabled,
|
|
||||||
color: fgDisabled,
|
|
||||||
borderColor: borderColorDisabled,
|
|
||||||
svg: {
|
|
||||||
fill: fgDisabled,
|
|
||||||
},
|
|
||||||
},
|
|
||||||
};
|
|
||||||
|
|
||||||
const _base = {
|
|
||||||
bg: bg,
|
|
||||||
color: fg,
|
|
||||||
borderWidth: borderWidth,
|
|
||||||
borderStyle: borderStyle,
|
|
||||||
borderColor: borderColor,
|
|
||||||
svg: {
|
|
||||||
fill: fg,
|
|
||||||
},
|
|
||||||
};
|
|
||||||
|
|
||||||
return {
|
|
||||||
..._base,
|
|
||||||
_hover: {
|
|
||||||
bg: bgHover,
|
|
||||||
color: fgHover,
|
|
||||||
borderColor: borderColorHover,
|
|
||||||
svg: {
|
|
||||||
fill: fgHover,
|
|
||||||
},
|
|
||||||
_disabled,
|
|
||||||
},
|
|
||||||
_active: { ..._base },
|
|
||||||
_disabled,
|
|
||||||
} as const;
|
|
||||||
};
|
|
||||||
|
|
||||||
export const buttonTheme = defineStyleConfig({
|
|
||||||
baseStyle: {
|
|
||||||
fontWeight: 'semibold',
|
|
||||||
svg: {
|
|
||||||
transitionProperty: 'all',
|
|
||||||
transitionDuration: 'faster',
|
|
||||||
},
|
|
||||||
},
|
|
||||||
sizes: {
|
|
||||||
sm: {
|
|
||||||
fontSize: 'sm',
|
|
||||||
px: 3,
|
|
||||||
py: 2,
|
|
||||||
},
|
|
||||||
md: {
|
|
||||||
fontSize: 'md',
|
|
||||||
px: 4,
|
|
||||||
py: 2,
|
|
||||||
},
|
|
||||||
lg: {
|
|
||||||
fontSize: 'lg',
|
|
||||||
px: 4,
|
|
||||||
py: 2,
|
|
||||||
h: 12,
|
|
||||||
},
|
|
||||||
},
|
|
||||||
variants: {
|
|
||||||
solid: defineStyle((props) => getStyles(props, 'solid')),
|
|
||||||
appTab: defineStyle((_props) => {
|
|
||||||
// Has no disabled, invalid, loading, etc state
|
|
||||||
return {
|
|
||||||
bg: 'none',
|
|
||||||
svg: {
|
|
||||||
fill: 'base.600',
|
|
||||||
},
|
|
||||||
_hover: {
|
|
||||||
bg: 'none',
|
|
||||||
svg: {
|
|
||||||
fill: 'base.400',
|
|
||||||
},
|
|
||||||
},
|
|
||||||
'&[data-selected="true"]': {
|
|
||||||
bg: 'none',
|
|
||||||
svg: {
|
|
||||||
fill: 'base.100',
|
|
||||||
},
|
|
||||||
},
|
|
||||||
};
|
|
||||||
}),
|
|
||||||
outline: defineStyle((props) => getStyles(props, 'outline')),
|
|
||||||
ghost: defineStyle((props) => getStyles(props, 'ghost')),
|
|
||||||
link: defineStyle((props) => getStyles(props, 'link')),
|
|
||||||
promptOverlay: buttonVariantPromptOverlay,
|
|
||||||
},
|
|
||||||
defaultProps: {
|
|
||||||
variant: 'solid',
|
|
||||||
colorScheme: 'base',
|
|
||||||
size: 'md',
|
|
||||||
},
|
|
||||||
});
|
|
@ -1,7 +0,0 @@
|
|||||||
import type { ButtonProps } from '@chakra-ui/react';
|
|
||||||
import type { ReactNode } from 'react';
|
|
||||||
|
|
||||||
export type InvButtonProps = ButtonProps & {
|
|
||||||
isChecked?: boolean;
|
|
||||||
tooltip?: ReactNode;
|
|
||||||
};
|
|
@ -1,47 +0,0 @@
|
|||||||
import type { Meta, StoryObj } from '@storybook/react';
|
|
||||||
import { InvButton } from 'common/components/InvButton/InvButton';
|
|
||||||
import { InvIconButton } from 'common/components/InvIconButton/InvIconButton';
|
|
||||||
import { FaImage } from 'react-icons/fa';
|
|
||||||
|
|
||||||
import { InvButtonGroup } from './InvButtonGroup';
|
|
||||||
import type { InvButtonGroupProps } from './types';
|
|
||||||
|
|
||||||
const meta: Meta<typeof InvButtonGroup> = {
|
|
||||||
title: 'Primitives/InvButtonGroup',
|
|
||||||
tags: ['autodocs'],
|
|
||||||
component: InvButtonGroup,
|
|
||||||
args: {
|
|
||||||
colorScheme: 'base',
|
|
||||||
},
|
|
||||||
};
|
|
||||||
|
|
||||||
export default meta;
|
|
||||||
type Story = StoryObj<typeof InvButtonGroup>;
|
|
||||||
|
|
||||||
const Component = (props: InvButtonGroupProps) => {
|
|
||||||
return (
|
|
||||||
<InvButtonGroup {...props}>
|
|
||||||
<InvButton>Test</InvButton>
|
|
||||||
<InvButton>Test</InvButton>
|
|
||||||
<InvButton>Test</InvButton>
|
|
||||||
</InvButtonGroup>
|
|
||||||
);
|
|
||||||
};
|
|
||||||
|
|
||||||
const ComponentWithIconButtons = (props: InvButtonGroupProps) => {
|
|
||||||
return (
|
|
||||||
<InvButtonGroup {...props}>
|
|
||||||
<InvIconButton aria-label="test" icon={<FaImage />} />
|
|
||||||
<InvIconButton aria-label="test" icon={<FaImage />} />
|
|
||||||
<InvIconButton aria-label="test" icon={<FaImage />} />
|
|
||||||
</InvButtonGroup>
|
|
||||||
);
|
|
||||||
};
|
|
||||||
|
|
||||||
export const Default: Story = {
|
|
||||||
render: Component,
|
|
||||||
};
|
|
||||||
|
|
||||||
export const WithIconButtons: Story = {
|
|
||||||
render: ComponentWithIconButtons,
|
|
||||||
};
|
|
@ -1,14 +0,0 @@
|
|||||||
import { ButtonGroup, forwardRef } from '@chakra-ui/react';
|
|
||||||
import { memo } from 'react';
|
|
||||||
|
|
||||||
import type { InvButtonGroupProps } from './types';
|
|
||||||
|
|
||||||
export const InvButtonGroup = memo(
|
|
||||||
forwardRef<InvButtonGroupProps, typeof ButtonGroup>(
|
|
||||||
({ isAttached = true, ...rest }: InvButtonGroupProps, ref) => {
|
|
||||||
return <ButtonGroup ref={ref} isAttached={isAttached} {...rest} />;
|
|
||||||
}
|
|
||||||
)
|
|
||||||
);
|
|
||||||
|
|
||||||
InvButtonGroup.displayName = 'InvButtonGroup';
|
|
@ -1 +0,0 @@
|
|||||||
export type { ButtonGroupProps as InvButtonGroupProps } from '@chakra-ui/react';
|
|
@ -1,24 +0,0 @@
|
|||||||
import type { Meta, StoryObj } from '@storybook/react';
|
|
||||||
|
|
||||||
import type { InvCardProps } from './types';
|
|
||||||
import { InvCard } from './wrapper';
|
|
||||||
|
|
||||||
const meta: Meta<typeof InvCard> = {
|
|
||||||
title: 'Primitives/InvCard',
|
|
||||||
tags: ['autodocs'],
|
|
||||||
component: InvCard,
|
|
||||||
args: {
|
|
||||||
colorScheme: 'base',
|
|
||||||
},
|
|
||||||
};
|
|
||||||
|
|
||||||
export default meta;
|
|
||||||
type Story = StoryObj<typeof InvCard>;
|
|
||||||
|
|
||||||
const Component = (props: InvCardProps) => {
|
|
||||||
return <InvCard {...props}>Invoke</InvCard>;
|
|
||||||
};
|
|
||||||
|
|
||||||
export const Default: Story = {
|
|
||||||
render: Component,
|
|
||||||
};
|
|
@ -1,11 +0,0 @@
|
|||||||
import { cardAnatomy } from '@chakra-ui/anatomy';
|
|
||||||
import { createMultiStyleConfigHelpers } from '@chakra-ui/react';
|
|
||||||
import { cardVariantLora } from 'features/lora/components/styles';
|
|
||||||
|
|
||||||
const { defineMultiStyleConfig } = createMultiStyleConfigHelpers(
|
|
||||||
cardAnatomy.keys
|
|
||||||
);
|
|
||||||
|
|
||||||
export const cardTheme = defineMultiStyleConfig({
|
|
||||||
variants: { lora: cardVariantLora },
|
|
||||||
});
|
|
@ -1,6 +0,0 @@
|
|||||||
export type {
|
|
||||||
CardBodyProps as InvCardBodyProps,
|
|
||||||
CardFooterProps as InvCardFooterProps,
|
|
||||||
CardHeaderProps as InvCardHeaderProps,
|
|
||||||
CardProps as InvCardProps,
|
|
||||||
} from '@chakra-ui/react';
|
|
@ -1,6 +0,0 @@
|
|||||||
export {
|
|
||||||
Card as InvCard,
|
|
||||||
CardBody as InvCardBody,
|
|
||||||
CardFooter as InvCardFooter,
|
|
||||||
CardHeader as InvCardHeader,
|
|
||||||
} from '@chakra-ui/react';
|
|
@ -1,21 +0,0 @@
|
|||||||
import type { Meta, StoryObj } from '@storybook/react';
|
|
||||||
|
|
||||||
import type { InvCheckboxProps } from './types';
|
|
||||||
import { InvCheckbox } from './wrapper';
|
|
||||||
|
|
||||||
const meta: Meta<typeof InvCheckbox> = {
|
|
||||||
title: 'Primitives/InvCheckbox',
|
|
||||||
tags: ['autodocs'],
|
|
||||||
component: InvCheckbox,
|
|
||||||
};
|
|
||||||
|
|
||||||
export default meta;
|
|
||||||
type Story = StoryObj<typeof InvCheckbox>;
|
|
||||||
|
|
||||||
const Component = (props: InvCheckboxProps) => {
|
|
||||||
return <InvCheckbox {...props} />;
|
|
||||||
};
|
|
||||||
|
|
||||||
export const Default: Story = {
|
|
||||||
render: Component,
|
|
||||||
};
|
|
@ -1,69 +0,0 @@
|
|||||||
import { checkboxAnatomy as parts } from '@chakra-ui/anatomy';
|
|
||||||
import {
|
|
||||||
createMultiStyleConfigHelpers,
|
|
||||||
defineStyle,
|
|
||||||
} from '@chakra-ui/styled-system';
|
|
||||||
|
|
||||||
const { definePartsStyle, defineMultiStyleConfig } =
|
|
||||||
createMultiStyleConfigHelpers(parts.keys);
|
|
||||||
|
|
||||||
const invokeAIControl = defineStyle((props) => {
|
|
||||||
const { colorScheme: c } = props;
|
|
||||||
|
|
||||||
return {
|
|
||||||
bg: 'base.700',
|
|
||||||
borderColor: 'base.600',
|
|
||||||
color: 'base.100',
|
|
||||||
|
|
||||||
_checked: {
|
|
||||||
bg: `${c}.500`,
|
|
||||||
borderColor: `${c}.500`,
|
|
||||||
color: `${c}.100`,
|
|
||||||
|
|
||||||
_hover: {
|
|
||||||
bg: `${c}.500`,
|
|
||||||
borderColor: `${c}.500`,
|
|
||||||
},
|
|
||||||
|
|
||||||
_disabled: {
|
|
||||||
borderColor: 'transparent',
|
|
||||||
bg: 'whiteAlpha.300',
|
|
||||||
color: 'whiteAlpha.500',
|
|
||||||
},
|
|
||||||
},
|
|
||||||
|
|
||||||
_indeterminate: {
|
|
||||||
bg: `${c}.600`,
|
|
||||||
borderColor: `${c}.600`,
|
|
||||||
color: `${c}.100`,
|
|
||||||
},
|
|
||||||
|
|
||||||
_disabled: {
|
|
||||||
bg: 'whiteAlpha.100',
|
|
||||||
borderColor: 'transparent',
|
|
||||||
},
|
|
||||||
|
|
||||||
_focusVisible: {
|
|
||||||
boxShadow: 'none',
|
|
||||||
outline: 'none',
|
|
||||||
},
|
|
||||||
|
|
||||||
_invalid: {
|
|
||||||
borderColor: 'error.300',
|
|
||||||
},
|
|
||||||
};
|
|
||||||
});
|
|
||||||
|
|
||||||
const invokeAI = definePartsStyle((props) => ({
|
|
||||||
control: invokeAIControl(props),
|
|
||||||
}));
|
|
||||||
|
|
||||||
export const checkboxTheme = defineMultiStyleConfig({
|
|
||||||
variants: {
|
|
||||||
invokeAI: invokeAI,
|
|
||||||
},
|
|
||||||
defaultProps: {
|
|
||||||
variant: 'invokeAI',
|
|
||||||
colorScheme: 'blue',
|
|
||||||
},
|
|
||||||
});
|
|
@ -1,3 +0,0 @@
|
|||||||
import type { CheckboxProps as ChakraCheckboxProps } from '@chakra-ui/react';
|
|
||||||
|
|
||||||
export interface InvCheckboxProps extends ChakraCheckboxProps {}
|
|
@ -1 +0,0 @@
|
|||||||
export { Checkbox as InvCheckbox } from '@chakra-ui/react';
|
|
@ -1,76 +0,0 @@
|
|||||||
import {
|
|
||||||
InvAlertDialog,
|
|
||||||
InvAlertDialogBody,
|
|
||||||
InvAlertDialogContent,
|
|
||||||
InvAlertDialogFooter,
|
|
||||||
InvAlertDialogHeader,
|
|
||||||
InvAlertDialogOverlay,
|
|
||||||
} from 'common/components/InvAlertDialog/wrapper';
|
|
||||||
import { InvButton } from 'common/components/InvButton/InvButton';
|
|
||||||
import { memo, useCallback, useRef } from 'react';
|
|
||||||
import { useTranslation } from 'react-i18next';
|
|
||||||
|
|
||||||
import type { InvConfirmationAlertDialogProps } from './types';
|
|
||||||
|
|
||||||
/**
|
|
||||||
* This component is a wrapper around InvAlertDialog that provides a confirmation dialog.
|
|
||||||
* Its state must be managed externally using chakra's `useDisclosure()` hook.
|
|
||||||
*/
|
|
||||||
export const InvConfirmationAlertDialog = memo(
|
|
||||||
(props: InvConfirmationAlertDialogProps) => {
|
|
||||||
const { t } = useTranslation();
|
|
||||||
|
|
||||||
const {
|
|
||||||
acceptCallback,
|
|
||||||
cancelCallback,
|
|
||||||
acceptButtonText = t('common.accept'),
|
|
||||||
cancelButtonText = t('common.cancel'),
|
|
||||||
children,
|
|
||||||
title,
|
|
||||||
isOpen,
|
|
||||||
onClose,
|
|
||||||
} = props;
|
|
||||||
|
|
||||||
const cancelRef = useRef<HTMLButtonElement | null>(null);
|
|
||||||
|
|
||||||
const handleAccept = useCallback(() => {
|
|
||||||
acceptCallback();
|
|
||||||
onClose();
|
|
||||||
}, [acceptCallback, onClose]);
|
|
||||||
|
|
||||||
const handleCancel = useCallback(() => {
|
|
||||||
cancelCallback && cancelCallback();
|
|
||||||
onClose();
|
|
||||||
}, [cancelCallback, onClose]);
|
|
||||||
|
|
||||||
return (
|
|
||||||
<InvAlertDialog
|
|
||||||
isOpen={isOpen}
|
|
||||||
leastDestructiveRef={cancelRef}
|
|
||||||
onClose={onClose}
|
|
||||||
isCentered
|
|
||||||
>
|
|
||||||
<InvAlertDialogOverlay>
|
|
||||||
<InvAlertDialogContent>
|
|
||||||
<InvAlertDialogHeader fontSize="lg" fontWeight="bold">
|
|
||||||
{title}
|
|
||||||
</InvAlertDialogHeader>
|
|
||||||
|
|
||||||
<InvAlertDialogBody>{children}</InvAlertDialogBody>
|
|
||||||
|
|
||||||
<InvAlertDialogFooter>
|
|
||||||
<InvButton ref={cancelRef} onClick={handleCancel}>
|
|
||||||
{cancelButtonText}
|
|
||||||
</InvButton>
|
|
||||||
<InvButton colorScheme="error" onClick={handleAccept} ml={3}>
|
|
||||||
{acceptButtonText}
|
|
||||||
</InvButton>
|
|
||||||
</InvAlertDialogFooter>
|
|
||||||
</InvAlertDialogContent>
|
|
||||||
</InvAlertDialogOverlay>
|
|
||||||
</InvAlertDialog>
|
|
||||||
);
|
|
||||||
}
|
|
||||||
);
|
|
||||||
|
|
||||||
InvConfirmationAlertDialog.displayName = 'InvConfirmationAlertDialog';
|
|
@ -1,16 +0,0 @@
|
|||||||
import type { AlertDialogProps } from '@chakra-ui/react';
|
|
||||||
import type { PropsWithChildren } from 'react';
|
|
||||||
|
|
||||||
export type InvConfirmationAlertDialogProps = Omit<
|
|
||||||
AlertDialogProps,
|
|
||||||
'leastDestructiveRef' | 'isOpen' | 'onClose'
|
|
||||||
> &
|
|
||||||
PropsWithChildren<{
|
|
||||||
isOpen: boolean;
|
|
||||||
onClose: () => void;
|
|
||||||
acceptButtonText?: string;
|
|
||||||
acceptCallback: () => void;
|
|
||||||
cancelButtonText?: string;
|
|
||||||
cancelCallback?: () => void;
|
|
||||||
title: string;
|
|
||||||
}>;
|
|
@ -1,52 +0,0 @@
|
|||||||
import type { Meta, StoryObj } from '@storybook/react';
|
|
||||||
import { InvMenuItem } from 'common/components/InvMenu/InvMenuItem';
|
|
||||||
import { InvMenuList } from 'common/components/InvMenu/InvMenuList';
|
|
||||||
import { InvText } from 'common/components/InvText/wrapper';
|
|
||||||
import { useCallback } from 'react';
|
|
||||||
import { FaCopy, FaDownload, FaTrash } from 'react-icons/fa6';
|
|
||||||
|
|
||||||
import { InvContextMenu } from './InvContextMenu';
|
|
||||||
|
|
||||||
const meta: Meta<typeof InvContextMenu> = {
|
|
||||||
title: 'Primitives/InvContextMenu',
|
|
||||||
tags: ['autodocs'],
|
|
||||||
component: InvContextMenu,
|
|
||||||
};
|
|
||||||
|
|
||||||
export default meta;
|
|
||||||
type Story = StoryObj<typeof InvContextMenu>;
|
|
||||||
|
|
||||||
const Component = () => {
|
|
||||||
const renderMenuFunc = useCallback(
|
|
||||||
() => (
|
|
||||||
<InvMenuList>
|
|
||||||
<InvMenuItem icon={<FaDownload />} command="⌘S">
|
|
||||||
Download
|
|
||||||
</InvMenuItem>
|
|
||||||
<InvMenuItem icon={<FaCopy />} command="⌘C">
|
|
||||||
Create a Copy
|
|
||||||
</InvMenuItem>
|
|
||||||
<InvMenuItem>Mark as Draft</InvMenuItem>
|
|
||||||
<InvMenuItem icon={<FaTrash />} isDestructive>
|
|
||||||
Delete
|
|
||||||
</InvMenuItem>
|
|
||||||
<InvMenuItem>Attend a Workshop</InvMenuItem>
|
|
||||||
</InvMenuList>
|
|
||||||
),
|
|
||||||
[]
|
|
||||||
);
|
|
||||||
|
|
||||||
return (
|
|
||||||
<InvContextMenu<HTMLParagraphElement> renderMenu={renderMenuFunc}>
|
|
||||||
{(ref) => (
|
|
||||||
<InvText ref={ref} p={5} bg="base.500">
|
|
||||||
Right-click me
|
|
||||||
</InvText>
|
|
||||||
)}
|
|
||||||
</InvContextMenu>
|
|
||||||
);
|
|
||||||
};
|
|
||||||
|
|
||||||
export const Default: Story = {
|
|
||||||
render: Component,
|
|
||||||
};
|
|
@ -1,111 +0,0 @@
|
|||||||
/**
|
|
||||||
* Adapted from https://github.com/lukasbach/chakra-ui-contextmenu
|
|
||||||
*/
|
|
||||||
import type {
|
|
||||||
ChakraProps,
|
|
||||||
MenuButtonProps,
|
|
||||||
MenuProps,
|
|
||||||
PortalProps,
|
|
||||||
} from '@chakra-ui/react';
|
|
||||||
import { Portal, useDisclosure, useEventListener } from '@chakra-ui/react';
|
|
||||||
import { InvMenu, InvMenuButton } from 'common/components/InvMenu/wrapper';
|
|
||||||
import { useGlobalMenuClose } from 'common/hooks/useGlobalMenuClose';
|
|
||||||
import { typedMemo } from 'common/util/typedMemo';
|
|
||||||
import { useCallback, useEffect, useRef, useState } from 'react';
|
|
||||||
|
|
||||||
export interface InvContextMenuProps<T extends HTMLElement = HTMLDivElement> {
|
|
||||||
renderMenu: () => JSX.Element | null;
|
|
||||||
children: (ref: React.MutableRefObject<T | null>) => JSX.Element | null;
|
|
||||||
menuProps?: Omit<MenuProps, 'children'> & { children?: React.ReactNode };
|
|
||||||
portalProps?: Omit<PortalProps, 'children'> & { children?: React.ReactNode };
|
|
||||||
menuButtonProps?: MenuButtonProps;
|
|
||||||
}
|
|
||||||
|
|
||||||
export const InvContextMenu = typedMemo(
|
|
||||||
<T extends HTMLElement = HTMLElement>(props: InvContextMenuProps<T>) => {
|
|
||||||
const { isOpen, onOpen, onClose } = useDisclosure();
|
|
||||||
const [position, setPosition] = useState([-1, -1]);
|
|
||||||
const targetRef = useRef<T>(null);
|
|
||||||
const lastPositionRef = useRef([-1, -1]);
|
|
||||||
const timeoutRef = useRef(0);
|
|
||||||
|
|
||||||
useGlobalMenuClose(onClose);
|
|
||||||
|
|
||||||
const onContextMenu = useCallback(
|
|
||||||
(e: MouseEvent) => {
|
|
||||||
if (e.shiftKey) {
|
|
||||||
onClose();
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
if (
|
|
||||||
targetRef.current?.contains(e.target as HTMLElement) ||
|
|
||||||
e.target === targetRef.current
|
|
||||||
) {
|
|
||||||
// clear pending delayed open
|
|
||||||
window.clearTimeout(timeoutRef.current);
|
|
||||||
e.preventDefault();
|
|
||||||
if (
|
|
||||||
lastPositionRef.current[0] !== e.pageX ||
|
|
||||||
lastPositionRef.current[1] !== e.pageY
|
|
||||||
) {
|
|
||||||
// if the mouse moved, we need to close, wait for animation and reopen the menu at the new position
|
|
||||||
onClose();
|
|
||||||
timeoutRef.current = window.setTimeout(() => {
|
|
||||||
onOpen();
|
|
||||||
setPosition([e.pageX, e.pageY]);
|
|
||||||
}, 100);
|
|
||||||
} else {
|
|
||||||
// else we can just open the menu at the current position
|
|
||||||
onOpen();
|
|
||||||
setPosition([e.pageX, e.pageY]);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
lastPositionRef.current = [e.pageX, e.pageY];
|
|
||||||
},
|
|
||||||
[onClose, onOpen]
|
|
||||||
);
|
|
||||||
|
|
||||||
useEffect(
|
|
||||||
() => () => {
|
|
||||||
window.clearTimeout(timeoutRef.current);
|
|
||||||
},
|
|
||||||
[]
|
|
||||||
);
|
|
||||||
|
|
||||||
useEventListener('contextmenu', onContextMenu);
|
|
||||||
|
|
||||||
return (
|
|
||||||
<>
|
|
||||||
{props.children(targetRef)}
|
|
||||||
<Portal {...props.portalProps}>
|
|
||||||
<InvMenu
|
|
||||||
isLazy
|
|
||||||
isOpen={isOpen}
|
|
||||||
gutter={0}
|
|
||||||
placement="auto-end"
|
|
||||||
onClose={onClose}
|
|
||||||
{...props.menuProps}
|
|
||||||
>
|
|
||||||
<InvMenuButton
|
|
||||||
aria-hidden={true}
|
|
||||||
w={1}
|
|
||||||
h={1}
|
|
||||||
position="absolute"
|
|
||||||
left={position[0]}
|
|
||||||
top={position[1]}
|
|
||||||
cursor="default"
|
|
||||||
bg="transparent"
|
|
||||||
size="sm"
|
|
||||||
_hover={_hover}
|
|
||||||
pointerEvents="none"
|
|
||||||
{...props.menuButtonProps}
|
|
||||||
/>
|
|
||||||
{props.renderMenu()}
|
|
||||||
</InvMenu>
|
|
||||||
</Portal>
|
|
||||||
</>
|
|
||||||
);
|
|
||||||
}
|
|
||||||
);
|
|
||||||
|
|
||||||
const _hover: ChakraProps['_hover'] = { bg: 'transparent' };
|
|
@ -1,95 +0,0 @@
|
|||||||
import type { Meta, StoryObj } from '@storybook/react';
|
|
||||||
import { InvNumberInput } from 'common/components/InvNumberInput/InvNumberInput';
|
|
||||||
import { InvSelect } from 'common/components/InvSelect/InvSelect';
|
|
||||||
import type { InvSelectOption } from 'common/components/InvSelect/types';
|
|
||||||
import { InvSlider } from 'common/components/InvSlider/InvSlider';
|
|
||||||
import { useState } from 'react';
|
|
||||||
|
|
||||||
import { InvControl } from './InvControl';
|
|
||||||
import type { InvControlProps } from './types';
|
|
||||||
|
|
||||||
const meta: Meta<typeof InvControl> = {
|
|
||||||
title: 'Primitives/InvControl',
|
|
||||||
tags: ['autodocs'],
|
|
||||||
component: InvControl,
|
|
||||||
args: {
|
|
||||||
label: 'My Control',
|
|
||||||
isDisabled: false,
|
|
||||||
isInvalid: false,
|
|
||||||
w: 96,
|
|
||||||
},
|
|
||||||
};
|
|
||||||
|
|
||||||
export default meta;
|
|
||||||
type Story = StoryObj<typeof InvControl>;
|
|
||||||
|
|
||||||
const InvControlWithSliderComponent = (props: InvControlProps) => {
|
|
||||||
const [value, setValue] = useState(0);
|
|
||||||
return (
|
|
||||||
<InvControl {...props}>
|
|
||||||
<InvSlider value={value} min={0} max={10} step={1} onChange={setValue} />
|
|
||||||
</InvControl>
|
|
||||||
);
|
|
||||||
};
|
|
||||||
|
|
||||||
const InvControlWithSliderAndHelperTextComponent = (props: InvControlProps) => {
|
|
||||||
const [value, setValue] = useState(0);
|
|
||||||
return (
|
|
||||||
<InvControl {...props} helperText="This is some helpful text">
|
|
||||||
<InvSlider value={value} min={0} max={10} step={1} onChange={setValue} />
|
|
||||||
</InvControl>
|
|
||||||
);
|
|
||||||
};
|
|
||||||
|
|
||||||
const InvControlWithNumberInputComponent = (props: InvControlProps) => {
|
|
||||||
const [value, setValue] = useState(0);
|
|
||||||
return (
|
|
||||||
<InvControl {...props}>
|
|
||||||
<InvNumberInput
|
|
||||||
value={value}
|
|
||||||
min={0}
|
|
||||||
max={10}
|
|
||||||
step={1}
|
|
||||||
onChange={setValue}
|
|
||||||
/>
|
|
||||||
</InvControl>
|
|
||||||
);
|
|
||||||
};
|
|
||||||
|
|
||||||
const options: InvSelectOption[] = [
|
|
||||||
{
|
|
||||||
value: 'chocolate',
|
|
||||||
label: 'Chocolate',
|
|
||||||
},
|
|
||||||
{
|
|
||||||
value: 'strawberry',
|
|
||||||
label: 'Strawberry',
|
|
||||||
},
|
|
||||||
{
|
|
||||||
value: 'vanilla',
|
|
||||||
label: 'Vanilla',
|
|
||||||
},
|
|
||||||
];
|
|
||||||
const InvControlWithSelectComponent = (props: InvControlProps) => {
|
|
||||||
return (
|
|
||||||
<InvControl {...props}>
|
|
||||||
<InvSelect defaultValue={options[0]} options={options} />
|
|
||||||
</InvControl>
|
|
||||||
);
|
|
||||||
};
|
|
||||||
|
|
||||||
export const InvControlWithSlider: Story = {
|
|
||||||
render: InvControlWithSliderComponent,
|
|
||||||
};
|
|
||||||
|
|
||||||
export const InvControlWithSliderAndHelperText: Story = {
|
|
||||||
render: InvControlWithSliderAndHelperTextComponent,
|
|
||||||
};
|
|
||||||
|
|
||||||
export const InvControlWithNumberInput: Story = {
|
|
||||||
render: InvControlWithNumberInputComponent,
|
|
||||||
};
|
|
||||||
|
|
||||||
export const InvControlWithSelect: Story = {
|
|
||||||
render: InvControlWithSelectComponent,
|
|
||||||
};
|
|
@ -1,72 +0,0 @@
|
|||||||
import {
|
|
||||||
Flex,
|
|
||||||
FormControl as ChakraFormControl,
|
|
||||||
FormErrorMessage as ChakraFormErrorMessage,
|
|
||||||
FormHelperText as ChakraFormHelperText,
|
|
||||||
forwardRef,
|
|
||||||
} from '@chakra-ui/react';
|
|
||||||
import { InvControlGroupContext } from 'common/components/InvControl/InvControlGroup';
|
|
||||||
import { memo, useContext, useMemo } from 'react';
|
|
||||||
|
|
||||||
import { InvLabel } from './InvLabel';
|
|
||||||
import type { InvControlProps } from './types';
|
|
||||||
|
|
||||||
export const InvControl = memo(
|
|
||||||
forwardRef<InvControlProps, typeof ChakraFormControl>(
|
|
||||||
(props: InvControlProps, ref) => {
|
|
||||||
const {
|
|
||||||
children,
|
|
||||||
helperText,
|
|
||||||
feature,
|
|
||||||
orientation: _orientation,
|
|
||||||
renderInfoPopoverInPortal = true,
|
|
||||||
isDisabled: _isDisabled,
|
|
||||||
labelProps,
|
|
||||||
label,
|
|
||||||
error,
|
|
||||||
...formControlProps
|
|
||||||
} = props;
|
|
||||||
|
|
||||||
const ctx = useContext(InvControlGroupContext);
|
|
||||||
|
|
||||||
const orientation = useMemo(
|
|
||||||
() => _orientation ?? ctx.orientation,
|
|
||||||
[_orientation, ctx.orientation]
|
|
||||||
);
|
|
||||||
|
|
||||||
const isDisabled = useMemo(
|
|
||||||
() => _isDisabled ?? ctx.isDisabled,
|
|
||||||
[_isDisabled, ctx.isDisabled]
|
|
||||||
);
|
|
||||||
|
|
||||||
return (
|
|
||||||
<ChakraFormControl
|
|
||||||
ref={ref}
|
|
||||||
orientation={orientation}
|
|
||||||
isDisabled={isDisabled}
|
|
||||||
{...formControlProps}
|
|
||||||
{...ctx.controlProps}
|
|
||||||
>
|
|
||||||
<Flex className="invcontrol-label-wrapper">
|
|
||||||
{label && (
|
|
||||||
<InvLabel
|
|
||||||
feature={feature}
|
|
||||||
renderInfoPopoverInPortal={renderInfoPopoverInPortal}
|
|
||||||
{...labelProps}
|
|
||||||
>
|
|
||||||
{label}
|
|
||||||
</InvLabel>
|
|
||||||
)}
|
|
||||||
<Flex className="invcontrol-input-wrapper">{children}</Flex>
|
|
||||||
</Flex>
|
|
||||||
{helperText && (
|
|
||||||
<ChakraFormHelperText>{helperText}</ChakraFormHelperText>
|
|
||||||
)}
|
|
||||||
{error && <ChakraFormErrorMessage>{error}</ChakraFormErrorMessage>}
|
|
||||||
</ChakraFormControl>
|
|
||||||
);
|
|
||||||
}
|
|
||||||
)
|
|
||||||
);
|
|
||||||
|
|
||||||
InvControl.displayName = 'InvControl';
|
|
@ -1,24 +0,0 @@
|
|||||||
import type { FormControlProps, FormLabelProps } from '@chakra-ui/react';
|
|
||||||
import type { PropsWithChildren } from 'react';
|
|
||||||
import { createContext, memo } from 'react';
|
|
||||||
|
|
||||||
export type InvControlGroupProps = {
|
|
||||||
labelProps?: FormLabelProps;
|
|
||||||
controlProps?: FormControlProps;
|
|
||||||
isDisabled?: boolean;
|
|
||||||
orientation?: 'horizontal' | 'vertical';
|
|
||||||
};
|
|
||||||
|
|
||||||
export const InvControlGroupContext = createContext<InvControlGroupProps>({});
|
|
||||||
|
|
||||||
export const InvControlGroup = memo(
|
|
||||||
({ children, ...context }: PropsWithChildren<InvControlGroupProps>) => {
|
|
||||||
return (
|
|
||||||
<InvControlGroupContext.Provider value={context}>
|
|
||||||
{children}
|
|
||||||
</InvControlGroupContext.Provider>
|
|
||||||
);
|
|
||||||
}
|
|
||||||
);
|
|
||||||
|
|
||||||
InvControlGroup.displayName = 'InvControlGroup';
|
|
@ -1,43 +0,0 @@
|
|||||||
import { Flex, FormLabel, forwardRef } from '@chakra-ui/react';
|
|
||||||
import { useAppSelector } from 'app/store/storeHooks';
|
|
||||||
import IAIInformationalPopover from 'common/components/IAIInformationalPopover/IAIInformationalPopover';
|
|
||||||
import { InvControlGroupContext } from 'common/components/InvControl/InvControlGroup';
|
|
||||||
import { memo, useContext } from 'react';
|
|
||||||
|
|
||||||
import type { InvLabelProps } from './types';
|
|
||||||
|
|
||||||
export const InvLabel = memo(
|
|
||||||
forwardRef<InvLabelProps, typeof FormLabel>(
|
|
||||||
(
|
|
||||||
{ feature, renderInfoPopoverInPortal, children, ...rest }: InvLabelProps,
|
|
||||||
ref
|
|
||||||
) => {
|
|
||||||
const shouldEnableInformationalPopovers = useAppSelector(
|
|
||||||
(s) => s.system.shouldEnableInformationalPopovers
|
|
||||||
);
|
|
||||||
|
|
||||||
const ctx = useContext(InvControlGroupContext);
|
|
||||||
if (feature && shouldEnableInformationalPopovers) {
|
|
||||||
return (
|
|
||||||
<IAIInformationalPopover
|
|
||||||
feature={feature}
|
|
||||||
inPortal={renderInfoPopoverInPortal}
|
|
||||||
>
|
|
||||||
<Flex as="span">
|
|
||||||
<FormLabel ref={ref} {...ctx.labelProps} {...rest}>
|
|
||||||
{children}
|
|
||||||
</FormLabel>
|
|
||||||
</Flex>
|
|
||||||
</IAIInformationalPopover>
|
|
||||||
);
|
|
||||||
}
|
|
||||||
return (
|
|
||||||
<FormLabel ref={ref} {...ctx.labelProps} {...rest}>
|
|
||||||
{children}
|
|
||||||
</FormLabel>
|
|
||||||
);
|
|
||||||
}
|
|
||||||
)
|
|
||||||
);
|
|
||||||
|
|
||||||
InvLabel.displayName = 'InvLabel';
|
|
@ -1,89 +0,0 @@
|
|||||||
import {
|
|
||||||
formAnatomy as formParts,
|
|
||||||
formErrorAnatomy as formErrorParts,
|
|
||||||
} from '@chakra-ui/anatomy';
|
|
||||||
import {
|
|
||||||
createMultiStyleConfigHelpers,
|
|
||||||
defineStyle,
|
|
||||||
defineStyleConfig,
|
|
||||||
} from '@chakra-ui/styled-system';
|
|
||||||
|
|
||||||
const {
|
|
||||||
definePartsStyle: defineFormPartsStyle,
|
|
||||||
defineMultiStyleConfig: defineFormMultiStyleConfig,
|
|
||||||
} = createMultiStyleConfigHelpers(formParts.keys);
|
|
||||||
|
|
||||||
const formBaseStyle = defineFormPartsStyle((props) => ({
|
|
||||||
container: {
|
|
||||||
flexDirection: 'column',
|
|
||||||
alignItems: 'flex-start',
|
|
||||||
gap: 4,
|
|
||||||
h: 'unset',
|
|
||||||
'> .invcontrol-label-wrapper': {
|
|
||||||
display: 'flex',
|
|
||||||
flexDirection: props.orientation === 'vertical' ? 'column' : 'row',
|
|
||||||
alignItems: props.orientation === 'vertical' ? 'flex-start' : 'center',
|
|
||||||
gap: props.orientation === 'vertical' ? 0 : 4,
|
|
||||||
minH: 8,
|
|
||||||
w: 'full',
|
|
||||||
_invalid: {
|
|
||||||
color: 'error.300',
|
|
||||||
},
|
|
||||||
'> .invcontrol-input-wrapper': {
|
|
||||||
w: 'full',
|
|
||||||
display: 'flex',
|
|
||||||
gap: 4,
|
|
||||||
justifyContent: 'flex-end',
|
|
||||||
},
|
|
||||||
},
|
|
||||||
},
|
|
||||||
helperText: {
|
|
||||||
w: 'full',
|
|
||||||
fontSize: 'sm',
|
|
||||||
color: 'base.400',
|
|
||||||
m: 0,
|
|
||||||
},
|
|
||||||
}));
|
|
||||||
|
|
||||||
export const formTheme = defineFormMultiStyleConfig({
|
|
||||||
baseStyle: formBaseStyle,
|
|
||||||
});
|
|
||||||
|
|
||||||
const formLabelBaseStyle = defineStyle(() => {
|
|
||||||
return {
|
|
||||||
fontSize: 'sm',
|
|
||||||
marginEnd: 0,
|
|
||||||
mb: 0,
|
|
||||||
flexShrink: 0,
|
|
||||||
flexGrow: 0,
|
|
||||||
fontWeight: 'semibold',
|
|
||||||
transitionProperty: 'common',
|
|
||||||
transitionDuration: 'normal',
|
|
||||||
whiteSpace: 'nowrap',
|
|
||||||
userSelect: 'none',
|
|
||||||
h: 'full',
|
|
||||||
alignItems: 'center',
|
|
||||||
_disabled: {
|
|
||||||
opacity: 0.4,
|
|
||||||
},
|
|
||||||
color: 'base.300',
|
|
||||||
_invalid: {
|
|
||||||
color: 'error.300',
|
|
||||||
},
|
|
||||||
};
|
|
||||||
});
|
|
||||||
|
|
||||||
export const formLabelTheme = defineStyleConfig({
|
|
||||||
baseStyle: formLabelBaseStyle,
|
|
||||||
});
|
|
||||||
|
|
||||||
const { defineMultiStyleConfig: defineFormErrorMultiStyleConfig } =
|
|
||||||
createMultiStyleConfigHelpers(formErrorParts.keys);
|
|
||||||
|
|
||||||
export const formErrorTheme = defineFormErrorMultiStyleConfig({
|
|
||||||
baseStyle: {
|
|
||||||
text: {
|
|
||||||
color: 'error.300',
|
|
||||||
},
|
|
||||||
},
|
|
||||||
});
|
|
@ -1,22 +0,0 @@
|
|||||||
import type {
|
|
||||||
FormControlProps as ChakraFormControlProps,
|
|
||||||
FormLabelProps as ChakraFormLabelProps,
|
|
||||||
} from '@chakra-ui/react';
|
|
||||||
import type { Feature } from 'common/components/IAIInformationalPopover/constants';
|
|
||||||
|
|
||||||
export type InvControlProps = ChakraFormControlProps & {
|
|
||||||
label?: string;
|
|
||||||
helperText?: string;
|
|
||||||
error?: string;
|
|
||||||
feature?: Feature;
|
|
||||||
renderInfoPopoverInPortal?: boolean;
|
|
||||||
labelProps?: Omit<
|
|
||||||
InvLabelProps,
|
|
||||||
'children' | 'feature' | 'renderInfoPopoverInPortal'
|
|
||||||
>;
|
|
||||||
};
|
|
||||||
|
|
||||||
export type InvLabelProps = ChakraFormLabelProps & {
|
|
||||||
feature?: Feature;
|
|
||||||
renderInfoPopoverInPortal?: boolean;
|
|
||||||
};
|
|
@ -1,26 +0,0 @@
|
|||||||
import type { Meta, StoryObj } from '@storybook/react';
|
|
||||||
|
|
||||||
import type { InvEditableProps } from './types';
|
|
||||||
import { InvEditable, InvEditableInput, InvEditablePreview } from './wrapper';
|
|
||||||
|
|
||||||
const meta: Meta<typeof InvEditable> = {
|
|
||||||
title: 'Primitives/InvEditable',
|
|
||||||
tags: ['autodocs'],
|
|
||||||
component: InvEditable,
|
|
||||||
};
|
|
||||||
|
|
||||||
export default meta;
|
|
||||||
type Story = StoryObj<typeof InvEditable>;
|
|
||||||
|
|
||||||
const Component = (props: InvEditableProps) => {
|
|
||||||
return (
|
|
||||||
<InvEditable defaultValue="Take some chakra" {...props}>
|
|
||||||
<InvEditablePreview />
|
|
||||||
<InvEditableInput />
|
|
||||||
</InvEditable>
|
|
||||||
);
|
|
||||||
};
|
|
||||||
|
|
||||||
export const Default: Story = {
|
|
||||||
render: Component,
|
|
||||||
};
|
|
@ -1,62 +0,0 @@
|
|||||||
import { editableAnatomy as parts } from '@chakra-ui/anatomy';
|
|
||||||
import {
|
|
||||||
createMultiStyleConfigHelpers,
|
|
||||||
defineStyle,
|
|
||||||
} from '@chakra-ui/styled-system';
|
|
||||||
|
|
||||||
const { definePartsStyle, defineMultiStyleConfig } =
|
|
||||||
createMultiStyleConfigHelpers(parts.keys);
|
|
||||||
|
|
||||||
const baseStylePreview = defineStyle({
|
|
||||||
fontSize: 'sm',
|
|
||||||
borderRadius: 'md',
|
|
||||||
py: '1',
|
|
||||||
transitionProperty: 'common',
|
|
||||||
transitionDuration: 'normal',
|
|
||||||
color: 'base.100',
|
|
||||||
_invalid: {
|
|
||||||
color: 'error.300',
|
|
||||||
},
|
|
||||||
});
|
|
||||||
|
|
||||||
const baseStyleInput = defineStyle(() => ({
|
|
||||||
color: 'base.100',
|
|
||||||
fontSize: 'sm',
|
|
||||||
borderRadius: 'md',
|
|
||||||
py: '1',
|
|
||||||
transitionProperty: 'common',
|
|
||||||
transitionDuration: 'normal',
|
|
||||||
width: 'full',
|
|
||||||
_focusVisible: { boxShadow: 'none' },
|
|
||||||
_placeholder: { opacity: 0.6 },
|
|
||||||
'::selection': {
|
|
||||||
color: 'blue.900',
|
|
||||||
bg: 'blue.300',
|
|
||||||
},
|
|
||||||
}));
|
|
||||||
|
|
||||||
const baseStyleTextarea = defineStyle({
|
|
||||||
borderRadius: 'md',
|
|
||||||
py: '1',
|
|
||||||
transitionProperty: 'common',
|
|
||||||
transitionDuration: 'normal',
|
|
||||||
width: 'full',
|
|
||||||
_focusVisible: { boxShadow: 'outline' },
|
|
||||||
_placeholder: { opacity: 0.6 },
|
|
||||||
});
|
|
||||||
|
|
||||||
const invokeAI = definePartsStyle(() => ({
|
|
||||||
preview: baseStylePreview,
|
|
||||||
input: baseStyleInput(),
|
|
||||||
textarea: baseStyleTextarea,
|
|
||||||
}));
|
|
||||||
|
|
||||||
export const editableTheme = defineMultiStyleConfig({
|
|
||||||
variants: {
|
|
||||||
invokeAI,
|
|
||||||
},
|
|
||||||
defaultProps: {
|
|
||||||
size: 'sm',
|
|
||||||
variant: 'invokeAI',
|
|
||||||
},
|
|
||||||
});
|
|
@ -1,6 +0,0 @@
|
|||||||
export type {
|
|
||||||
EditableInputProps as InvEditableInputProps,
|
|
||||||
EditablePreviewProps as InvEditablePreviewProps,
|
|
||||||
EditableProps as InvEditableProps,
|
|
||||||
EditableTextareaProps as InvEditableTextareaProps,
|
|
||||||
} from '@chakra-ui/react';
|
|
@ -1,6 +0,0 @@
|
|||||||
export {
|
|
||||||
Editable as InvEditable,
|
|
||||||
EditableInput as InvEditableInput,
|
|
||||||
EditablePreview as InvEditablePreview,
|
|
||||||
EditableTextarea as InvEditableTextarea,
|
|
||||||
} from '@chakra-ui/react';
|
|
@ -1,21 +0,0 @@
|
|||||||
import type { Meta, StoryObj } from '@storybook/react';
|
|
||||||
|
|
||||||
import { InvExpander } from './InvExpander';
|
|
||||||
import type { InvExpanderProps } from './types';
|
|
||||||
|
|
||||||
const meta: Meta<typeof InvExpander> = {
|
|
||||||
title: 'Primitives/InvExpander',
|
|
||||||
tags: ['autodocs'],
|
|
||||||
component: InvExpander,
|
|
||||||
};
|
|
||||||
|
|
||||||
export default meta;
|
|
||||||
type Story = StoryObj<typeof InvExpander>;
|
|
||||||
|
|
||||||
const Component = (props: InvExpanderProps) => {
|
|
||||||
return <InvExpander {...props}>Invoke</InvExpander>;
|
|
||||||
};
|
|
||||||
|
|
||||||
export const Default: Story = {
|
|
||||||
render: Component,
|
|
||||||
};
|
|
@ -1,77 +0,0 @@
|
|||||||
import { Divider, Flex } from '@chakra-ui/layout';
|
|
||||||
import type { SystemStyleObject } from '@chakra-ui/react';
|
|
||||||
import { Collapse, Icon, useDisclosure } from '@chakra-ui/react';
|
|
||||||
import { useAppDispatch } from 'app/store/storeHooks';
|
|
||||||
import type { InvExpanderProps } from 'common/components/InvExpander/types';
|
|
||||||
import { InvText } from 'common/components/InvText/wrapper';
|
|
||||||
import { expanderToggled } from 'features/parameters/store/actions';
|
|
||||||
import { t } from 'i18next';
|
|
||||||
import { useCallback } from 'react';
|
|
||||||
import { BiCollapseVertical, BiExpandVertical } from 'react-icons/bi';
|
|
||||||
|
|
||||||
const buttonStyles: SystemStyleObject = {
|
|
||||||
color: 'base.400',
|
|
||||||
borderColor: 'base.400',
|
|
||||||
transitionDuration: 'normal',
|
|
||||||
transitionProperty: 'common',
|
|
||||||
':hover, :hover *': {
|
|
||||||
transitionDuration: 'normal',
|
|
||||||
transitionProperty: 'common',
|
|
||||||
color: 'base.300',
|
|
||||||
borderColor: 'base.300',
|
|
||||||
},
|
|
||||||
};
|
|
||||||
|
|
||||||
export const InvExpander = ({
|
|
||||||
children,
|
|
||||||
label = t('common.advancedOptions'),
|
|
||||||
defaultIsOpen = false,
|
|
||||||
id,
|
|
||||||
}: InvExpanderProps) => {
|
|
||||||
const { isOpen, onToggle } = useDisclosure({ defaultIsOpen });
|
|
||||||
const dispatch = useAppDispatch();
|
|
||||||
|
|
||||||
const onToggleExpander = useCallback(() => {
|
|
||||||
if (id) {
|
|
||||||
dispatch(expanderToggled({ id, isOpen }));
|
|
||||||
}
|
|
||||||
|
|
||||||
onToggle();
|
|
||||||
}, [id, dispatch, onToggle, isOpen]);
|
|
||||||
|
|
||||||
return (
|
|
||||||
<Flex flexDir="column" w="full">
|
|
||||||
<Flex
|
|
||||||
as="button"
|
|
||||||
flexDir="row"
|
|
||||||
alignItems="center"
|
|
||||||
gap={3}
|
|
||||||
py={4}
|
|
||||||
px={2}
|
|
||||||
onClick={onToggleExpander}
|
|
||||||
sx={buttonStyles}
|
|
||||||
>
|
|
||||||
<Divider w="unset" flexGrow={1} sx={buttonStyles} />
|
|
||||||
<Flex flexDir="row" alignItems="center" gap={2}>
|
|
||||||
<Icon
|
|
||||||
as={isOpen ? BiCollapseVertical : BiExpandVertical}
|
|
||||||
fontSize="14px"
|
|
||||||
sx={buttonStyles}
|
|
||||||
/>
|
|
||||||
<InvText
|
|
||||||
variant="subtext"
|
|
||||||
fontSize="sm"
|
|
||||||
fontWeight="semibold"
|
|
||||||
flexShrink={0}
|
|
||||||
sx={buttonStyles}
|
|
||||||
>
|
|
||||||
{label}
|
|
||||||
</InvText>
|
|
||||||
</Flex>
|
|
||||||
</Flex>
|
|
||||||
<Collapse in={isOpen} animateOpacity>
|
|
||||||
{children}
|
|
||||||
</Collapse>
|
|
||||||
</Flex>
|
|
||||||
);
|
|
||||||
};
|
|
@ -1,7 +0,0 @@
|
|||||||
import type { PropsWithChildren } from 'react';
|
|
||||||
|
|
||||||
export type InvExpanderProps = PropsWithChildren<{
|
|
||||||
label?: string;
|
|
||||||
defaultIsOpen?: boolean;
|
|
||||||
id?: string;
|
|
||||||
}>;
|
|
@ -1,21 +0,0 @@
|
|||||||
import type { Meta, StoryObj } from '@storybook/react';
|
|
||||||
|
|
||||||
import type { InvHeadingProps } from './types';
|
|
||||||
import { InvHeading } from './wrapper';
|
|
||||||
|
|
||||||
const meta: Meta<typeof InvHeading> = {
|
|
||||||
title: 'Primitives/InvHeading',
|
|
||||||
tags: ['autodocs'],
|
|
||||||
component: InvHeading,
|
|
||||||
};
|
|
||||||
|
|
||||||
export default meta;
|
|
||||||
type Story = StoryObj<typeof InvHeading>;
|
|
||||||
|
|
||||||
const Component = (props: InvHeadingProps) => {
|
|
||||||
return <InvHeading {...props}>Banana sushi is delectable!</InvHeading>;
|
|
||||||
};
|
|
||||||
|
|
||||||
export const Default: Story = {
|
|
||||||
render: Component,
|
|
||||||
};
|
|
@ -1,11 +0,0 @@
|
|||||||
import { defineStyle, defineStyleConfig } from '@chakra-ui/react';
|
|
||||||
|
|
||||||
const invokeBlue = defineStyle(() => ({
|
|
||||||
color: 'invokeBlue.300',
|
|
||||||
}));
|
|
||||||
|
|
||||||
export const headingTheme = defineStyleConfig({
|
|
||||||
variants: {
|
|
||||||
invokeBlue,
|
|
||||||
},
|
|
||||||
});
|
|
@ -1 +0,0 @@
|
|||||||
export type { HeadingProps as InvHeadingProps } from '@chakra-ui/react';
|
|
@ -1 +0,0 @@
|
|||||||
export { Heading as InvHeading } from '@chakra-ui/react';
|
|
@ -1,25 +0,0 @@
|
|||||||
import type { Meta, StoryObj } from '@storybook/react';
|
|
||||||
import { FaBoltLightning } from 'react-icons/fa6';
|
|
||||||
|
|
||||||
import { InvIconButton } from './InvIconButton';
|
|
||||||
import type { InvIconButtonProps } from './types';
|
|
||||||
|
|
||||||
const meta: Meta<typeof InvIconButton> = {
|
|
||||||
title: 'Primitives/InvIconButton',
|
|
||||||
tags: ['autodocs'],
|
|
||||||
component: InvIconButton,
|
|
||||||
args: {
|
|
||||||
icon: <FaBoltLightning />,
|
|
||||||
},
|
|
||||||
};
|
|
||||||
|
|
||||||
export default meta;
|
|
||||||
type Story = StoryObj<typeof InvIconButton>;
|
|
||||||
|
|
||||||
const Component = (props: InvIconButtonProps) => {
|
|
||||||
return <InvIconButton {...props} />;
|
|
||||||
};
|
|
||||||
|
|
||||||
export const Default: Story = {
|
|
||||||
render: Component,
|
|
||||||
};
|
|
@ -1,32 +0,0 @@
|
|||||||
import { forwardRef, IconButton } from '@chakra-ui/react';
|
|
||||||
import type { InvIconButtonProps } from 'common/components/InvIconButton/types';
|
|
||||||
import { InvTooltip } from 'common/components/InvTooltip/InvTooltip';
|
|
||||||
import { memo } from 'react';
|
|
||||||
|
|
||||||
export const InvIconButton = memo(
|
|
||||||
forwardRef<InvIconButtonProps, typeof IconButton>(
|
|
||||||
({ isChecked, tooltip, ...rest }: InvIconButtonProps, ref) => {
|
|
||||||
if (tooltip) {
|
|
||||||
return (
|
|
||||||
<InvTooltip label={tooltip}>
|
|
||||||
<IconButton
|
|
||||||
ref={ref}
|
|
||||||
colorScheme={isChecked ? 'invokeBlue' : 'base'}
|
|
||||||
{...rest}
|
|
||||||
/>
|
|
||||||
</InvTooltip>
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
return (
|
|
||||||
<IconButton
|
|
||||||
ref={ref}
|
|
||||||
colorScheme={isChecked ? 'invokeBlue' : 'base'}
|
|
||||||
{...rest}
|
|
||||||
/>
|
|
||||||
);
|
|
||||||
}
|
|
||||||
)
|
|
||||||
);
|
|
||||||
|
|
||||||
InvIconButton.displayName = 'InvIconButton';
|
|
@ -1,7 +0,0 @@
|
|||||||
import type { IconButtonProps as ChakraIconButtonProps } from '@chakra-ui/react';
|
|
||||||
import type { ReactNode } from 'react';
|
|
||||||
|
|
||||||
export type InvIconButtonProps = ChakraIconButtonProps & {
|
|
||||||
isChecked?: boolean;
|
|
||||||
tooltip?: ReactNode;
|
|
||||||
};
|
|
@ -1,21 +0,0 @@
|
|||||||
import type { Meta, StoryObj } from '@storybook/react';
|
|
||||||
|
|
||||||
import { InvInput } from './InvInput';
|
|
||||||
import type { InvInputProps } from './types';
|
|
||||||
|
|
||||||
const meta: Meta<typeof InvInput> = {
|
|
||||||
title: 'Primitives/InvInput',
|
|
||||||
tags: ['autodocs'],
|
|
||||||
component: InvInput,
|
|
||||||
};
|
|
||||||
|
|
||||||
export default meta;
|
|
||||||
type Story = StoryObj<typeof InvInput>;
|
|
||||||
|
|
||||||
const Component = (props: InvInputProps) => {
|
|
||||||
return <InvInput {...props} />;
|
|
||||||
};
|
|
||||||
|
|
||||||
export const Default: Story = {
|
|
||||||
render: Component,
|
|
||||||
};
|
|
@ -1,30 +0,0 @@
|
|||||||
import { forwardRef, Input } from '@chakra-ui/react';
|
|
||||||
import { useGlobalModifiersSetters } from 'common/hooks/useGlobalModifiers';
|
|
||||||
import { stopPastePropagation } from 'common/util/stopPastePropagation';
|
|
||||||
import type { KeyboardEvent } from 'react';
|
|
||||||
import { memo, useCallback } from 'react';
|
|
||||||
|
|
||||||
import type { InvInputProps } from './types';
|
|
||||||
|
|
||||||
export const InvInput = memo(
|
|
||||||
forwardRef<InvInputProps, typeof Input>((props: InvInputProps, ref) => {
|
|
||||||
const { setShift } = useGlobalModifiersSetters();
|
|
||||||
const onKeyUpDown = useCallback(
|
|
||||||
(e: KeyboardEvent<HTMLInputElement>) => {
|
|
||||||
setShift(e.shiftKey);
|
|
||||||
},
|
|
||||||
[setShift]
|
|
||||||
);
|
|
||||||
return (
|
|
||||||
<Input
|
|
||||||
ref={ref}
|
|
||||||
onPaste={stopPastePropagation}
|
|
||||||
onKeyUp={onKeyUpDown}
|
|
||||||
onKeyDown={onKeyUpDown}
|
|
||||||
{...props}
|
|
||||||
/>
|
|
||||||
);
|
|
||||||
})
|
|
||||||
);
|
|
||||||
|
|
||||||
InvInput.displayName = 'InvInput';
|
|
@ -1,21 +0,0 @@
|
|||||||
import { inputAnatomy as parts } from '@chakra-ui/anatomy';
|
|
||||||
import { createMultiStyleConfigHelpers } from '@chakra-ui/styled-system';
|
|
||||||
import { getInputFilledStyles } from 'theme/util/getInputFilledStyles';
|
|
||||||
|
|
||||||
const { definePartsStyle, defineMultiStyleConfig } =
|
|
||||||
createMultiStyleConfigHelpers(parts.keys);
|
|
||||||
|
|
||||||
export const inputTheme = defineMultiStyleConfig({
|
|
||||||
variants: {
|
|
||||||
filled: definePartsStyle((props) => ({
|
|
||||||
field: getInputFilledStyles(props),
|
|
||||||
})),
|
|
||||||
darkFilled: definePartsStyle((props) => ({
|
|
||||||
field: getInputFilledStyles(props),
|
|
||||||
})),
|
|
||||||
},
|
|
||||||
defaultProps: {
|
|
||||||
size: 'sm',
|
|
||||||
variant: 'filled',
|
|
||||||
},
|
|
||||||
});
|
|
@ -1,3 +0,0 @@
|
|||||||
import type { InputProps as ChakraInputProps } from '@chakra-ui/react';
|
|
||||||
|
|
||||||
export type InvInputProps = ChakraInputProps;
|
|
@ -1,63 +0,0 @@
|
|||||||
import { ChevronDownIcon } from '@chakra-ui/icons';
|
|
||||||
import type { Meta, StoryObj } from '@storybook/react';
|
|
||||||
import { InvButton } from 'common/components/InvButton/InvButton';
|
|
||||||
import { FaCopy, FaDownload, FaTrash } from 'react-icons/fa6';
|
|
||||||
|
|
||||||
import { InvMenuItem } from './InvMenuItem';
|
|
||||||
import { InvMenuList } from './InvMenuList';
|
|
||||||
import type { InvMenuProps } from './types';
|
|
||||||
import { InvMenu, InvMenuButton, InvMenuGroup } from './wrapper';
|
|
||||||
|
|
||||||
const meta: Meta<typeof InvMenu> = {
|
|
||||||
title: 'Primitives/InvMenu',
|
|
||||||
tags: ['autodocs'],
|
|
||||||
component: InvMenu,
|
|
||||||
args: {
|
|
||||||
colorScheme: 'base',
|
|
||||||
},
|
|
||||||
};
|
|
||||||
|
|
||||||
export default meta;
|
|
||||||
type Story = StoryObj<typeof InvMenu>;
|
|
||||||
|
|
||||||
const Component = (props: InvMenuProps) => {
|
|
||||||
return (
|
|
||||||
<InvMenu {...props}>
|
|
||||||
<InvMenuButton as={InvButton} rightIcon={<ChevronDownIcon />}>
|
|
||||||
Actions
|
|
||||||
</InvMenuButton>
|
|
||||||
<InvMenuList>
|
|
||||||
<InvMenuGroup title="Some Category">
|
|
||||||
<InvMenuItem icon={<FaDownload />} command="⌘S">
|
|
||||||
Download
|
|
||||||
</InvMenuItem>
|
|
||||||
<InvMenuItem icon={<FaCopy />} command="⌘C">
|
|
||||||
Create a Copy
|
|
||||||
</InvMenuItem>
|
|
||||||
<InvMenuItem>Mark as Draft</InvMenuItem>
|
|
||||||
<InvMenuItem icon={<FaTrash />} isDestructive>
|
|
||||||
Delete
|
|
||||||
</InvMenuItem>
|
|
||||||
<InvMenuItem>Attend a Workshop</InvMenuItem>
|
|
||||||
</InvMenuGroup>
|
|
||||||
<InvMenuGroup title="Another Category">
|
|
||||||
<InvMenuItem icon={<FaDownload />} command="⌘S">
|
|
||||||
Download
|
|
||||||
</InvMenuItem>
|
|
||||||
<InvMenuItem icon={<FaCopy />} command="⌘C">
|
|
||||||
Create a Copy
|
|
||||||
</InvMenuItem>
|
|
||||||
<InvMenuItem>Mark as Draft</InvMenuItem>
|
|
||||||
<InvMenuItem icon={<FaTrash />} isDestructive>
|
|
||||||
Delete
|
|
||||||
</InvMenuItem>
|
|
||||||
<InvMenuItem>Attend a Workshop</InvMenuItem>
|
|
||||||
</InvMenuGroup>
|
|
||||||
</InvMenuList>
|
|
||||||
</InvMenu>
|
|
||||||
);
|
|
||||||
};
|
|
||||||
|
|
||||||
export const Default: Story = {
|
|
||||||
render: Component,
|
|
||||||
};
|
|
@ -1,31 +0,0 @@
|
|||||||
import { SpinnerIcon } from '@chakra-ui/icons';
|
|
||||||
import { forwardRef, MenuItem as ChakraMenuItem } from '@chakra-ui/react';
|
|
||||||
import { memo } from 'react';
|
|
||||||
import { spinAnimation } from 'theme/animations';
|
|
||||||
|
|
||||||
import type { InvMenuItemProps } from './types';
|
|
||||||
|
|
||||||
export const InvMenuItem = memo(
|
|
||||||
forwardRef<InvMenuItemProps, typeof ChakraMenuItem>(
|
|
||||||
(props: InvMenuItemProps, ref) => {
|
|
||||||
const {
|
|
||||||
isDestructive = false,
|
|
||||||
isLoading = false,
|
|
||||||
isDisabled,
|
|
||||||
icon,
|
|
||||||
...rest
|
|
||||||
} = props;
|
|
||||||
return (
|
|
||||||
<ChakraMenuItem
|
|
||||||
ref={ref}
|
|
||||||
icon={isLoading ? <SpinnerIcon animation={spinAnimation} /> : icon}
|
|
||||||
isDisabled={isLoading || isDisabled}
|
|
||||||
data-destructive={isDestructive}
|
|
||||||
{...rest}
|
|
||||||
/>
|
|
||||||
);
|
|
||||||
}
|
|
||||||
)
|
|
||||||
);
|
|
||||||
|
|
||||||
InvMenuItem.displayName = 'InvMenuItem';
|
|
@ -1,29 +0,0 @@
|
|||||||
import {
|
|
||||||
forwardRef,
|
|
||||||
MenuList as ChakraMenuList,
|
|
||||||
Portal,
|
|
||||||
} from '@chakra-ui/react';
|
|
||||||
import { skipMouseEvent } from 'common/util/skipMouseEvent';
|
|
||||||
import { memo } from 'react';
|
|
||||||
|
|
||||||
import { menuListMotionProps } from './constants';
|
|
||||||
import type { InvMenuListProps } from './types';
|
|
||||||
|
|
||||||
export const InvMenuList = memo(
|
|
||||||
forwardRef<InvMenuListProps, typeof ChakraMenuList>(
|
|
||||||
(props: InvMenuListProps, ref) => {
|
|
||||||
return (
|
|
||||||
<Portal>
|
|
||||||
<ChakraMenuList
|
|
||||||
ref={ref}
|
|
||||||
motionProps={menuListMotionProps}
|
|
||||||
onContextMenu={skipMouseEvent}
|
|
||||||
{...props}
|
|
||||||
/>
|
|
||||||
</Portal>
|
|
||||||
);
|
|
||||||
}
|
|
||||||
)
|
|
||||||
);
|
|
||||||
|
|
||||||
InvMenuList.displayName = 'InvMenuList';
|
|
@ -1,29 +0,0 @@
|
|||||||
import type { MotionProps } from 'framer-motion';
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Props for the animation of the MenuList.
|
|
||||||
*/
|
|
||||||
export const menuListMotionProps: MotionProps = {
|
|
||||||
variants: {
|
|
||||||
enter: {
|
|
||||||
visibility: 'visible',
|
|
||||||
opacity: 1,
|
|
||||||
scale: 1,
|
|
||||||
transition: {
|
|
||||||
duration: 0.07,
|
|
||||||
ease: [0.4, 0, 0.2, 1],
|
|
||||||
},
|
|
||||||
},
|
|
||||||
exit: {
|
|
||||||
transitionEnd: {
|
|
||||||
visibility: 'hidden',
|
|
||||||
},
|
|
||||||
opacity: 0,
|
|
||||||
scale: 0.8,
|
|
||||||
transition: {
|
|
||||||
duration: 0.07,
|
|
||||||
easings: 'easeOut',
|
|
||||||
},
|
|
||||||
},
|
|
||||||
},
|
|
||||||
};
|
|
@ -1,86 +0,0 @@
|
|||||||
import { menuAnatomy } from '@chakra-ui/anatomy';
|
|
||||||
import { createMultiStyleConfigHelpers } from '@chakra-ui/react';
|
|
||||||
|
|
||||||
const { definePartsStyle, defineMultiStyleConfig } =
|
|
||||||
createMultiStyleConfigHelpers(menuAnatomy.keys);
|
|
||||||
|
|
||||||
// define the base component styles
|
|
||||||
const invokeAI = definePartsStyle(() => ({
|
|
||||||
// define the part you're going to style
|
|
||||||
button: {
|
|
||||||
// this will style the MenuButton component
|
|
||||||
bg: 'base.500',
|
|
||||||
color: 'base.100',
|
|
||||||
_hover: {
|
|
||||||
bg: 'base.600',
|
|
||||||
color: 'base.50',
|
|
||||||
fontWeight: 'semibold',
|
|
||||||
},
|
|
||||||
},
|
|
||||||
list: {
|
|
||||||
zIndex: 9999,
|
|
||||||
color: 'base.150',
|
|
||||||
bg: 'base.800',
|
|
||||||
shadow: 'dark-lg',
|
|
||||||
border: 'none',
|
|
||||||
p: 2,
|
|
||||||
},
|
|
||||||
item: {
|
|
||||||
// this will style the MenuItem and MenuItemOption components
|
|
||||||
borderRadius: 'sm',
|
|
||||||
fontSize: 'sm',
|
|
||||||
bg: 'base.800',
|
|
||||||
_hover: {
|
|
||||||
bg: 'base.700',
|
|
||||||
svg: {
|
|
||||||
opacity: 1,
|
|
||||||
},
|
|
||||||
},
|
|
||||||
_focus: {
|
|
||||||
bg: 'base.700',
|
|
||||||
},
|
|
||||||
svg: {
|
|
||||||
opacity: 0.7,
|
|
||||||
fontSize: 14,
|
|
||||||
},
|
|
||||||
"&[data-destructive='true']": {
|
|
||||||
color: 'error.300',
|
|
||||||
fill: 'error.300',
|
|
||||||
_hover: {
|
|
||||||
bg: 'error.600',
|
|
||||||
color: 'base.50',
|
|
||||||
fill: 'base.50',
|
|
||||||
},
|
|
||||||
},
|
|
||||||
"&[aria-selected='true']": {
|
|
||||||
fontWeight: 'semibold',
|
|
||||||
bg: 'blue.300 !important',
|
|
||||||
color: 'base.800 !important',
|
|
||||||
_hover: {
|
|
||||||
color: 'base.900 !important',
|
|
||||||
bg: 'blue.400 !important',
|
|
||||||
},
|
|
||||||
},
|
|
||||||
"&[aria-selected='true'] [data-option-desc='true']": {
|
|
||||||
color: 'base.800',
|
|
||||||
},
|
|
||||||
},
|
|
||||||
divider: {
|
|
||||||
borderColor: 'base.700',
|
|
||||||
},
|
|
||||||
groupTitle: {
|
|
||||||
m: 0,
|
|
||||||
px: 3,
|
|
||||||
py: 2,
|
|
||||||
color: 'base.500',
|
|
||||||
},
|
|
||||||
}));
|
|
||||||
|
|
||||||
export const menuTheme = defineMultiStyleConfig({
|
|
||||||
variants: {
|
|
||||||
invokeAI,
|
|
||||||
},
|
|
||||||
defaultProps: {
|
|
||||||
variant: 'invokeAI',
|
|
||||||
},
|
|
||||||
});
|
|
@ -1,22 +0,0 @@
|
|||||||
import type {
|
|
||||||
MenuButtonProps as ChakraMenuButtonProps,
|
|
||||||
MenuDividerProps as ChakraMenuDividerProps,
|
|
||||||
MenuGroupProps as ChakraMenuGroupProps,
|
|
||||||
MenuItemOptionProps as ChakraMenuItemOptionProps,
|
|
||||||
MenuItemProps as ChakraMenuItemProps,
|
|
||||||
MenuListProps as ChakraMenuListProps,
|
|
||||||
MenuOptionGroupProps as ChakraMenuOptionGroupProps,
|
|
||||||
MenuProps as ChakraMenuProps,
|
|
||||||
} from '@chakra-ui/react';
|
|
||||||
|
|
||||||
export type InvMenuProps = ChakraMenuProps;
|
|
||||||
export type InvMenuButtonProps = ChakraMenuButtonProps;
|
|
||||||
export type InvMenuListProps = ChakraMenuListProps;
|
|
||||||
export type InvMenuItemProps = ChakraMenuItemProps & {
|
|
||||||
isDestructive?: boolean;
|
|
||||||
isLoading?: boolean;
|
|
||||||
};
|
|
||||||
export type InvMenuItemOptionProps = ChakraMenuItemOptionProps;
|
|
||||||
export type InvMenuGroupProps = ChakraMenuGroupProps;
|
|
||||||
export type InvMenuOptionGroupProps = ChakraMenuOptionGroupProps;
|
|
||||||
export type InvMenuDividerProps = ChakraMenuDividerProps;
|
|
@ -1,8 +0,0 @@
|
|||||||
export {
|
|
||||||
Menu as InvMenu,
|
|
||||||
MenuButton as InvMenuButton,
|
|
||||||
MenuDivider as InvMenuDivider,
|
|
||||||
MenuGroup as InvMenuGroup,
|
|
||||||
MenuItemOption as InvMenuItemOption,
|
|
||||||
MenuOptionGroup as InvMenuOptionGroup,
|
|
||||||
} from '@chakra-ui/react';
|
|
@ -1,61 +0,0 @@
|
|||||||
import { useDisclosure } from '@chakra-ui/react';
|
|
||||||
import type { Meta, StoryObj } from '@storybook/react';
|
|
||||||
import { InvButton } from 'common/components/InvButton/InvButton';
|
|
||||||
|
|
||||||
import {
|
|
||||||
InvModal,
|
|
||||||
InvModalBody,
|
|
||||||
InvModalCloseButton,
|
|
||||||
InvModalContent,
|
|
||||||
InvModalFooter,
|
|
||||||
InvModalHeader,
|
|
||||||
InvModalOverlay,
|
|
||||||
} from './wrapper';
|
|
||||||
|
|
||||||
const meta: Meta<typeof InvModal> = {
|
|
||||||
title: 'Primitives/InvModal',
|
|
||||||
tags: ['autodocs'],
|
|
||||||
component: InvModal,
|
|
||||||
args: {
|
|
||||||
colorScheme: 'base',
|
|
||||||
},
|
|
||||||
};
|
|
||||||
|
|
||||||
export default meta;
|
|
||||||
type Story = StoryObj<typeof InvModal>;
|
|
||||||
|
|
||||||
const Component = () => {
|
|
||||||
const { isOpen, onOpen, onClose } = useDisclosure();
|
|
||||||
return (
|
|
||||||
<>
|
|
||||||
<InvButton onClick={onOpen}>Open Modal</InvButton>
|
|
||||||
|
|
||||||
<InvModal isOpen={isOpen} onClose={onClose}>
|
|
||||||
<InvModalOverlay />
|
|
||||||
<InvModalContent>
|
|
||||||
<InvModalHeader>Modal Title</InvModalHeader>
|
|
||||||
<InvModalCloseButton />
|
|
||||||
<InvModalBody>
|
|
||||||
Slices of banana are caramelized with brown sugar and butter, then
|
|
||||||
rolled in sushi rice and topped with a drizzle of caramel sauce.
|
|
||||||
This variety offers a sweet and rich flavor, combining the
|
|
||||||
creaminess of banana with the indulgent taste of caramel.
|
|
||||||
</InvModalBody>
|
|
||||||
|
|
||||||
<InvModalFooter>
|
|
||||||
<InvButton colorScheme="base" mr={3} onClick={onClose}>
|
|
||||||
Close
|
|
||||||
</InvButton>
|
|
||||||
<InvButton colorScheme="green" variant="ghost">
|
|
||||||
Secondary Action
|
|
||||||
</InvButton>
|
|
||||||
</InvModalFooter>
|
|
||||||
</InvModalContent>
|
|
||||||
</InvModal>
|
|
||||||
</>
|
|
||||||
);
|
|
||||||
};
|
|
||||||
|
|
||||||
export const Default: Story = {
|
|
||||||
render: Component,
|
|
||||||
};
|
|
@ -1,33 +0,0 @@
|
|||||||
import { modalAnatomy as parts } from '@chakra-ui/anatomy';
|
|
||||||
import { createMultiStyleConfigHelpers } from '@chakra-ui/styled-system';
|
|
||||||
|
|
||||||
const { defineMultiStyleConfig, definePartsStyle } =
|
|
||||||
createMultiStyleConfigHelpers(parts.keys);
|
|
||||||
|
|
||||||
export const baseStyle = definePartsStyle(() => ({
|
|
||||||
overlay: {
|
|
||||||
bg: 'blackAlpha.700',
|
|
||||||
},
|
|
||||||
dialogContainer: {},
|
|
||||||
dialog: {
|
|
||||||
maxH: '80vh',
|
|
||||||
bg: 'base.800',
|
|
||||||
},
|
|
||||||
header: {
|
|
||||||
fontWeight: 'semibold',
|
|
||||||
fontSize: 'lg',
|
|
||||||
color: 'base.300',
|
|
||||||
},
|
|
||||||
closeButton: {
|
|
||||||
opacity: 0.5,
|
|
||||||
},
|
|
||||||
body: {
|
|
||||||
overflowY: 'scroll',
|
|
||||||
},
|
|
||||||
footer: {},
|
|
||||||
}));
|
|
||||||
|
|
||||||
export const modalTheme = defineMultiStyleConfig({
|
|
||||||
baseStyle,
|
|
||||||
defaultProps: { size: 'lg' },
|
|
||||||
});
|
|
@ -1,9 +0,0 @@
|
|||||||
export type {
|
|
||||||
ModalBody as InvModalBodyProps,
|
|
||||||
ModalCloseButton as InvModalCloseButtonProps,
|
|
||||||
ModalContent as InvModalContentProps,
|
|
||||||
ModalFooter as InvModalFooterProps,
|
|
||||||
ModalHeader as InvModalHeaderProps,
|
|
||||||
ModalOverlay as InvModalOverlayProps,
|
|
||||||
Modal as InvModalProps,
|
|
||||||
} from '@chakra-ui/react';
|
|
@ -1,9 +0,0 @@
|
|||||||
export {
|
|
||||||
Modal as InvModal,
|
|
||||||
ModalBody as InvModalBody,
|
|
||||||
ModalCloseButton as InvModalCloseButton,
|
|
||||||
ModalContent as InvModalContent,
|
|
||||||
ModalFooter as InvModalFooter,
|
|
||||||
ModalHeader as InvModalHeader,
|
|
||||||
ModalOverlay as InvModalOverlay,
|
|
||||||
} from '@chakra-ui/react';
|
|
@ -1,33 +0,0 @@
|
|||||||
import type { Meta, StoryObj } from '@storybook/react';
|
|
||||||
import { useState } from 'react';
|
|
||||||
|
|
||||||
import { InvNumberInput } from './InvNumberInput';
|
|
||||||
import type { InvNumberInputProps } from './types';
|
|
||||||
|
|
||||||
const meta: Meta<typeof InvNumberInput> = {
|
|
||||||
title: 'Primitives/InvNumberInput',
|
|
||||||
tags: ['autodocs'],
|
|
||||||
component: InvNumberInput,
|
|
||||||
args: {
|
|
||||||
min: -10,
|
|
||||||
max: 10,
|
|
||||||
step: 1,
|
|
||||||
},
|
|
||||||
};
|
|
||||||
|
|
||||||
export default meta;
|
|
||||||
type Story = StoryObj<typeof InvNumberInput>;
|
|
||||||
|
|
||||||
const Component = (props: InvNumberInputProps) => {
|
|
||||||
const [value, setValue] = useState(0);
|
|
||||||
return <InvNumberInput {...props} value={value} onChange={setValue} />;
|
|
||||||
};
|
|
||||||
|
|
||||||
export const Default: Story = {
|
|
||||||
render: Component,
|
|
||||||
args: { fineStep: 0.1 },
|
|
||||||
};
|
|
||||||
|
|
||||||
export const Integer: Story = {
|
|
||||||
render: Component,
|
|
||||||
};
|
|
@ -1,135 +0,0 @@
|
|||||||
import { forwardRef, NumberInput as ChakraNumberInput } from '@chakra-ui/react';
|
|
||||||
import { useStore } from '@nanostores/react';
|
|
||||||
import { $shift } from 'common/hooks/useGlobalModifiers';
|
|
||||||
import { roundToMultiple } from 'common/util/roundDownToMultiple';
|
|
||||||
import { stopPastePropagation } from 'common/util/stopPastePropagation';
|
|
||||||
import { clamp } from 'lodash-es';
|
|
||||||
import type { FocusEventHandler } from 'react';
|
|
||||||
import { memo, useCallback, useEffect, useMemo, useState } from 'react';
|
|
||||||
|
|
||||||
import { InvNumberInputField } from './InvNumberInputField';
|
|
||||||
import { InvNumberInputStepper } from './InvNumberInputStepper';
|
|
||||||
import type { InvNumberInputProps } from './types';
|
|
||||||
|
|
||||||
const isValidCharacter = (char: string) => /^[0-9\-.]$/i.test(char);
|
|
||||||
|
|
||||||
export const InvNumberInput = memo(
|
|
||||||
forwardRef<InvNumberInputProps, typeof ChakraNumberInput>(
|
|
||||||
(props: InvNumberInputProps, ref) => {
|
|
||||||
const {
|
|
||||||
value,
|
|
||||||
min = 0,
|
|
||||||
max,
|
|
||||||
step: _step = 1,
|
|
||||||
fineStep: _fineStep,
|
|
||||||
onChange: _onChange,
|
|
||||||
numberInputFieldProps,
|
|
||||||
defaultValue,
|
|
||||||
...rest
|
|
||||||
} = props;
|
|
||||||
|
|
||||||
const [valueAsString, setValueAsString] = useState<string>(String(value));
|
|
||||||
const [valueAsNumber, setValueAsNumber] = useState<number>(value);
|
|
||||||
const shift = useStore($shift);
|
|
||||||
const step = useMemo(
|
|
||||||
() => (shift ? _fineStep ?? _step : _step),
|
|
||||||
[shift, _fineStep, _step]
|
|
||||||
);
|
|
||||||
const isInteger = useMemo(
|
|
||||||
() => Number.isInteger(_step) && Number.isInteger(_fineStep ?? 1),
|
|
||||||
[_step, _fineStep]
|
|
||||||
);
|
|
||||||
|
|
||||||
const inputMode = useMemo(
|
|
||||||
() => (isInteger ? 'numeric' : 'decimal'),
|
|
||||||
[isInteger]
|
|
||||||
);
|
|
||||||
|
|
||||||
const precision = useMemo(() => (isInteger ? 0 : 3), [isInteger]);
|
|
||||||
|
|
||||||
const onChange = useCallback(
|
|
||||||
(valueAsString: string, valueAsNumber: number) => {
|
|
||||||
setValueAsString(valueAsString);
|
|
||||||
if (isNaN(valueAsNumber)) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
setValueAsNumber(valueAsNumber);
|
|
||||||
_onChange(valueAsNumber);
|
|
||||||
},
|
|
||||||
[_onChange]
|
|
||||||
);
|
|
||||||
|
|
||||||
// This appears to be unnecessary? Cannot figure out what it did but leaving it here in case
|
|
||||||
// it was important.
|
|
||||||
// const onClickStepper = useCallback(
|
|
||||||
// () => _onChange(Number(valueAsString)),
|
|
||||||
// [_onChange, valueAsString]
|
|
||||||
// );
|
|
||||||
|
|
||||||
const onBlur: FocusEventHandler<HTMLInputElement> = useCallback(
|
|
||||||
(e) => {
|
|
||||||
if (!e.target.value) {
|
|
||||||
// If the input is empty, we set it to the minimum value
|
|
||||||
onChange(String(defaultValue ?? min), Number(defaultValue) ?? min);
|
|
||||||
} else {
|
|
||||||
// Otherwise, we round the value to the nearest multiple if integer, else 3 decimals
|
|
||||||
const roundedValue = isInteger
|
|
||||||
? roundToMultiple(valueAsNumber, _fineStep ?? _step)
|
|
||||||
: Number(valueAsNumber.toFixed(precision));
|
|
||||||
// Clamp to min/max
|
|
||||||
const clampedValue = clamp(roundedValue, min, max);
|
|
||||||
onChange(String(clampedValue), clampedValue);
|
|
||||||
}
|
|
||||||
},
|
|
||||||
[
|
|
||||||
_fineStep,
|
|
||||||
_step,
|
|
||||||
defaultValue,
|
|
||||||
isInteger,
|
|
||||||
max,
|
|
||||||
min,
|
|
||||||
onChange,
|
|
||||||
precision,
|
|
||||||
valueAsNumber,
|
|
||||||
]
|
|
||||||
);
|
|
||||||
|
|
||||||
/**
|
|
||||||
* When `value` changes (e.g. from a diff source than this component), we need
|
|
||||||
* to update the internal `valueAsString`, but only if the actual value is different
|
|
||||||
* from the current value.
|
|
||||||
*/
|
|
||||||
useEffect(() => {
|
|
||||||
if (value !== valueAsNumber) {
|
|
||||||
setValueAsString(String(value));
|
|
||||||
setValueAsNumber(value);
|
|
||||||
}
|
|
||||||
}, [value, valueAsNumber]);
|
|
||||||
|
|
||||||
return (
|
|
||||||
<ChakraNumberInput
|
|
||||||
ref={ref}
|
|
||||||
value={valueAsString}
|
|
||||||
defaultValue={defaultValue}
|
|
||||||
min={min}
|
|
||||||
max={max}
|
|
||||||
step={step}
|
|
||||||
onChange={onChange}
|
|
||||||
clampValueOnBlur={false}
|
|
||||||
isValidCharacter={isValidCharacter}
|
|
||||||
focusInputOnChange={false}
|
|
||||||
onPaste={stopPastePropagation}
|
|
||||||
inputMode={inputMode}
|
|
||||||
precision={precision}
|
|
||||||
variant="filled"
|
|
||||||
{...rest}
|
|
||||||
>
|
|
||||||
<InvNumberInputField onBlur={onBlur} {...numberInputFieldProps} />
|
|
||||||
<InvNumberInputStepper />
|
|
||||||
</ChakraNumberInput>
|
|
||||||
);
|
|
||||||
}
|
|
||||||
)
|
|
||||||
);
|
|
||||||
|
|
||||||
InvNumberInput.displayName = 'InvNumberInput';
|
|
@ -1,34 +0,0 @@
|
|||||||
import { NumberInputField as ChakraNumberInputField } from '@chakra-ui/react';
|
|
||||||
import { useGlobalModifiersSetters } from 'common/hooks/useGlobalModifiers';
|
|
||||||
import type { KeyboardEventHandler } from 'react';
|
|
||||||
import { memo, useCallback } from 'react';
|
|
||||||
|
|
||||||
import type { InvNumberInputFieldProps } from './types';
|
|
||||||
|
|
||||||
export const InvNumberInputField = memo((props: InvNumberInputFieldProps) => {
|
|
||||||
const { onKeyUp, onKeyDown, children, ...rest } = props;
|
|
||||||
const { setShift } = useGlobalModifiersSetters();
|
|
||||||
|
|
||||||
const _onKeyUp: KeyboardEventHandler<HTMLInputElement> = useCallback(
|
|
||||||
(e) => {
|
|
||||||
onKeyUp?.(e);
|
|
||||||
setShift(e.key === 'Shift');
|
|
||||||
},
|
|
||||||
[onKeyUp, setShift]
|
|
||||||
);
|
|
||||||
const _onKeyDown: KeyboardEventHandler<HTMLInputElement> = useCallback(
|
|
||||||
(e) => {
|
|
||||||
onKeyDown?.(e);
|
|
||||||
setShift(e.key === 'Shift');
|
|
||||||
},
|
|
||||||
[onKeyDown, setShift]
|
|
||||||
);
|
|
||||||
|
|
||||||
return (
|
|
||||||
<ChakraNumberInputField onKeyUp={_onKeyUp} onKeyDown={_onKeyDown} {...rest}>
|
|
||||||
{children}
|
|
||||||
</ChakraNumberInputField>
|
|
||||||
);
|
|
||||||
});
|
|
||||||
|
|
||||||
InvNumberInputField.displayName = 'InvNumberInputField';
|
|
@ -1,29 +0,0 @@
|
|||||||
import { ChevronDownIcon, ChevronUpIcon } from '@chakra-ui/icons';
|
|
||||||
import {
|
|
||||||
forwardRef,
|
|
||||||
NumberDecrementStepper as ChakraNumberDecrementStepper,
|
|
||||||
NumberIncrementStepper as ChakraNumberIncrementStepper,
|
|
||||||
NumberInputStepper as ChakraNumberInputStepper,
|
|
||||||
} from '@chakra-ui/react';
|
|
||||||
import { memo } from 'react';
|
|
||||||
|
|
||||||
import type { InvNumberInputStepperProps } from './types';
|
|
||||||
|
|
||||||
export const InvNumberInputStepper = memo(
|
|
||||||
forwardRef<InvNumberInputStepperProps, typeof ChakraNumberInputStepper>(
|
|
||||||
(props: InvNumberInputStepperProps, ref) => {
|
|
||||||
return (
|
|
||||||
<ChakraNumberInputStepper ref={ref} {...props}>
|
|
||||||
<ChakraNumberIncrementStepper>
|
|
||||||
<ChevronUpIcon />
|
|
||||||
</ChakraNumberIncrementStepper>
|
|
||||||
<ChakraNumberDecrementStepper>
|
|
||||||
<ChevronDownIcon />
|
|
||||||
</ChakraNumberDecrementStepper>
|
|
||||||
</ChakraNumberInputStepper>
|
|
||||||
);
|
|
||||||
}
|
|
||||||
)
|
|
||||||
);
|
|
||||||
|
|
||||||
InvNumberInputStepper.displayName = 'InvNumberInputStepper';
|
|
@ -1,84 +0,0 @@
|
|||||||
import { numberInputAnatomy as parts } from '@chakra-ui/anatomy';
|
|
||||||
import { createMultiStyleConfigHelpers } from '@chakra-ui/styled-system';
|
|
||||||
import { getInputFilledStyles } from 'theme/util/getInputFilledStyles';
|
|
||||||
import { getInputOutlineStyles } from 'theme/util/getInputOutlineStyles';
|
|
||||||
|
|
||||||
const { defineMultiStyleConfig, definePartsStyle } =
|
|
||||||
createMultiStyleConfigHelpers(parts.keys);
|
|
||||||
|
|
||||||
const invokeAI = definePartsStyle(() => ({
|
|
||||||
root: {
|
|
||||||
// height: 8,
|
|
||||||
},
|
|
||||||
field: {
|
|
||||||
border: 'none',
|
|
||||||
fontWeight: 'semibold',
|
|
||||||
height: 'auto',
|
|
||||||
py: 1,
|
|
||||||
ps: 2,
|
|
||||||
pe: 6,
|
|
||||||
...getInputOutlineStyles(),
|
|
||||||
},
|
|
||||||
stepperGroup: {
|
|
||||||
display: 'flex',
|
|
||||||
},
|
|
||||||
stepper: {
|
|
||||||
border: 'none',
|
|
||||||
svg: {
|
|
||||||
color: 'base.300',
|
|
||||||
width: 2.5,
|
|
||||||
height: 2.5,
|
|
||||||
_hover: {
|
|
||||||
color: 'base.100',
|
|
||||||
},
|
|
||||||
},
|
|
||||||
},
|
|
||||||
}));
|
|
||||||
|
|
||||||
const filled = definePartsStyle((props) => {
|
|
||||||
return {
|
|
||||||
root: { h: '28px' },
|
|
||||||
field: { ...getInputFilledStyles(props), pe: 6, h: 'full' },
|
|
||||||
stepperGroup: {
|
|
||||||
border: 'none',
|
|
||||||
w: 6,
|
|
||||||
},
|
|
||||||
stepper: {
|
|
||||||
color: 'base.200',
|
|
||||||
_hover: {
|
|
||||||
bg: 'base.700',
|
|
||||||
color: 'base.100',
|
|
||||||
},
|
|
||||||
_disabled: {
|
|
||||||
_hover: {
|
|
||||||
bg: 'base.800',
|
|
||||||
color: 'base.200',
|
|
||||||
},
|
|
||||||
},
|
|
||||||
_first: {
|
|
||||||
border: 'none',
|
|
||||||
margin: 0,
|
|
||||||
borderTopEndRadius: 'base',
|
|
||||||
borderBottomStartRadius: 'base',
|
|
||||||
},
|
|
||||||
_last: {
|
|
||||||
border: 'none',
|
|
||||||
margin: 0,
|
|
||||||
borderBottomEndRadius: 'base',
|
|
||||||
borderTopStartRadius: 'base',
|
|
||||||
},
|
|
||||||
},
|
|
||||||
};
|
|
||||||
});
|
|
||||||
|
|
||||||
export const numberInputTheme = defineMultiStyleConfig({
|
|
||||||
variants: {
|
|
||||||
invokeAI,
|
|
||||||
filled,
|
|
||||||
darkFilled: filled,
|
|
||||||
},
|
|
||||||
defaultProps: {
|
|
||||||
size: 'sm',
|
|
||||||
variant: 'filled',
|
|
||||||
},
|
|
||||||
});
|
|
@ -1,46 +0,0 @@
|
|||||||
import type {
|
|
||||||
NumberDecrementStepperProps as ChakraNumberDecrementStepperProps,
|
|
||||||
NumberIncrementStepperProps as ChakraNumberIncrementStepperProps,
|
|
||||||
NumberInputFieldProps as ChakraNumberInputFieldProps,
|
|
||||||
NumberInputProps as ChakraNumberInputProps,
|
|
||||||
NumberInputStepperProps as ChakraNumberInputStepperProps,
|
|
||||||
} from '@chakra-ui/react';
|
|
||||||
|
|
||||||
export type InvNumberInputFieldProps = ChakraNumberInputFieldProps;
|
|
||||||
export type InvNumberInputStepperProps = ChakraNumberInputStepperProps;
|
|
||||||
export type InvNumberIncrementStepperProps = ChakraNumberIncrementStepperProps;
|
|
||||||
export type InvNumberDecrementStepperProps = ChakraNumberDecrementStepperProps;
|
|
||||||
|
|
||||||
export type InvNumberInputProps = Omit<
|
|
||||||
ChakraNumberInputProps,
|
|
||||||
'onChange' | 'min' | 'max'
|
|
||||||
> & {
|
|
||||||
/**
|
|
||||||
* The value
|
|
||||||
*/
|
|
||||||
value: number;
|
|
||||||
/**
|
|
||||||
* The minimum value
|
|
||||||
*/
|
|
||||||
min: number;
|
|
||||||
/**
|
|
||||||
* The maximum value
|
|
||||||
*/
|
|
||||||
max: number;
|
|
||||||
/**
|
|
||||||
* The default step
|
|
||||||
*/
|
|
||||||
step?: number;
|
|
||||||
/**
|
|
||||||
* The fine step (used when shift is pressed)
|
|
||||||
*/
|
|
||||||
fineStep?: number;
|
|
||||||
/**
|
|
||||||
* The change handler
|
|
||||||
*/
|
|
||||||
onChange: (v: number) => void;
|
|
||||||
/**
|
|
||||||
* Override props for the Chakra NumberInputField component
|
|
||||||
*/
|
|
||||||
numberInputFieldProps?: InvNumberInputFieldProps;
|
|
||||||
};
|
|
@ -1,46 +0,0 @@
|
|||||||
import type { Meta, StoryObj } from '@storybook/react';
|
|
||||||
import { InvButton } from 'common/components/InvButton/InvButton';
|
|
||||||
|
|
||||||
import {
|
|
||||||
InvPopover,
|
|
||||||
InvPopoverArrow,
|
|
||||||
InvPopoverBody,
|
|
||||||
InvPopoverCloseButton,
|
|
||||||
InvPopoverContent,
|
|
||||||
InvPopoverHeader,
|
|
||||||
InvPopoverTrigger,
|
|
||||||
} from './wrapper';
|
|
||||||
|
|
||||||
const meta: Meta<typeof InvPopover> = {
|
|
||||||
title: 'Primitives/InvPopover',
|
|
||||||
tags: ['autodocs'],
|
|
||||||
component: InvPopover,
|
|
||||||
args: {
|
|
||||||
colorScheme: 'base',
|
|
||||||
},
|
|
||||||
};
|
|
||||||
|
|
||||||
export default meta;
|
|
||||||
type Story = StoryObj<typeof InvPopover>;
|
|
||||||
|
|
||||||
const Component = () => {
|
|
||||||
return (
|
|
||||||
<InvPopover>
|
|
||||||
<InvPopoverTrigger>
|
|
||||||
<InvButton>Trigger</InvButton>
|
|
||||||
</InvPopoverTrigger>
|
|
||||||
<InvPopoverContent>
|
|
||||||
<InvPopoverArrow />
|
|
||||||
<InvPopoverCloseButton />
|
|
||||||
<InvPopoverHeader>Confirmation!</InvPopoverHeader>
|
|
||||||
<InvPopoverBody>
|
|
||||||
Are you sure you want to have that milkshake?
|
|
||||||
</InvPopoverBody>
|
|
||||||
</InvPopoverContent>
|
|
||||||
</InvPopover>
|
|
||||||
);
|
|
||||||
};
|
|
||||||
|
|
||||||
export const Default: Story = {
|
|
||||||
render: Component,
|
|
||||||
};
|
|
@ -1,59 +0,0 @@
|
|||||||
import { popoverAnatomy as parts } from '@chakra-ui/anatomy';
|
|
||||||
import {
|
|
||||||
createMultiStyleConfigHelpers,
|
|
||||||
defineStyle,
|
|
||||||
} from '@chakra-ui/styled-system';
|
|
||||||
import { cssVar } from '@chakra-ui/theme-tools';
|
|
||||||
|
|
||||||
const { defineMultiStyleConfig, definePartsStyle } =
|
|
||||||
createMultiStyleConfigHelpers(parts.keys);
|
|
||||||
|
|
||||||
const $popperBg = cssVar('popper-bg');
|
|
||||||
const $arrowBg = cssVar('popper-arrow-bg');
|
|
||||||
const $arrowShadowColor = cssVar('popper-arrow-shadow-color');
|
|
||||||
|
|
||||||
const invokeAIContent = defineStyle(() => {
|
|
||||||
return {
|
|
||||||
[$arrowBg.variable]: 'colors.base.800',
|
|
||||||
[$popperBg.variable]: 'colors.base.800',
|
|
||||||
[$arrowShadowColor.variable]: 'colors.base.600',
|
|
||||||
minW: 'unset',
|
|
||||||
width: 'unset',
|
|
||||||
p: 4,
|
|
||||||
bg: 'base.800',
|
|
||||||
border: 'none',
|
|
||||||
shadow: 'dark-lg',
|
|
||||||
};
|
|
||||||
});
|
|
||||||
|
|
||||||
const informationalContent = defineStyle(() => {
|
|
||||||
return {
|
|
||||||
[$arrowBg.variable]: 'colors.base.700',
|
|
||||||
[$popperBg.variable]: 'colors.base.700',
|
|
||||||
[$arrowShadowColor.variable]: 'colors.base.400',
|
|
||||||
p: 4,
|
|
||||||
bg: 'base.700',
|
|
||||||
border: 'none',
|
|
||||||
shadow: 'dark-lg',
|
|
||||||
};
|
|
||||||
});
|
|
||||||
|
|
||||||
const invokeAI = definePartsStyle(() => ({
|
|
||||||
content: invokeAIContent(),
|
|
||||||
body: { padding: 0 },
|
|
||||||
}));
|
|
||||||
|
|
||||||
const informational = definePartsStyle(() => ({
|
|
||||||
content: informationalContent(),
|
|
||||||
body: { padding: 0 },
|
|
||||||
}));
|
|
||||||
|
|
||||||
export const popoverTheme = defineMultiStyleConfig({
|
|
||||||
variants: {
|
|
||||||
invokeAI,
|
|
||||||
informational,
|
|
||||||
},
|
|
||||||
defaultProps: {
|
|
||||||
variant: 'invokeAI',
|
|
||||||
},
|
|
||||||
});
|
|
@ -1,9 +0,0 @@
|
|||||||
export type {
|
|
||||||
PopoverArrowProps as InvPopoverArrowProps,
|
|
||||||
PopoverBodyProps as InvPopoverBodyProps,
|
|
||||||
PopoverCloseButtonProps as InvPopoverCloseButtonProps,
|
|
||||||
PopoverContentProps as InvPopoverContentProps,
|
|
||||||
PopoverFooterProps as InvPopoverFooterProps,
|
|
||||||
PopoverHeaderProps as InvPopoverHeaderProps,
|
|
||||||
PopoverProps as InvPopoverProps,
|
|
||||||
} from '@chakra-ui/react';
|
|
@ -1,11 +0,0 @@
|
|||||||
export {
|
|
||||||
Popover as InvPopover,
|
|
||||||
PopoverAnchor as InvPopoverAnchor,
|
|
||||||
PopoverArrow as InvPopoverArrow,
|
|
||||||
PopoverBody as InvPopoverBody,
|
|
||||||
PopoverCloseButton as InvPopoverCloseButton,
|
|
||||||
PopoverContent as InvPopoverContent,
|
|
||||||
PopoverFooter as InvPopoverFooter,
|
|
||||||
PopoverHeader as InvPopoverHeader,
|
|
||||||
PopoverTrigger as InvPopoverTrigger,
|
|
||||||
} from '@chakra-ui/react';
|
|
@ -1,21 +0,0 @@
|
|||||||
import type { Meta, StoryObj } from '@storybook/react';
|
|
||||||
|
|
||||||
import type { InvProgressProps } from './types';
|
|
||||||
import { InvProgress } from './wrapper';
|
|
||||||
|
|
||||||
const meta: Meta<typeof InvProgress> = {
|
|
||||||
title: 'Primitives/InvProgress',
|
|
||||||
tags: ['autodocs'],
|
|
||||||
component: InvProgress,
|
|
||||||
};
|
|
||||||
|
|
||||||
export default meta;
|
|
||||||
type Story = StoryObj<typeof InvProgress>;
|
|
||||||
|
|
||||||
const Component = (props: InvProgressProps) => {
|
|
||||||
return <InvProgress {...props}>Banana sushi is delectable!</InvProgress>;
|
|
||||||
};
|
|
||||||
|
|
||||||
export const Default: Story = {
|
|
||||||
render: Component,
|
|
||||||
};
|
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue
Block a user