diff --git a/invokeai/frontend/web/.eslintrc.js b/invokeai/frontend/web/.eslintrc.js index fe9d890a66..28177d3de1 100644 --- a/invokeai/frontend/web/.eslintrc.js +++ b/invokeai/frontend/web/.eslintrc.js @@ -28,12 +28,14 @@ module.exports = { 'i18next', 'path', 'unused-imports', + 'simple-import-sort', + 'eslint-plugin-import', ], root: true, rules: { 'path/no-relative-imports': ['error', { maxDepth: 0 }], curly: 'error', - 'i18next/no-literal-string': 2, + 'i18next/no-literal-string': 'warn', 'react/jsx-no-bind': ['error', { allowBind: true }], 'react/jsx-curly-brace-presence': [ 'error', @@ -43,6 +45,7 @@ module.exports = { 'no-var': 'error', 'brace-style': 'error', 'prefer-template': 'error', + 'import/no-duplicates': 'error', radix: 'error', 'space-before-blocks': 'error', 'import/prefer-default-export': 'off', @@ -65,7 +68,26 @@ module.exports = { allowSingleExtends: true, }, ], + '@typescript-eslint/consistent-type-imports': [ + 'error', + { + prefer: 'type-imports', + fixStyle: 'separate-type-imports', + disallowTypeAnnotations: true, + }, + ], + '@typescript-eslint/no-import-type-side-effects': 'error', + 'simple-import-sort/imports': 'error', + 'simple-import-sort/exports': 'error', }, + overrides: [ + { + files: ['*.stories.tsx'], + rules: { + 'i18next/no-literal-string': 'off', + }, + }, + ], settings: { react: { version: 'detect', diff --git a/invokeai/frontend/web/.prettierignore b/invokeai/frontend/web/.prettierignore index 253908a6a8..5317daea68 100644 --- a/invokeai/frontend/web/.prettierignore +++ b/invokeai/frontend/web/.prettierignore @@ -12,4 +12,5 @@ index.html src/services/api/schema.d.ts static/ src/theme/css/overlayscrollbars.css +src/theme_/css/overlayscrollbars.css pnpm-lock.yaml diff --git a/invokeai/frontend/web/.storybook/ReduxInit.tsx b/invokeai/frontend/web/.storybook/ReduxInit.tsx new file mode 100644 index 0000000000..36583ca121 --- /dev/null +++ b/invokeai/frontend/web/.storybook/ReduxInit.tsx @@ -0,0 +1,23 @@ +import { PropsWithChildren, useEffect } from 'react'; +import { modelChanged } from '../src/features/parameters/store/generationSlice'; +import { useAppDispatch } from '../src/app/store/storeHooks'; +import { useGlobalModifiersInit } from '../src/common/hooks/useGlobalModifiers'; +/** + * Initializes some state for storybook. Must be in a different component + * so that it is run inside the redux context. + */ +export const ReduxInit = (props: PropsWithChildren) => { + const dispatch = useAppDispatch(); + useGlobalModifiersInit(); + useEffect(() => { + dispatch( + modelChanged({ + model_name: 'test_model', + base_model: 'sd-1', + model_type: 'main', + }) + ); + }, []); + + return props.children; +}; diff --git a/invokeai/frontend/web/.storybook/main.ts b/invokeai/frontend/web/.storybook/main.ts index 73e1a3b6d8..1663839903 100644 --- a/invokeai/frontend/web/.storybook/main.ts +++ b/invokeai/frontend/web/.storybook/main.ts @@ -6,6 +6,7 @@ const config: StorybookConfig = { '@storybook/addon-links', '@storybook/addon-essentials', '@storybook/addon-interactions', + '@storybook/addon-storysource', ], framework: { name: '@storybook/react-vite', diff --git a/invokeai/frontend/web/.storybook/preview.tsx b/invokeai/frontend/web/.storybook/preview.tsx index 3f70f92d71..3d5c8d8493 100644 --- a/invokeai/frontend/web/.storybook/preview.tsx +++ b/invokeai/frontend/web/.storybook/preview.tsx @@ -1,16 +1,17 @@ import { Preview } from '@storybook/react'; import { themes } from '@storybook/theming'; import i18n from 'i18next'; -import React from 'react'; import { initReactI18next } from 'react-i18next'; import { Provider } from 'react-redux'; -import GlobalHotkeys from '../src/app/components/GlobalHotkeys'; import ThemeLocaleProvider from '../src/app/components/ThemeLocaleProvider'; +import { $baseUrl } from '../src/app/store/nanostores/baseUrl'; import { createStore } from '../src/app/store/store'; +import { Container } from '@chakra-ui/react'; // TODO: Disabled for IDE performance issues with our translation JSON // eslint-disable-next-line @typescript-eslint/ban-ts-comment // @ts-ignore import translationEN from '../public/locales/en.json'; +import { ReduxInit } from './ReduxInit'; i18n.use(initReactI18next).init({ lng: 'en', @@ -25,17 +26,21 @@ i18n.use(initReactI18next).init({ }); const store = createStore(undefined, false); +$baseUrl.set('http://localhost:9090'); const preview: Preview = { decorators: [ - (Story) => ( - - - - - - - ), + (Story) => { + return ( + + + + + + + + ); + }, ], parameters: { docs: { diff --git a/invokeai/frontend/web/.unimportedrc.json b/invokeai/frontend/web/.unimportedrc.json new file mode 100644 index 0000000000..733e958861 --- /dev/null +++ b/invokeai/frontend/web/.unimportedrc.json @@ -0,0 +1,15 @@ +{ + "entry": ["src/main.tsx"], + "extensions": [".ts", ".tsx"], + "ignorePatterns": [ + "**/node_modules/**", + "dist/**", + "public/**", + "**/*.stories.tsx", + "config/**" + ], + "ignoreUnresolved": [], + "ignoreUnimported": ["src/i18.d.ts", "vite.config.ts", "src/vite-env.d.ts"], + "respectGitignore": true, + "ignoreUnused": [] +} diff --git a/invokeai/frontend/web/config/common.ts b/invokeai/frontend/web/config/common.ts index 4470224225..fd559cabd1 100644 --- a/invokeai/frontend/web/config/common.ts +++ b/invokeai/frontend/web/config/common.ts @@ -1,6 +1,6 @@ import react from '@vitejs/plugin-react-swc'; import { visualizer } from 'rollup-plugin-visualizer'; -import { PluginOption, UserConfig } from 'vite'; +import type { PluginOption, UserConfig } from 'vite'; import eslint from 'vite-plugin-eslint'; import tsconfigPaths from 'vite-tsconfig-paths'; diff --git a/invokeai/frontend/web/config/vite.app.config.ts b/invokeai/frontend/web/config/vite.app.config.ts index 958313402a..694e37cada 100644 --- a/invokeai/frontend/web/config/vite.app.config.ts +++ b/invokeai/frontend/web/config/vite.app.config.ts @@ -1,4 +1,5 @@ -import { UserConfig } from 'vite'; +import type { UserConfig } from 'vite'; + import { commonPlugins } from './common'; export const appConfig: UserConfig = { diff --git a/invokeai/frontend/web/config/vite.package.config.ts b/invokeai/frontend/web/config/vite.package.config.ts index d605b51c67..d6895c19e2 100644 --- a/invokeai/frontend/web/config/vite.package.config.ts +++ b/invokeai/frontend/web/config/vite.package.config.ts @@ -1,7 +1,8 @@ import path from 'path'; -import { UserConfig } from 'vite'; -import dts from 'vite-plugin-dts'; +import type { UserConfig } from 'vite'; import cssInjectedByJsPlugin from 'vite-plugin-css-injected-by-js'; +import dts from 'vite-plugin-dts'; + import { commonPlugins } from './common'; export const packageConfig: UserConfig = { diff --git a/invokeai/frontend/web/package.json b/invokeai/frontend/web/package.json index df40d0646f..c4830a042f 100644 --- a/invokeai/frontend/web/package.json +++ b/invokeai/frontend/web/package.json @@ -31,13 +31,17 @@ "lint": "concurrently -g -n eslint,prettier,tsc,madge -c cyan,green,magenta,yellow \"pnpm run lint:eslint\" \"pnpm run lint:prettier\" \"pnpm run lint:tsc\" \"pnpm run lint:madge\"", "fix": "eslint --fix . && prettier --log-level warn --write .", "preinstall": "npx only-allow pnpm", - "postinstall": "patch-package && pnpm run theme", + "postinstall": "pnpm run theme", "theme": "chakra-cli tokens src/theme/theme.ts", "theme:watch": "chakra-cli tokens src/theme/theme.ts --watch", "storybook": "storybook dev -p 6006", - "build-storybook": "storybook build" + "build-storybook": "storybook build", + "unimported": "npx unimported" }, "madge": { + "excludeRegExp": [ + "^index.ts$" + ], "detectiveOptions": { "ts": { "skipTypeImports": true @@ -53,6 +57,7 @@ "@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", "@dagrejs/graphlib": "^2.1.13", @@ -61,14 +66,11 @@ "@emotion/react": "^11.11.1", "@emotion/styled": "^11.11.0", "@fontsource-variable/inter": "^5.0.16", - "@mantine/core": "^6.0.19", "@mantine/form": "^6.0.19", - "@mantine/hooks": "^6.0.19", "@nanostores/react": "^0.7.1", "@reduxjs/toolkit": "^2.0.1", "@roarr/browser-log-writer": "^1.3.0", - "@storybook/manager-api": "^7.6.4", - "@storybook/theming": "^7.6.4", + "chakra-react-select": "^4.7.6", "compare-versions": "^6.1.0", "dateformat": "^5.0.3", "framer-motion": "^10.16.15", @@ -81,7 +83,6 @@ "new-github-issue-url": "^1.0.0", "overlayscrollbars": "^2.4.5", "overlayscrollbars-react": "^0.5.3", - "patch-package": "^8.0.0", "query-string": "^8.1.0", "react": "^18.2.0", "react-colorful": "^5.6.1", @@ -94,6 +95,8 @@ "react-konva": "^18.2.10", "react-redux": "^9.0.2", "react-resizable-panels": "^0.0.55", + "react-select": "5.7.7", + "react-textarea-autosize": "^8.5.3", "react-use": "^17.4.2", "react-virtuoso": "^4.6.2", "reactflow": "^11.10.1", @@ -118,13 +121,17 @@ }, "devDependencies": { "@chakra-ui/cli": "^2.4.1", + "@storybook/addon-docs": "^7.6.4", "@storybook/addon-essentials": "^7.6.4", "@storybook/addon-interactions": "^7.6.4", "@storybook/addon-links": "^7.6.4", + "@storybook/addon-storysource": "^7.6.4", "@storybook/blocks": "^7.6.4", + "@storybook/manager-api": "^7.6.4", "@storybook/react": "^7.6.4", "@storybook/react-vite": "^7.6.4", "@storybook/test": "^7.6.4", + "@storybook/theming": "^7.6.4", "@types/dateformat": "^5.0.2", "@types/lodash-es": "^4.17.12", "@types/node": "^20.9.0", @@ -138,9 +145,11 @@ "eslint": "^8.55.0", "eslint-config-prettier": "^9.1.0", "eslint-plugin-i18next": "^6.0.3", + "eslint-plugin-import": "^2.29.1", "eslint-plugin-path": "^1.2.2", "eslint-plugin-react": "^7.33.2", "eslint-plugin-react-hooks": "^4.6.0", + "eslint-plugin-simple-import-sort": "^10.0.0", "eslint-plugin-storybook": "^0.6.15", "eslint-plugin-unused-imports": "^3.0.0", "madge": "^6.1.0", diff --git a/invokeai/frontend/web/pnpm-lock.yaml b/invokeai/frontend/web/pnpm-lock.yaml index f4aecf13b8..fb48dc5d33 100644 --- a/invokeai/frontend/web/pnpm-lock.yaml +++ b/invokeai/frontend/web/pnpm-lock.yaml @@ -20,6 +20,9 @@ dependencies: '@chakra-ui/react': specifier: ^2.8.2 version: 2.8.2(@emotion/react@11.11.1)(@emotion/styled@11.11.0)(@types/react@18.2.42)(framer-motion@10.16.15)(react-dom@18.2.0)(react@18.2.0) + '@chakra-ui/react-use-size': + specifier: ^2.1.0 + version: 2.1.0(react@18.2.0) '@chakra-ui/styled-system': specifier: ^2.9.2 version: 2.9.2 @@ -44,15 +47,9 @@ dependencies: '@fontsource-variable/inter': specifier: ^5.0.16 version: 5.0.16 - '@mantine/core': - specifier: ^6.0.19 - version: 6.0.21(@emotion/react@11.11.1)(@mantine/hooks@6.0.21)(@types/react@18.2.42)(react-dom@18.2.0)(react@18.2.0) '@mantine/form': specifier: ^6.0.19 version: 6.0.21(react@18.2.0) - '@mantine/hooks': - specifier: ^6.0.19 - version: 6.0.21(react@18.2.0) '@nanostores/react': specifier: ^0.7.1 version: 0.7.1(nanostores@0.9.5)(react@18.2.0) @@ -62,12 +59,9 @@ dependencies: '@roarr/browser-log-writer': specifier: ^1.3.0 version: 1.3.0 - '@storybook/manager-api': - specifier: ^7.6.4 - version: 7.6.4(react-dom@18.2.0)(react@18.2.0) - '@storybook/theming': - specifier: ^7.6.4 - version: 7.6.4(react-dom@18.2.0)(react@18.2.0) + chakra-react-select: + specifier: ^4.7.6 + version: 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.1)(@types/react@18.2.42)(react-dom@18.2.0)(react@18.2.0) compare-versions: specifier: ^6.1.0 version: 6.1.0 @@ -104,9 +98,6 @@ dependencies: overlayscrollbars-react: specifier: ^0.5.3 version: 0.5.3(overlayscrollbars@2.4.5)(react@18.2.0) - patch-package: - specifier: ^8.0.0 - version: 8.0.0 query-string: specifier: ^8.1.0 version: 8.1.0 @@ -143,6 +134,12 @@ dependencies: react-resizable-panels: specifier: ^0.0.55 version: 0.0.55(react-dom@18.2.0)(react@18.2.0) + react-select: + specifier: 5.7.7 + version: 5.7.7(@types/react@18.2.42)(react-dom@18.2.0)(react@18.2.0) + react-textarea-autosize: + specifier: ^8.5.3 + version: 8.5.3(@types/react@18.2.42)(react@18.2.0) react-use: specifier: ^17.4.2 version: 17.4.2(react-dom@18.2.0)(react@18.2.0) @@ -190,6 +187,9 @@ devDependencies: '@chakra-ui/cli': specifier: ^2.4.1 version: 2.4.1 + '@storybook/addon-docs': + specifier: ^7.6.4 + version: 7.6.4(@types/react-dom@18.2.17)(@types/react@18.2.42)(react-dom@18.2.0)(react@18.2.0) '@storybook/addon-essentials': specifier: ^7.6.4 version: 7.6.4(@types/react-dom@18.2.17)(@types/react@18.2.42)(react-dom@18.2.0)(react@18.2.0) @@ -199,9 +199,15 @@ devDependencies: '@storybook/addon-links': specifier: ^7.6.4 version: 7.6.4(react@18.2.0) + '@storybook/addon-storysource': + specifier: ^7.6.4 + version: 7.6.4 '@storybook/blocks': specifier: ^7.6.4 version: 7.6.4(@types/react-dom@18.2.17)(@types/react@18.2.42)(react-dom@18.2.0)(react@18.2.0) + '@storybook/manager-api': + specifier: ^7.6.4 + version: 7.6.4(react-dom@18.2.0)(react@18.2.0) '@storybook/react': specifier: ^7.6.4 version: 7.6.4(react-dom@18.2.0)(react@18.2.0)(typescript@5.3.3) @@ -211,6 +217,9 @@ devDependencies: '@storybook/test': specifier: ^7.6.4 version: 7.6.4 + '@storybook/theming': + specifier: ^7.6.4 + version: 7.6.4(react-dom@18.2.0)(react@18.2.0) '@types/dateformat': specifier: ^5.0.2 version: 5.0.2 @@ -250,6 +259,9 @@ devDependencies: eslint-plugin-i18next: specifier: ^6.0.3 version: 6.0.3 + eslint-plugin-import: + specifier: ^2.29.1 + version: 2.29.1(@typescript-eslint/parser@6.13.2)(eslint@8.55.0) eslint-plugin-path: specifier: ^1.2.2 version: 1.2.2(eslint@8.55.0) @@ -259,6 +271,9 @@ devDependencies: eslint-plugin-react-hooks: specifier: ^4.6.0 version: 4.6.0(eslint@8.55.0) + eslint-plugin-simple-import-sort: + specifier: ^10.0.0 + version: 10.0.0(eslint@8.55.0) eslint-plugin-storybook: specifier: ^0.6.15 version: 0.6.15(eslint@8.55.0)(typescript@5.3.3) @@ -597,6 +612,7 @@ packages: hasBin: true dependencies: '@babel/types': 7.23.5 + dev: true /@babel/plugin-bugfix-safari-id-destructuring-collision-in-function-expression@7.23.3(@babel/core@7.23.5): resolution: {integrity: sha512-iRkKcCqb7iGnq9+3G6rZ+Ciz5VywC4XNRHe57lKM+jOeYAoR0lVqdeeDRfh0tQcTfw/+vBhHn926FmQhLtlFLQ==} @@ -3355,17 +3371,6 @@ packages: '@floating-ui/core': 1.5.0 '@floating-ui/utils': 0.1.6 - /@floating-ui/react-dom@1.3.0(react-dom@18.2.0)(react@18.2.0): - resolution: {integrity: sha512-htwHm67Ji5E/pROEAr7f8IKFShuiCKHwUC/UY4vC3I5jiSvGFAYnSYiZO5MlGmads+QqvUkR9ANHEguGrDv72g==} - peerDependencies: - react: '>=16.8.0' - react-dom: '>=16.8.0' - dependencies: - '@floating-ui/dom': 1.5.3 - react: 18.2.0 - react-dom: 18.2.0(react@18.2.0) - dev: false - /@floating-ui/react-dom@2.0.4(react-dom@18.2.0)(react@18.2.0): resolution: {integrity: sha512-CF8k2rgKeh/49UrnIBs4BdxPUV6vize/Db1d/YbCLyp9GiVZ0BEwf5AiDSxJRCr6yOkGqTFHtmrULxkEfYZ7dQ==} peerDependencies: @@ -3377,19 +3382,6 @@ packages: react-dom: 18.2.0(react@18.2.0) dev: true - /@floating-ui/react@0.19.2(react-dom@18.2.0)(react@18.2.0): - resolution: {integrity: sha512-JyNk4A0Ezirq8FlXECvRtQOX/iBe5Ize0W/pLkrZjfHW9GUV7Xnq6zm6fyZuQzaHHqEnVizmvlA96e1/CkZv+w==} - peerDependencies: - react: '>=16.8.0' - react-dom: '>=16.8.0' - dependencies: - '@floating-ui/react-dom': 1.3.0(react-dom@18.2.0)(react@18.2.0) - aria-hidden: 1.2.3 - react: 18.2.0 - react-dom: 18.2.0(react@18.2.0) - tabbable: 6.2.0 - dev: false - /@floating-ui/utils@0.1.6: resolution: {integrity: sha512-OfX7E2oUDYxtBvsuS4e/jSn4Q9Qb6DzgeYtsAdkPZ47znpoNsMgZw0+tVijiv3uGNR6dgNlty6r9rzIzHjtd/A==} @@ -3548,27 +3540,6 @@ packages: resolution: {integrity: sha512-dfLbk+PwWvFzSxwk3n5ySL0hfBog779o8h68wK/7/APo/7cgyWp5jcXockbxdk5kFRkbeXWm4Fbi9FrdN381sA==} dev: true - /@mantine/core@6.0.21(@emotion/react@11.11.1)(@mantine/hooks@6.0.21)(@types/react@18.2.42)(react-dom@18.2.0)(react@18.2.0): - resolution: {integrity: sha512-Kx4RrRfv0I+cOCIcsq/UA2aWcYLyXgW3aluAuW870OdXnbII6qg7RW28D+r9D76SHPxWFKwIKwmcucAG08Divg==} - peerDependencies: - '@mantine/hooks': 6.0.21 - react: '>=16.8.0' - react-dom: '>=16.8.0' - dependencies: - '@floating-ui/react': 0.19.2(react-dom@18.2.0)(react@18.2.0) - '@mantine/hooks': 6.0.21(react@18.2.0) - '@mantine/styles': 6.0.21(@emotion/react@11.11.1)(react-dom@18.2.0)(react@18.2.0) - '@mantine/utils': 6.0.21(react@18.2.0) - '@radix-ui/react-scroll-area': 1.0.2(react-dom@18.2.0)(react@18.2.0) - react: 18.2.0 - react-dom: 18.2.0(react@18.2.0) - react-remove-scroll: 2.5.7(@types/react@18.2.42)(react@18.2.0) - react-textarea-autosize: 8.3.4(@types/react@18.2.42)(react@18.2.0) - transitivePeerDependencies: - - '@emotion/react' - - '@types/react' - dev: false - /@mantine/form@6.0.21(react@18.2.0): resolution: {integrity: sha512-d4tlxyZic7MSDnaPx/WliCX1sRFDkUd2nxx4MxxO2T4OSek0YDqTlSBCxeoveu60P+vrQQN5rbbsVsaOJBe4SQ==} peerDependencies: @@ -3579,36 +3550,6 @@ packages: react: 18.2.0 dev: false - /@mantine/hooks@6.0.21(react@18.2.0): - resolution: {integrity: sha512-sYwt5wai25W6VnqHbS5eamey30/HD5dNXaZuaVEAJ2i2bBv8C0cCiczygMDpAFiSYdXoSMRr/SZ2CrrPTzeNew==} - peerDependencies: - react: '>=16.8.0' - dependencies: - react: 18.2.0 - dev: false - - /@mantine/styles@6.0.21(@emotion/react@11.11.1)(react-dom@18.2.0)(react@18.2.0): - resolution: {integrity: sha512-PVtL7XHUiD/B5/kZ/QvZOZZQQOj12QcRs3Q6nPoqaoPcOX5+S7bMZLMH0iLtcGq5OODYk0uxlvuJkOZGoPj8Mg==} - peerDependencies: - '@emotion/react': '>=11.9.0' - react: '>=16.8.0' - react-dom: '>=16.8.0' - dependencies: - '@emotion/react': 11.11.1(@types/react@18.2.42)(react@18.2.0) - clsx: 1.1.1 - csstype: 3.0.9 - react: 18.2.0 - react-dom: 18.2.0(react@18.2.0) - dev: false - - /@mantine/utils@6.0.21(react@18.2.0): - resolution: {integrity: sha512-33RVDRop5jiWFao3HKd3Yp7A9mEq4HAJxJPTuYm1NkdqX6aTKOQK7wT8v8itVodBp+sb4cJK6ZVdD1UurK/txQ==} - peerDependencies: - react: '>=16.8.0' - dependencies: - react: 18.2.0 - dev: false - /@mdx-js/react@2.3.0(react@18.2.0): resolution: {integrity: sha512-zQH//gdOmuu7nt2oJR29vFhDv88oGPmVw6BggmrHeMI+xgEkp1B2dX9/bMBSYtK0dyLX/aOmesKS09g222K1/g==} peerDependencies: @@ -3713,24 +3654,12 @@ packages: resolution: {integrity: sha512-P1st0aksCrn9sGZhp8GMYwBnQsbvAWsZAX44oXNNvLHGqAOcoVxmjZiohstwQ7SqKnbR47akdNi+uleWD8+g6A==} dev: false - /@radix-ui/number@1.0.0: - resolution: {integrity: sha512-Ofwh/1HX69ZfJRiRBMTy7rgjAzHmwe4kW9C9Y99HTRUcYLUuVT0KESFj15rPjRgKJs20GPq8Bm5aEDJ8DuA3vA==} - dependencies: - '@babel/runtime': 7.23.5 - dev: false - /@radix-ui/number@1.0.1: resolution: {integrity: sha512-T5gIdVO2mmPW3NNhjNgEP3cqMXjXL9UbO0BzWcXfvdBs+BohbQxvd/K5hSVKmn9/lbTdsQVKbUcP5WLCwvUbBg==} dependencies: '@babel/runtime': 7.23.5 dev: true - /@radix-ui/primitive@1.0.0: - resolution: {integrity: sha512-3e7rn8FDMin4CgeL7Z/49smCA3rFYY3Ha2rUQ7HRWFadS5iCRw08ZgVT1LaNTCNqgvrUiyczLflrVrF0SRQtNA==} - dependencies: - '@babel/runtime': 7.23.5 - dev: false - /@radix-ui/primitive@1.0.1: resolution: {integrity: sha512-yQ8oGX2GVsEYMWGxcovu1uGWPCxV5BFfeeYxqPmuAzUyLT9qmaMXSAhXpb0WrspIeqYzdJpkh2vHModJPgRIaw==} dependencies: @@ -3782,15 +3711,6 @@ packages: react-dom: 18.2.0(react@18.2.0) dev: true - /@radix-ui/react-compose-refs@1.0.0(react@18.2.0): - resolution: {integrity: sha512-0KaSv6sx787/hK3eF53iOkiSLwAGlFMx5lotrqD2pTjB18KbybKoEIgkNZTKC60YECDQTKGTRcDBILwZVqVKvA==} - peerDependencies: - react: ^16.8 || ^17.0 || ^18.0 - dependencies: - '@babel/runtime': 7.23.5 - react: 18.2.0 - dev: false - /@radix-ui/react-compose-refs@1.0.1(@types/react@18.2.42)(react@18.2.0): resolution: {integrity: sha512-fDSBgd44FKHa1FRMU59qBMPFcl2PZE+2nmqunj+BWFyYYjnhIDWL2ItDs3rrbJDQOtzt5nIebLCQc4QRfz6LJw==} peerDependencies: @@ -3805,15 +3725,6 @@ packages: react: 18.2.0 dev: true - /@radix-ui/react-context@1.0.0(react@18.2.0): - resolution: {integrity: sha512-1pVM9RfOQ+n/N5PJK33kRSKsr1glNxomxONs5c49MliinBY6Yw2Q995qfBUUo0/Mbg05B/sGA0gkgPI7kmSHBg==} - peerDependencies: - react: ^16.8 || ^17.0 || ^18.0 - dependencies: - '@babel/runtime': 7.23.5 - react: 18.2.0 - dev: false - /@radix-ui/react-context@1.0.1(@types/react@18.2.42)(react@18.2.0): resolution: {integrity: sha512-ebbrdFoYTcuZ0v4wG5tedGnp9tzcV8awzsxYph7gXUyvnNLuTIcCk1q17JEbnVhXAKG9oX3KtchwiMIAYp9NLg==} peerDependencies: @@ -3828,15 +3739,6 @@ packages: react: 18.2.0 dev: true - /@radix-ui/react-direction@1.0.0(react@18.2.0): - resolution: {integrity: sha512-2HV05lGUgYcA6xgLQ4BKPDmtL+QbIZYH5fCOTAOOcJ5O0QbWS3i9lKaurLzliYUDhORI2Qr3pyjhJh44lKA3rQ==} - peerDependencies: - react: ^16.8 || ^17.0 || ^18.0 - dependencies: - '@babel/runtime': 7.23.5 - react: 18.2.0 - dev: false - /@radix-ui/react-direction@1.0.1(@types/react@18.2.42)(react@18.2.0): resolution: {integrity: sha512-RXcvnXgyvYvBEOhCBuddKecVkoMiI10Jcm5cTI7abJRAHYfFxeu+FBQs/DvdxSYucxR5mna0dNsL6QFlds5TMA==} peerDependencies: @@ -3979,31 +3881,6 @@ packages: react-dom: 18.2.0(react@18.2.0) dev: true - /@radix-ui/react-presence@1.0.0(react-dom@18.2.0)(react@18.2.0): - resolution: {integrity: sha512-A+6XEvN01NfVWiKu38ybawfHsBjWum42MRPnEuqPsBZ4eV7e/7K321B5VgYMPv3Xx5An6o1/l9ZuDBgmcmWK3w==} - peerDependencies: - react: ^16.8 || ^17.0 || ^18.0 - react-dom: ^16.8 || ^17.0 || ^18.0 - dependencies: - '@babel/runtime': 7.23.5 - '@radix-ui/react-compose-refs': 1.0.0(react@18.2.0) - '@radix-ui/react-use-layout-effect': 1.0.0(react@18.2.0) - react: 18.2.0 - react-dom: 18.2.0(react@18.2.0) - dev: false - - /@radix-ui/react-primitive@1.0.1(react-dom@18.2.0)(react@18.2.0): - resolution: {integrity: sha512-fHbmislWVkZaIdeF6GZxF0A/NH/3BjrGIYj+Ae6eTmTCr7EB0RQAAVEiqsXK6p3/JcRqVSBQoceZroj30Jj3XA==} - peerDependencies: - react: ^16.8 || ^17.0 || ^18.0 - react-dom: ^16.8 || ^17.0 || ^18.0 - dependencies: - '@babel/runtime': 7.23.5 - '@radix-ui/react-slot': 1.0.1(react@18.2.0) - react: 18.2.0 - react-dom: 18.2.0(react@18.2.0) - dev: false - /@radix-ui/react-primitive@1.0.3(@types/react-dom@18.2.17)(@types/react@18.2.42)(react-dom@18.2.0)(react@18.2.0): resolution: {integrity: sha512-yi58uVyoAcK/Nq1inRY56ZSjKypBNKTa/1mcL8qdl6oJeEaDbOldlzrGn7P6Q3Id5d+SYNGc5AJgc4vGhjs5+g==} peerDependencies: @@ -4054,26 +3931,6 @@ packages: react-dom: 18.2.0(react@18.2.0) dev: true - /@radix-ui/react-scroll-area@1.0.2(react-dom@18.2.0)(react@18.2.0): - resolution: {integrity: sha512-k8VseTxI26kcKJaX0HPwkvlNBPTs56JRdYzcZ/vzrNUkDlvXBy8sMc7WvCpYzZkHgb+hd72VW9MqkqecGtuNgg==} - peerDependencies: - react: ^16.8 || ^17.0 || ^18.0 - react-dom: ^16.8 || ^17.0 || ^18.0 - dependencies: - '@babel/runtime': 7.23.5 - '@radix-ui/number': 1.0.0 - '@radix-ui/primitive': 1.0.0 - '@radix-ui/react-compose-refs': 1.0.0(react@18.2.0) - '@radix-ui/react-context': 1.0.0(react@18.2.0) - '@radix-ui/react-direction': 1.0.0(react@18.2.0) - '@radix-ui/react-presence': 1.0.0(react-dom@18.2.0)(react@18.2.0) - '@radix-ui/react-primitive': 1.0.1(react-dom@18.2.0)(react@18.2.0) - '@radix-ui/react-use-callback-ref': 1.0.0(react@18.2.0) - '@radix-ui/react-use-layout-effect': 1.0.0(react@18.2.0) - react: 18.2.0 - react-dom: 18.2.0(react@18.2.0) - dev: false - /@radix-ui/react-select@1.2.2(@types/react-dom@18.2.17)(@types/react@18.2.42)(react-dom@18.2.0)(react@18.2.0): resolution: {integrity: sha512-zI7McXr8fNaSrUY9mZe4x/HC0jTLY9fWNhO1oLWYMQGDXuV4UCivIGTxwioSzO0ZCYX9iSLyWmAh/1TOmX3Cnw==} peerDependencies: @@ -4136,16 +3993,6 @@ packages: react-dom: 18.2.0(react@18.2.0) dev: true - /@radix-ui/react-slot@1.0.1(react@18.2.0): - resolution: {integrity: sha512-avutXAFL1ehGvAXtPquu0YK5oz6ctS474iM3vNGQIkswrVhdrS52e3uoMQBzZhNRAIE0jBnUyXWNmSjGHhCFcw==} - peerDependencies: - react: ^16.8 || ^17.0 || ^18.0 - dependencies: - '@babel/runtime': 7.23.5 - '@radix-ui/react-compose-refs': 1.0.0(react@18.2.0) - react: 18.2.0 - dev: false - /@radix-ui/react-slot@1.0.2(@types/react@18.2.42)(react@18.2.0): resolution: {integrity: sha512-YeTpuq4deV+6DusvVUW4ivBgnkHwECUu0BiN43L5UCDFgdhsRUWAghhTF5MbvNTPzmiFOx90asDSUjWuCNapwg==} peerDependencies: @@ -4238,15 +4085,6 @@ packages: react-dom: 18.2.0(react@18.2.0) dev: true - /@radix-ui/react-use-callback-ref@1.0.0(react@18.2.0): - resolution: {integrity: sha512-GZtyzoHz95Rhs6S63D2t/eqvdFCm7I+yHMLVQheKM7nBD8mbZIt+ct1jz4536MDnaOGKIxynJ8eHTkVGVVkoTg==} - peerDependencies: - react: ^16.8 || ^17.0 || ^18.0 - dependencies: - '@babel/runtime': 7.23.5 - react: 18.2.0 - dev: false - /@radix-ui/react-use-callback-ref@1.0.1(@types/react@18.2.42)(react@18.2.0): resolution: {integrity: sha512-D94LjX4Sp0xJFVaoQOd3OO9k7tpBYNOXdVhkltUbGv2Qb9OXdrg/CpsjlZv7ia14Sylv398LswWBVVu5nqKzAQ==} peerDependencies: @@ -4291,15 +4129,6 @@ packages: react: 18.2.0 dev: true - /@radix-ui/react-use-layout-effect@1.0.0(react@18.2.0): - resolution: {integrity: sha512-6Tpkq+R6LOlmQb1R5NNETLG0B4YP0wc+klfXafpUCj6JGyaUc8il7/kUZ7m59rGbXGczE9Bs+iz2qloqsZBduQ==} - peerDependencies: - react: ^16.8 || ^17.0 || ^18.0 - dependencies: - '@babel/runtime': 7.23.5 - react: 18.2.0 - dev: false - /@radix-ui/react-use-layout-effect@1.0.1(@types/react@18.2.42)(react@18.2.0): resolution: {integrity: sha512-v/5RegiJWYdoCvMnITBkNNx6bCj20fiaJnWtRkU18yITptraXjffz5Qbn05uOiQnOvi+dbkznkoaMltz1GnszQ==} peerDependencies: @@ -4726,6 +4555,14 @@ packages: ts-dedent: 2.2.0 dev: true + /@storybook/addon-storysource@7.6.4: + resolution: {integrity: sha512-D63IB8bkqn5ZDq4yjvkcLVfGz3OcAQUohlxSFR1e7COo8jMSTiQWjN7xaVPNOnVJRCj6GrlRlto/hqGl+F+WiQ==} + dependencies: + '@storybook/source-loader': 7.6.4 + estraverse: 5.3.0 + tiny-invariant: 1.3.1 + dev: true + /@storybook/addon-toolbars@7.6.4: resolution: {integrity: sha512-ENMQJgU4sRCLLDVXYfa+P3cQVV9PC0ZxwVAKeM3NPYPNH/ODoryGNtq+Q68LwHlM4ObCE2oc9MzaQqPxloFcCw==} dev: true @@ -4845,6 +4682,7 @@ packages: qs: 6.11.2 telejson: 7.2.0 tiny-invariant: 1.3.1 + dev: true /@storybook/cli@7.6.4: resolution: {integrity: sha512-GqvaFdkkBMJOdnrVe82XY0V3b+qFMhRNyVoTv2nqB87iMUXZHqh4Pu4LqwaJBsBpuNregvCvVOPe9LGgoOzy4A==} @@ -4902,6 +4740,7 @@ packages: resolution: {integrity: sha512-vJwMShC98tcoFruRVQ4FphmFqvAZX1FqZqjFyk6IxtFumPKTVSnXJjlU1SnUIkSK2x97rgdUMqkdI+wAv/tugQ==} dependencies: '@storybook/global': 5.0.0 + dev: true /@storybook/codemod@7.6.4: resolution: {integrity: sha512-q4rZVOfozxzbDRH/LzuFDoIGBdXs+orAm18fi6iAx8PeMHe8J/MOXKccNV1zdkm/h7mTQowuRo45KwJHw8vX+g==} @@ -4989,6 +4828,7 @@ packages: resolution: {integrity: sha512-i3xzcJ19ILSy4oJL5Dz9y0IlyApynn5RsGhAMIsW+mcfri+hGfeakq1stNCo0o7jW4Y3A7oluFTtIoK8DOxQdQ==} dependencies: ts-dedent: 2.2.0 + dev: true /@storybook/core-server@7.6.4: resolution: {integrity: sha512-mXxZMpCwOhjEPPRjqrTHdiCpFdkc47f46vlgTj02SX+9xKHxslmZ2D3JG/8O4Ab9tG+bBl6lBm3RIrIzaiCu9Q==} @@ -5076,6 +4916,7 @@ packages: resolution: {integrity: sha512-ePrvE/pS1vsKR9Xr+o+YwdqNgHUyXvg+1Xjx0h9LrVx7Zq4zNe06pd63F5EvzTbCbJsHj7GHr9tkiaqm7U8WRA==} dependencies: type-fest: 2.19.0 + dev: true /@storybook/docs-mdx@0.1.0: resolution: {integrity: sha512-JDaBR9lwVY4eSH5W8EGHrhODjygPd6QImRbwjAuJNEnY0Vw4ie3bPkeGfnacB3OBW6u/agqPv2aRlR46JcAQLg==} @@ -5098,6 +4939,7 @@ packages: /@storybook/global@5.0.0: resolution: {integrity: sha512-FcOqPAXACP0I3oJ/ws6/rrPT9WGhu915Cg8D02a9YxLo0DE9zI+a9A5gRGvmQ09fiWPukqI8ZAEoQEdWUKMQdQ==} + dev: true /@storybook/instrumenter@7.6.4: resolution: {integrity: sha512-sfEXZbCy7orP2A7dYmSrCYGPnbwJcFAa55N+YBQEYhoyJkohGC//nd5LbuPjLj23uixgB9iOw4E0fGp5w8cf+w==} @@ -5132,6 +4974,7 @@ packages: transitivePeerDependencies: - react - react-dom + dev: true /@storybook/manager@7.6.4: resolution: {integrity: sha512-Ug2ejfKgKre8h/RJbkumukwAA44TbvTPEjDcJmyFdAI+kHYhOYdKPEC2UNmVYz8/4HjwMTJQ3M7t/esK8HHY4A==} @@ -5255,6 +5098,17 @@ packages: '@storybook/client-logger': 7.6.4 memoizerific: 1.11.3 qs: 6.11.2 + dev: true + + /@storybook/source-loader@7.6.4: + resolution: {integrity: sha512-1wb/3bVpJZ/3r3qUrLK8jb0kLuvwjNi5T1kci5huREdc1TrIxZXoPw9EiyjcMCZzCURkoj7euNLrLHGyzdBTLg==} + dependencies: + '@storybook/csf': 0.1.2 + '@storybook/types': 7.6.4 + estraverse: 5.3.0 + lodash: 4.17.21 + prettier: 2.8.8 + dev: true /@storybook/telemetry@7.6.4: resolution: {integrity: sha512-Q4QpvcgloHUEqC9PGo7tgqkUH91/PjX+74/0Hi9orLo8QmLMgdYS5fweFwgSKoTwDGNg2PaHp/jqvhhw7UmnJA==} @@ -5306,6 +5160,7 @@ packages: memoizerific: 1.11.3 react: 18.2.0 react-dom: 18.2.0(react@18.2.0) + dev: true /@storybook/types@7.6.4: resolution: {integrity: sha512-qyiiXPCvol5uVgfubcIMzJBA0awAyFPU+TyUP1mkPYyiTHnsHYel/mKlSdPjc8a97N3SlJXHOCx41Hde4IyJgg==} @@ -5314,6 +5169,7 @@ packages: '@types/babel__core': 7.20.5 '@types/express': 4.17.21 file-system-cache: 2.3.0 + dev: true /@swc/core-darwin-arm64@1.3.96: resolution: {integrity: sha512-8hzgXYVd85hfPh6mJ9yrG26rhgzCmcLO0h1TIl8U31hwmTbfZLzRitFQ/kqMJNbIBCwmNH1RU2QcJnL3d7f69A==} @@ -5505,28 +5361,33 @@ packages: '@types/babel__generator': 7.6.7 '@types/babel__template': 7.4.4 '@types/babel__traverse': 7.20.4 + dev: true /@types/babel__generator@7.6.7: resolution: {integrity: sha512-6Sfsq+EaaLrw4RmdFWE9Onp63TOUue71AWb4Gpa6JxzgTYtimbM086WnYTy2U67AofR++QKCo08ZP6pwx8YFHQ==} dependencies: '@babel/types': 7.23.5 + dev: true /@types/babel__template@7.4.4: resolution: {integrity: sha512-h/NUaSyG5EyxBIp8YRxo4RMe2/qQgvyowRwVMzhYhBCONbW8PUsg4lkFMrhgZhUe5z3L3MiLDuvyJ/CaPa2A8A==} dependencies: '@babel/parser': 7.23.5 '@babel/types': 7.23.5 + dev: true /@types/babel__traverse@7.20.4: resolution: {integrity: sha512-mSM/iKUk5fDDrEV/e83qY+Cr3I1+Q3qqTuEn++HAWYjEa1+NxZr6CNrcJGf2ZTnq4HoFGC3zaTPZTobCzCFukA==} dependencies: '@babel/types': 7.23.5 + dev: true /@types/body-parser@1.19.5: resolution: {integrity: sha512-fB3Zu92ucau0iQ0JMCFQE7b/dv8Ot07NI3KaZIkIUNXq82k4eBAqUaneXfleGY9JWskeS9y+u0nXMyspcuQrCg==} dependencies: '@types/connect': 3.4.38 '@types/node': 20.10.4 + dev: true /@types/chai@4.3.11: resolution: {integrity: sha512-qQR1dr2rGIHYlJulmr8Ioq3De0Le9E4MJ5AiaeAETJJpndT1uUNHsGFK3L/UIu+rbkQSdj8J/w2bCsBZc/Y5fQ==} @@ -5536,6 +5397,7 @@ packages: resolution: {integrity: sha512-K6uROf1LD88uDQqJCktA4yzL1YYAK6NgfsI0v/mTgyPKWsX1CnJ0XPSDhViejru1GcRkLWb8RlzFYJRqGUbaug==} dependencies: '@types/node': 20.10.4 + dev: true /@types/cross-spawn@6.0.6: resolution: {integrity: sha512-fXRhhUkG4H3TQk5dBhQ7m/JDdSNHKwR2BBia62lhwEIq9xGiQKLxd6LymNhn47SjXhsUEPmxi+PKw2OkW4LLjA==} @@ -5772,6 +5634,7 @@ packages: '@types/qs': 6.9.10 '@types/range-parser': 1.2.7 '@types/send': 0.17.4 + dev: true /@types/express@4.17.21: resolution: {integrity: sha512-ejlPM315qwLpaQlQDTjPdsUFSc6ZsP4AN6AlWnogPjQ7CVi7PYF3YVz+CY3jE2pwYf7E/7HlDAN0rV2GxTG0HQ==} @@ -5780,6 +5643,7 @@ packages: '@types/express-serve-static-core': 4.17.41 '@types/qs': 6.9.10 '@types/serve-static': 1.15.5 + dev: true /@types/find-cache-dir@3.2.1: resolution: {integrity: sha512-frsJrz2t/CeGifcu/6uRo4b+SzAwT4NYCVPu1GN8IB9XTzrpPkGuV0tmh9mN+/L0PklAlsC3u5Fxt0ju00LXIw==} @@ -5804,6 +5668,7 @@ packages: /@types/http-errors@2.0.4: resolution: {integrity: sha512-D0CFMMtydbJAegzOyHjtiKPLlvnm3iTZyZRSZoLq2mRhDdmLfIWOCYPfQJ4cu2erKghU++QvjcUjp/5h7hESpA==} + dev: true /@types/istanbul-lib-coverage@2.0.6: resolution: {integrity: sha512-2QF/t/auWm0lsy8XtKVPG19v3sSOQlJe/YHZgfjb/KBBHOGSV+J2q/S671rcq9uTBrLAXmZpqJiaQbMT+zNU1w==} @@ -5858,9 +5723,11 @@ packages: /@types/mime@1.3.5: resolution: {integrity: sha512-/pyBZWSLD2n0dcHE3hq8s8ZvcETHtEuF+3E7XVt0Ig2nvsVQXdghHVcEkIWjy9A0wKfTn97a/PSDYohKIlnP/w==} + dev: true /@types/mime@3.0.4: resolution: {integrity: sha512-iJt33IQnVRkqeqC7PzBHPTC6fDlRNRW8vjrgqtScAhrmMwe8c4Eo7+fUGTa+XdWrpEgpyKWMYmi2dIwMAYRzPw==} + dev: true /@types/minimatch@5.1.2: resolution: {integrity: sha512-K0VQKziLUWkVKiRVrx4a40iPaxTUefQmjtkQofBkYRcoaaL/8rhwDWww9qWbrgicNOgnpIsMxyNIUM4+n6dUIA==} @@ -5883,6 +5750,7 @@ packages: resolution: {integrity: sha512-D08YG6rr8X90YB56tSIuBaddy/UXAA9RKJoFvrsnogAum/0pmjkgi4+2nx96A330FmioegBWmEYQ+syqCFaveg==} dependencies: undici-types: 5.26.5 + dev: true /@types/normalize-package-data@2.4.4: resolution: {integrity: sha512-37i+OaWTh9qeK4LSHPsyRC7NahnGotNuZvjLSgcPzblpHB3rrCJxAOgI5gCdKm7coonsaX1Of0ILiTcnZjbfxA==} @@ -5901,9 +5769,11 @@ packages: /@types/qs@6.9.10: resolution: {integrity: sha512-3Gnx08Ns1sEoCrWssEgTSJs/rsT2vhGP+Ja9cnnk9k4ALxinORlQneLXFeFKOTJMOeZUFD1s7w+w2AphTpvzZw==} + dev: true /@types/range-parser@1.2.7: resolution: {integrity: sha512-hKormJbkJqzQGhziax5PItDUTMAM9uE2XXQmM37dyd4hVM+5aVl7oVxMVUiVQn2oCQFN/LKCZdvSM0pFRqbSmQ==} + dev: true /@types/react-dom@18.2.17: resolution: {integrity: sha512-rvrT/M7Df5eykWFxn6MYt5Pem/Dbyc1N8Y0S9Mrkw2WFCRiqUgw9P7ul2NpwsXCSM1DVdENzdG9J5SreqfAIWg==} @@ -5916,6 +5786,12 @@ packages: '@types/react': 18.2.42 dev: false + /@types/react-transition-group@4.4.10: + resolution: {integrity: sha512-hT/+s0VQs2ojCX823m60m5f0sL5idt9SO6Tj6Dg+rdphGPIeJbJ6CxvBYkgkGKrYeDjvIpKTR38UzmtHJOGW3Q==} + dependencies: + '@types/react': 18.2.42 + dev: false + /@types/react@18.2.42: resolution: {integrity: sha512-c1zEr96MjakLYus/wPnuWDo1/zErfdU9rNsIGmE+NV71nx88FG9Ttgo5dqorXTu/LImX2f63WBP986gJkMPNbA==} dependencies: @@ -5939,6 +5815,7 @@ packages: dependencies: '@types/mime': 1.3.5 '@types/node': 20.10.4 + dev: true /@types/serve-static@1.15.5: resolution: {integrity: sha512-PDRk21MnK70hja/YF8AHfC7yIsiQHn1rcXx7ijCFBX/k+XQJhQT/gw3xekXKJvx+5SXaMMS8oqQy09Mzvz2TuQ==} @@ -5946,6 +5823,7 @@ packages: '@types/http-errors': 2.0.4 '@types/mime': 3.0.4 '@types/node': 20.10.4 + dev: true /@types/unist@2.0.10: resolution: {integrity: sha512-IfYcSBWE3hLpBg8+X2SEa8LVkJdJEkT2Ese2aaLs3ptGdVtABxndrMaxuFlQ1qdFf9Q5rDvDpxI3WwgvKFAsQA==} @@ -6364,10 +6242,6 @@ packages: tslib: 1.14.1 dev: true - /@yarnpkg/lockfile@1.1.0: - resolution: {integrity: sha512-GpSwvyXOcOOlV70vbnzjj4fW5xW/FdUF6nQEt1ENy7m4ZCczi1+/buVUPAqmGfqznsORNFzUMjctTIp8a9tuCQ==} - dev: false - /@zag-js/dom-query@0.16.0: resolution: {integrity: sha512-Oqhd6+biWyKnhKwFFuZrrf6lxBz2tX2pRQe6grUnYwO6HJ8BcbqZomy2lpOdr+3itlaUqx+Ywj5E5ZZDr/LBfQ==} dev: false @@ -6485,6 +6359,7 @@ packages: engines: {node: '>=8'} dependencies: color-convert: 2.0.1 + dev: true /ansi-styles@5.2.0: resolution: {integrity: sha512-Cxwpt2SfTzTtXcfOlzGEee8O+c+MmUgGrNiBcXnuWxuFJHe6a5Hz7qwhwe5OgaSYI0IJvkLqWX1ASG+cJOkEiA==} @@ -6566,11 +6441,33 @@ packages: is-string: 1.0.7 dev: true + /array-includes@3.1.7: + resolution: {integrity: sha512-dlcsNBIiWhPkHdOEEKnehA+RNUWDc4UqFtnIXU4uuYDPtA4LDkr7qip2p0VvFAEXNDr0yWZ9PJyIRiGjRLQzwQ==} + engines: {node: '>= 0.4'} + dependencies: + call-bind: 1.0.5 + define-properties: 1.2.0 + es-abstract: 1.22.1 + get-intrinsic: 1.2.2 + is-string: 1.0.7 + dev: true + /array-union@2.1.0: resolution: {integrity: sha512-HGyxoOTYUyCM6stUe6EJgnd4EoewAI7zMdfqO+kGjnlZmBDz/cR5pf8r/cR4Wq60sL/p0IkcjUEEPwS3GFrIyw==} engines: {node: '>=8'} dev: true + /array.prototype.findlastindex@1.2.3: + resolution: {integrity: sha512-LzLoiOMAxvy+Gd3BAq3B7VeIgPdo+Q8hthvKtXybMvRV0jrXfJM/t8mw7nNlpEcVlVUnCnM2KSX4XU5HmpodOA==} + engines: {node: '>= 0.4'} + dependencies: + call-bind: 1.0.5 + define-properties: 1.2.0 + es-abstract: 1.22.1 + es-shim-unscopables: 1.0.0 + get-intrinsic: 1.2.2 + dev: true + /array.prototype.flat@1.3.1: resolution: {integrity: sha512-roTU0KWIOmJ4DRLmwKd19Otg0/mT3qPNt0Qb3GWW8iObuZXxrjB/pzn0R3hqpRSWg4HCwqx+0vwOnWnvlOyeIA==} engines: {node: '>= 0.4'} @@ -6581,6 +6478,16 @@ packages: es-shim-unscopables: 1.0.0 dev: true + /array.prototype.flat@1.3.2: + resolution: {integrity: sha512-djYB+Zx2vLewY8RWlNCUdHjDXs2XOgm602S9E7P/UpHgfeHL00cRiIF+IN/G/aUJ7kGPb6yO/ErDI5V2s8iycA==} + engines: {node: '>= 0.4'} + dependencies: + call-bind: 1.0.5 + define-properties: 1.2.0 + es-abstract: 1.22.1 + es-shim-unscopables: 1.0.0 + dev: true + /array.prototype.flatmap@1.3.1: resolution: {integrity: sha512-8UGn9O1FDVvMNB0UlLv4voxRMze7+FpHyF5mSMRjWHUMlpoDViniy05870VlxhfgTnLbpuwTzvD76MTtWxB/mQ==} engines: {node: '>= 0.4'} @@ -6591,6 +6498,16 @@ packages: es-shim-unscopables: 1.0.0 dev: true + /array.prototype.flatmap@1.3.2: + resolution: {integrity: sha512-Ewyx0c9PmpcsByhSW4r+9zDU7sGjFc86qf/kKtuSCRdhfbk0SNLLkaT5qvcHnRGgc5NP/ly/y+qkXkqONX54CQ==} + engines: {node: '>= 0.4'} + dependencies: + call-bind: 1.0.5 + define-properties: 1.2.0 + es-abstract: 1.22.1 + es-shim-unscopables: 1.0.0 + dev: true + /array.prototype.tosorted@1.1.1: resolution: {integrity: sha512-pZYPXPRl2PqWcsUs6LOMn+1f1532nEoPTYowBtqLwAW+W8vSVhkIGnmOX1t/UQjD6YGI0vcD2B1U7ZFGQH9jnQ==} dependencies: @@ -6666,11 +6583,6 @@ packages: resolution: {integrity: sha512-Oei9OH4tRh0YqU3GxhX79dM/mwVgvbZJaSNaRk+bshkj0S5cfHcgYakreBjrHwatXKbz+IoIdYLxrKim2MjW0Q==} dev: true - /at-least-node@1.0.0: - resolution: {integrity: sha512-+q/t7Ekv1EDY2l6Gda6LLiX14rU9TV20Wa3ofeQmwPFZbOMo9DXrLbOjFaaclkXKWidIaopwAObQDqwWtGUjqg==} - engines: {node: '>= 4.0.0'} - dev: false - /attr-accept@2.2.2: resolution: {integrity: sha512-7prDjvt9HmqiZ0cl5CRjtS84sEyhsHP2coDkaZKRKVfCDo9s7iw7ChVmar78Gu9pC4SoR/28wFu/G5JJhTnqEg==} engines: {node: '>=4'} @@ -6749,6 +6661,7 @@ packages: /balanced-match@1.0.2: resolution: {integrity: sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==} + dev: true /base64-js@1.5.1: resolution: {integrity: sha512-AKpaYlHn8t4SVbOHCy+b5+KKgvR4vrsD8vbvrbiQJps7fKDTkjkDry6ji0rUJjC0kzbNePLwzxq8iypo41qeWA==} @@ -6815,6 +6728,7 @@ packages: dependencies: balanced-match: 1.0.2 concat-map: 0.0.1 + dev: true /brace-expansion@2.0.1: resolution: {integrity: sha512-XnAIvQ8eM+kC6aULx6wuQiwVsnzsi9d3WxzV3FpWTGA19F621kwdbsAcFKXgKUHZWsy+mY6iL1sHTxWEFCytDA==} @@ -6827,6 +6741,7 @@ packages: engines: {node: '>=8'} dependencies: fill-range: 7.0.1 + dev: true /browser-assert@1.2.1: resolution: {integrity: sha512-nfulgvOR6S4gt9UKCeGJOuSGBPGiFT6oQ/2UBnvTY/5aQ1PnksW72fhZkM30DzoRRv2WpwZf1vHHEr3mtuXIWQ==} @@ -6886,6 +6801,7 @@ packages: function-bind: 1.1.2 get-intrinsic: 1.2.2 set-function-length: 1.1.1 + dev: true /callsites@3.1.0: resolution: {integrity: sha512-P8BjAsXvZS+VIDUI11hHCQEv74YT67YUi5JJFNWIqL235sBmjX4+qx9Muvls5ivyNENctx46xQLQ3aTuE7ssaQ==} @@ -6913,6 +6829,35 @@ packages: type-detect: 4.0.8 dev: true + /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.1)(@types/react@18.2.42)(react-dom@18.2.0)(react@18.2.0): + resolution: {integrity: sha512-ZL43hyXPnWf1g/HjsZDecbeJ4F2Q6tTPYJozlKWkrQ7lIX7ORP0aZYwmc5/Wly4UNzMimj2Vuosl6MmIXH+G2g==} + peerDependencies: + '@chakra-ui/form-control': ^2.0.0 + '@chakra-ui/icon': ^3.0.0 + '@chakra-ui/layout': ^2.0.0 + '@chakra-ui/media-query': ^3.0.0 + '@chakra-ui/menu': ^2.0.0 + '@chakra-ui/spinner': ^2.0.0 + '@chakra-ui/system': ^2.0.0 + '@emotion/react': ^11.8.1 + react: ^18.0.0 + react-dom: ^18.0.0 + dependencies: + '@chakra-ui/form-control': 2.2.0(@chakra-ui/system@2.6.2)(react@18.2.0) + '@chakra-ui/icon': 3.2.0(@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/media-query': 3.3.0(@chakra-ui/system@2.6.2)(react@18.2.0) + '@chakra-ui/menu': 2.2.1(@chakra-ui/system@2.6.2)(framer-motion@10.16.15)(react@18.2.0) + '@chakra-ui/spinner': 2.1.0(@chakra-ui/system@2.6.2)(react@18.2.0) + '@chakra-ui/system': 2.6.2(@emotion/react@11.11.1)(@emotion/styled@11.11.0)(react@18.2.0) + '@emotion/react': 11.11.1(@types/react@18.2.42)(react@18.2.0) + react: 18.2.0 + react-dom: 18.2.0(react@18.2.0) + react-select: 5.7.7(@types/react@18.2.42)(react-dom@18.2.0)(react@18.2.0) + transitivePeerDependencies: + - '@types/react' + dev: false + /chalk@2.4.2: resolution: {integrity: sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ==} engines: {node: '>=4'} @@ -6935,6 +6880,7 @@ packages: dependencies: ansi-styles: 4.3.0 supports-color: 7.2.0 + dev: true /check-error@1.0.3: resolution: {integrity: sha512-iKEoDYaRmd1mxM90a2OEfWhjsjPpYPuQ+lMYsoxB126+t8fw7ySEO48nmDg5COTjxDI65/Y2OWpeEHk3ZOe8zg==} @@ -6969,6 +6915,7 @@ packages: /ci-info@3.9.0: resolution: {integrity: sha512-NIxF55hv4nSqQswkAeiOi1r83xy8JldOFDTWiug55KBu9Jnblncd2U6ViHmYgHf01TPZS77NJBhBMKdWj9HQMQ==} engines: {node: '>=8'} + dev: true /classcat@5.0.4: resolution: {integrity: sha512-sbpkOw6z413p+HDGcBENe498WM9woqWHiJxCq7nvmxe9WmrUmqfAcxpIwAiMtM5Q3AhYkzXcNQHqsWq0mND51g==} @@ -7055,11 +7002,6 @@ packages: engines: {node: '>=0.8'} dev: true - /clsx@1.1.1: - resolution: {integrity: sha512-6/bPho624p3S2pMyvP5kKBPXnI3ufHLObBFCfgx+LkeR5lg2XYy2hqZqUf45ypD8COn2bhgGJSUE+l5dhNBieA==} - engines: {node: '>=6'} - dev: false - /color-convert@1.9.3: resolution: {integrity: sha512-QfAUtd+vFdAtFQcC8CCyYt1fYWxSqAiK2cSD6zDB8N3cpsEBAvRxp9zOGg6G/SHHJYAT88/az/IuDGALsNVbGg==} dependencies: @@ -7070,12 +7012,14 @@ packages: engines: {node: '>=7.0.0'} dependencies: color-name: 1.1.4 + dev: true /color-name@1.1.3: resolution: {integrity: sha512-72fSenhMw2HZMTVHeCA9KCmpEIbzWiQsjN+BHcBbS9vr1mtt+vJjPdksIBNUmKAW8TFUDPJK5SUU3QhE9NEXDw==} /color-name@1.1.4: resolution: {integrity: sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==} + dev: true /color2k@2.0.2: resolution: {integrity: sha512-kJhwH5nAwb34tmyuqq/lgjEKzlFXn1U99NlnB6Ws4qVaERcRUYeYP1cBw6BJ4vxaWStAUEef4WMr7WjOCnBt8w==} @@ -7162,6 +7106,7 @@ packages: /concat-map@0.0.1: resolution: {integrity: sha512-/Srv4dswyQNBfohGpz9o6Yb3Gz3SrUDqBH5rTuhGR7ahtlbYKnVxw2bCFMRljaA7EXHaXZ8wsHdodFvbkhKmqg==} + dev: true /concat-stream@1.6.2: resolution: {integrity: sha512-27HBghJxjiZtIk3Ycvn/4kbJk/1uZuJFfuPEns6LaEvpvG1f0hTea8lilrouyo9mVc2GWdcEZ8OLoGmSADlrCw==} @@ -7260,6 +7205,7 @@ packages: path-key: 3.1.1 shebang-command: 2.0.0 which: 2.0.2 + dev: true /crypto-random-string@2.0.0: resolution: {integrity: sha512-v1plID3y9r/lPhviJ1wrXpLeyUIGAZ2SHNYTEapm7/8A9nLPoyvVp3RK/EPFqn5kEznyWgYZNsRtYYIWbuG8KA==} @@ -7290,10 +7236,6 @@ packages: resolution: {integrity: sha512-YUifsXXuknHlUsmlgyY0PKzgPOr7/FjCePfHNt0jxm83wHZi44VDMQ7/fGNkjY3/jV1MC+1CmZbaHzugyeRtpg==} dev: true - /csstype@3.0.9: - resolution: {integrity: sha512-rpw6JPxK6Rfg1zLOYCSwle2GFOOsnjmDYDaBwEcwoOg4qlsIVCN789VkBZDJAGi4T07gI4YSutR43t9Zz4Lzuw==} - dev: false - /csstype@3.1.2: resolution: {integrity: sha512-I7K1Uu0MBPzaFKg4nI5Q7Vs2t+3gWWW648spaF+Rg7pI9ds18Ugn+lvg4SHczUdKlHI5LWBXyqfS8+DufyBsgQ==} @@ -7389,6 +7331,17 @@ packages: ms: 2.0.0 dev: true + /debug@3.2.7: + resolution: {integrity: sha512-CFjzYYAi4ThfiQvizrFQevTTXHtnCqWfe7x1AhgEscTz6ZbLbfoLRLPugTQyBth6f8ZERVUSyWHFD/7Wu4t1XQ==} + peerDependencies: + supports-color: '*' + peerDependenciesMeta: + supports-color: + optional: true + dependencies: + ms: 2.1.3 + dev: true + /debug@4.3.4: resolution: {integrity: sha512-PRWFHuSU3eDtQJPvnNY7Jcket1j0t5OuOsFzPPzsekD52Zl8qUfFIPEiswXqIvHWGVHOgX+7G/vCNNhehwxfkQ==} engines: {node: '>=6.0'} @@ -7466,6 +7419,7 @@ packages: get-intrinsic: 1.2.2 gopd: 1.0.1 has-property-descriptors: 1.0.0 + dev: true /define-lazy-prop@2.0.0: resolution: {integrity: sha512-Ds09qNh8yw3khSjiJjiUInaGX9xlqZDY7JVryGxdxV7NPeuqQfplOpQ66yJFZut3jLa5zOwkXw1g9EI2uKh4Og==} @@ -7524,6 +7478,7 @@ packages: /dequal@2.0.3: resolution: {integrity: sha512-0je+qPKHEMohvfRTCEo3CrPG6cAzAYgmzKyxRiYSSDkS6eGJdyVJm7WaYA5ECaAD9wLB2T4EEeymA5aFVcYXCA==} engines: {node: '>=6'} + dev: true /destroy@1.2.0: resolution: {integrity: sha512-2sJGJTaXIIaR1w4iJSNoN0hnMY7Gpc/n8D4qSCJw8QqFWXf7cuAgnEHxBpweaVcPevC2l3KpjYCx3NypQQgaJg==} @@ -7743,6 +7698,13 @@ packages: resolution: {integrity: sha512-X7BJ2yElsnOJ30pZF4uIIDfBEVgF4XEBxL9Bxhy6dnrm5hkzqmsWHGTiHqRiITNhMyFLyAiWndIJP7Z1NTteDg==} dev: true + /dom-helpers@5.2.1: + resolution: {integrity: sha512-nRCa7CK3VTrM2NmGkIy4cbK7IZlgBE/PYMn55rrXefr5xXDP0LdtfPnblFDoVdcAfslJ7or6iqAUnx0CCGIWQA==} + dependencies: + '@babel/runtime': 7.23.5 + csstype: 3.1.2 + dev: false + /dotenv-expand@10.0.0: resolution: {integrity: sha512-GopVGCpVS1UKH75VKHGuQFqS1Gusej0z4FyQkPdwjil2gNIv+LNsqBlboOzpJFZKVT95GkCyWJbBSdFEFUWI2A==} engines: {node: '>=12'} @@ -8064,6 +8026,45 @@ packages: eslint: 8.55.0 dev: true + /eslint-import-resolver-node@0.3.9: + resolution: {integrity: sha512-WFj2isz22JahUv+B788TlO3N6zL3nNJGU8CcZbPZvVEkBPaJdCV4vy5wyghty5ROFbCRnm132v8BScu5/1BQ8g==} + dependencies: + debug: 3.2.7 + is-core-module: 2.13.1 + resolve: 1.22.8 + transitivePeerDependencies: + - supports-color + dev: true + + /eslint-module-utils@2.8.0(@typescript-eslint/parser@6.13.2)(eslint-import-resolver-node@0.3.9)(eslint@8.55.0): + resolution: {integrity: sha512-aWajIYfsqCKRDgUfjEXNN/JlrzauMuSEy5sbd7WXbtW3EH6A6MpwEh42c7qD+MqQo9QMJ6fWLAeIJynx0g6OAw==} + engines: {node: '>=4'} + peerDependencies: + '@typescript-eslint/parser': '*' + eslint: '*' + eslint-import-resolver-node: '*' + eslint-import-resolver-typescript: '*' + eslint-import-resolver-webpack: '*' + peerDependenciesMeta: + '@typescript-eslint/parser': + optional: true + eslint: + optional: true + eslint-import-resolver-node: + optional: true + eslint-import-resolver-typescript: + optional: true + eslint-import-resolver-webpack: + optional: true + dependencies: + '@typescript-eslint/parser': 6.13.2(eslint@8.55.0)(typescript@5.3.3) + debug: 3.2.7 + eslint: 8.55.0 + eslint-import-resolver-node: 0.3.9 + transitivePeerDependencies: + - supports-color + dev: true + /eslint-plugin-i18next@6.0.3: resolution: {integrity: sha512-RtQXYfg6PZCjejIQ/YG+dUj/x15jPhufJ9hUDGH0kCpJ6CkVMAWOQ9exU1CrbPmzeykxLjrXkjAaOZF/V7+DOA==} engines: {node: '>=0.10.0'} @@ -8072,6 +8073,41 @@ packages: requireindex: 1.1.0 dev: true + /eslint-plugin-import@2.29.1(@typescript-eslint/parser@6.13.2)(eslint@8.55.0): + resolution: {integrity: sha512-BbPC0cuExzhiMo4Ff1BTVwHpjjv28C5R+btTOGaCRC7UEz801up0JadwkeSk5Ued6TG34uaczuVuH6qyy5YUxw==} + engines: {node: '>=4'} + peerDependencies: + '@typescript-eslint/parser': '*' + eslint: ^2 || ^3 || ^4 || ^5 || ^6 || ^7.2.0 || ^8 + peerDependenciesMeta: + '@typescript-eslint/parser': + optional: true + dependencies: + '@typescript-eslint/parser': 6.13.2(eslint@8.55.0)(typescript@5.3.3) + array-includes: 3.1.7 + array.prototype.findlastindex: 1.2.3 + array.prototype.flat: 1.3.2 + array.prototype.flatmap: 1.3.2 + debug: 3.2.7 + doctrine: 2.1.0 + eslint: 8.55.0 + eslint-import-resolver-node: 0.3.9 + eslint-module-utils: 2.8.0(@typescript-eslint/parser@6.13.2)(eslint-import-resolver-node@0.3.9)(eslint@8.55.0) + hasown: 2.0.0 + is-core-module: 2.13.1 + is-glob: 4.0.3 + minimatch: 3.1.2 + object.fromentries: 2.0.7 + object.groupby: 1.0.1 + object.values: 1.1.7 + semver: 6.3.1 + tsconfig-paths: 3.15.0 + transitivePeerDependencies: + - eslint-import-resolver-typescript + - eslint-import-resolver-webpack + - supports-color + dev: true + /eslint-plugin-path@1.2.2(eslint@8.55.0): resolution: {integrity: sha512-RJ5e/DXRUj7cFD6y3xX5r2syU0uKEkjo9sU8lpayxV/H2plNKPjWv/oRSrWv+XibWV1Qvsu7VELobBFFSPb1UQ==} engines: {node: '>= 12.22.0'} @@ -8116,6 +8152,14 @@ packages: string.prototype.matchall: 4.0.8 dev: true + /eslint-plugin-simple-import-sort@10.0.0(eslint@8.55.0): + resolution: {integrity: sha512-AeTvO9UCMSNzIHRkg8S6c3RPy5YEwKWSQPx3DYghLedo2ZQxowPFLGDN1AZ2evfg6r6mjBSZSLxLFsWSu3acsw==} + peerDependencies: + eslint: '>=5.0.0' + dependencies: + eslint: 8.55.0 + dev: true + /eslint-plugin-storybook@0.6.15(eslint@8.55.0)(typescript@5.3.3): resolution: {integrity: sha512-lAGqVAJGob47Griu29KXYowI4G7KwMoJDOkEip8ujikuDLxU+oWJ1l0WL6F2oDO4QiyUFXvtDkEkISMOPzo+7w==} engines: {node: 12.x || 14.x || >= 16} @@ -8430,6 +8474,7 @@ packages: dependencies: fs-extra: 11.1.1 ramda: 0.29.0 + dev: true /filelist@1.0.4: resolution: {integrity: sha512-w1cEuf3S+DrLCQL7ET6kz+gmlJdbq9J7yXCSjK/OZCPA+qEN1WyF4ZAf0YYJa4/shHJra2t/d/r8SV4Ji+x+8Q==} @@ -8464,6 +8509,7 @@ packages: engines: {node: '>=8'} dependencies: to-regex-range: 5.0.1 + dev: true /filter-obj@5.1.0: resolution: {integrity: sha512-qWeTREPoT7I0bifpPUXtxkZJ1XJzxWtfoWWkdVGqa+eCr3SHW/Ocp89o8vLvbUuQnadybJpjOKu4V+RwO6sGng==} @@ -8530,12 +8576,6 @@ packages: path-exists: 4.0.0 dev: true - /find-yarn-workspace-root@2.0.0: - resolution: {integrity: sha512-1IMnbjt4KzsQfnhnzNd8wUEgXZ44IzZaZmnLYx7D5FZlaHt2gW20Cri8Q+E/t5tIj4+epTBub+2Zxu/vNILzqQ==} - dependencies: - micromatch: 4.0.5 - dev: false - /flat-cache@3.0.4: resolution: {integrity: sha512-dm9s5Pw7Jc0GvMYbshN6zchCA9RgQlzzEZX3vylR9IqFfS8XciblUXOKfW6SiuJ0e13eDYZoZV5wdrev7P3Nwg==} engines: {node: ^10.12.0 || >=12.0.0} @@ -8633,6 +8673,7 @@ packages: graceful-fs: 4.2.11 jsonfile: 6.1.0 universalify: 2.0.0 + dev: true /fs-extra@7.0.1: resolution: {integrity: sha512-YJDaCJZEnBmcbw13fvdAM9AwNOJwOzrE4pqMqBq5nFiEqXUqHwlK4B+3pUw6JNvfSPtX05xFHtYy/1ni01eGCw==} @@ -8643,16 +8684,6 @@ packages: universalify: 0.1.2 dev: true - /fs-extra@9.1.0: - resolution: {integrity: sha512-hcg3ZmepS30/7BSFqRvoo3DOMQu7IjqxO5nCDt+zM9XWjb33Wg7ziNT+Qvqbuc3+gWpzO02JubVyk2G4Zvo1OQ==} - engines: {node: '>=10'} - dependencies: - at-least-node: 1.0.0 - graceful-fs: 4.2.11 - jsonfile: 6.1.0 - universalify: 2.0.0 - dev: false - /fs-minipass@2.1.0: resolution: {integrity: sha512-V/JgOLFCS+R6Vcq0slCuaeWEdNC3ouDlJMNIsacH2VtALiu9mV4LPrHc5cDl8k5aw6J8jwgWWpiTo5RYhmIzvg==} engines: {node: '>= 8'} @@ -8662,6 +8693,7 @@ packages: /fs.realpath@1.0.0: resolution: {integrity: sha512-OO0pH2lK6a0hZnAdau5ItzHPI6pUlvI7jMVnxUQRtw4owF2wk8lOSabtGDCTP4Ggrg2MbGnWO9X8K1t4+fGMDw==} + dev: true /fsevents@2.3.3: resolution: {integrity: sha512-5xoDfX+fL7faATnagmWPpbFtwh/R77WmMMqqHGS65C3vvB0YHrgF+B1YmZ3441tMj5n63k0212XNoJwzlhffQw==} @@ -8830,6 +8862,7 @@ packages: minimatch: 3.1.2 once: 1.4.0 path-is-absolute: 1.0.1 + dev: true /globals@11.12.0: resolution: {integrity: sha512-WOBp/EEGUiIsJSp7wcv/y6MO+lV9UoncWqxuFfm8eBwzWNgyfBd6Gz+IeKQ9jCmyhoH99g15M3T+QaVHFjizVA==} @@ -8877,9 +8910,11 @@ packages: resolution: {integrity: sha512-d65bNlIadxvpb/A2abVdlqKqV563juRnZ1Wtk6s1sIR8uNsXR70xqIzVqxVf1eTqDunwT2MkczEeaezCKTZhwA==} dependencies: get-intrinsic: 1.2.2 + dev: true /graceful-fs@4.2.11: resolution: {integrity: sha512-RbJ5/jmFcNNCcDV5o9eTnBLJ/HszWV0P73bc+Ff4nS/rJj+YaS6IGyiOL0VoBYX+l1Wrl3k63h/KrH+nhJ0XvQ==} + dev: true /graphemer@1.4.0: resolution: {integrity: sha512-EtKwoO6kxCL9WO5xipiHTZlSzBm7WLT627TqC/uVRd0HKmq8NXyebnNYxDoBi7wt8eTWrUrKXCOVaFq9x1kgag==} @@ -8921,6 +8956,7 @@ packages: /has-flag@4.0.0: resolution: {integrity: sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==} engines: {node: '>=8'} + dev: true /has-property-descriptors@1.0.0: resolution: {integrity: sha512-62DVLZGoiEBDHQyqG4w9xCuZ7eJEwNmJRWw2VY84Oedb7WFcA27fiEVe8oUQx9hAUJ4ekurquucTGwsyO1XGdQ==} @@ -9090,9 +9126,11 @@ packages: dependencies: once: 1.4.0 wrappy: 1.0.2 + dev: true /inherits@2.0.4: resolution: {integrity: sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==} + dev: true /ini@1.3.8: resolution: {integrity: sha512-JV/yugV2uzW5iMRSiZAyDtQd+nxtUnjeLt0acNdw98kKLrvuRVyB80tsREOE7yvGVgalhZ6RNXCmEHkUKBKxew==} @@ -9205,6 +9243,7 @@ packages: resolution: {integrity: sha512-F+i2BKsFrH66iaUFc0woD8sLy8getkwTwtOBjvs56Cx4CgJDeKQeqfz8wAYiSb8JOprWhHH5p77PbmYCvvUuXQ==} engines: {node: '>=8'} hasBin: true + dev: true /is-extglob@2.1.1: resolution: {integrity: sha512-SbKbANkN603Vi4jEZv49LeVJMn4yGwsbzZworEoyEiutsN3nJYdbO36zfhGJ6QEDpOZIFkDtnq5JRxmvl3jsoQ==} @@ -9273,6 +9312,7 @@ packages: /is-number@7.0.0: resolution: {integrity: sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng==} engines: {node: '>=0.12.0'} + dev: true /is-obj@1.0.1: resolution: {integrity: sha512-l4RyHgRqGN4Y3+9JHVrNqO+tN0rV5My76uW5/nuO4K1b6vw5G8d/cmFjP9tRfEsdhZNt0IFdZuK/c2Vr4Nb+Qg==} @@ -9390,6 +9430,7 @@ packages: engines: {node: '>=8'} dependencies: is-docker: 2.2.1 + dev: true /isarray@1.0.0: resolution: {integrity: sha512-VLghIWNM6ELQzo7zwmcg0NmTVyWKYjvIeM83yjp0wRDTmUnrM678fQbcKBo6n2CJEF0szoG//ytg+TKla89ALQ==} @@ -9401,6 +9442,7 @@ packages: /isexe@2.0.0: resolution: {integrity: sha512-RHxMLp9lnKHGHRng9QFhRCMbYAcVpn69smSGcq3f36xjgVVWThj4qqLbTLlq7Ssj8B+fIQ1EuCEGI2lKsyQeIw==} + dev: true /isobject@3.0.1: resolution: {integrity: sha512-WhB9zCku7EGTj/HQQRz5aUQEUeoQZH2bWcltRErOpymJ4boYE6wL9Tbr23krRPSZ+C5zqNSrSw+Cc7sZZ4b7vg==} @@ -9600,12 +9642,6 @@ packages: resolution: {integrity: sha512-Bdboy+l7tA3OGW6FjyFHWkP5LuByj1Tk33Ljyq0axyzdk9//JSi2u3fP1QSmd1KNwq6VOKYGlAu87CisVir6Pw==} dev: true - /json-stable-stringify@1.0.2: - resolution: {integrity: sha512-eunSSaEnxV12z+Z73y/j5N37/In40GK4GmsSy+tEHJMxknvqnA7/djeYtAgW0GsWHUfg+847WJjKaEylk2y09g==} - dependencies: - jsonify: 0.0.1 - dev: false - /json5@1.0.2: resolution: {integrity: sha512-g1MWMLBiz8FKi1e4w0UyVL3w+iJceWAFBAaBnnGKOpNa5f8TLktkbre1+s6oICydWAm+HRUGTmI+//xv2hvXYA==} hasBin: true @@ -9631,10 +9667,7 @@ packages: universalify: 2.0.0 optionalDependencies: graceful-fs: 4.2.11 - - /jsonify@0.0.1: - resolution: {integrity: sha512-2/Ki0GcmuqSrgFyelQq9M05y7PS0mEwuIzrf3f1fPqkVDVRvZrPZtVSMHxdgo8Aq0sxAOb/cr2aqqA3LeWHVPg==} - dev: false + dev: true /jsx-ast-utils@3.3.4: resolution: {integrity: sha512-fX2TVdCViod6HwKEtSWGHs57oFhVfCMwieb9PuRDgjDPh5XeqJiHFFFJCHxU5cnTc3Bu/GRL+kPiFmw8XWOfKw==} @@ -9651,12 +9684,6 @@ packages: engines: {node: '>=0.10.0'} dev: true - /klaw-sync@6.0.0: - resolution: {integrity: sha512-nIeuVSzdCCs6TDPTqI8w1Yre34sSq7AkZ4B3sfOBbI2CgVSB4Du4aLQijFU2+lhAFCwt9+42Hel6lQNIv6AntQ==} - dependencies: - graceful-fs: 4.2.11 - dev: false - /kleur@3.0.3: resolution: {integrity: sha512-eTIzlVOSUR+JxdDFepEYcBMtZ9Qqdef+rnzWdRZuMbOywu5tO2w2N7rqjoANZ5k9vywhL6Br1VRjUIgTQx4E8w==} engines: {node: '>=6'} @@ -9761,6 +9788,7 @@ packages: /lodash@4.17.21: resolution: {integrity: sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg==} + dev: true /log-symbols@3.0.0: resolution: {integrity: sha512-dSkNGuI7iG3mfvDzUuYZyvk5dD9ocYCYzNU6CYDE6+Xqd+gwme6Z00NS3dUh8mq/73HaEtT7m6W+yUPtU6BZnQ==} @@ -9805,6 +9833,7 @@ packages: engines: {node: '>=10'} dependencies: yallist: 4.0.0 + dev: true /lz-string@1.5.0: resolution: {integrity: sha512-h5bgJWpxJNswbU7qCrV0tIKQCaS3blPDrqKWx+QxzuzL1zGUzij9XCWLrSLsJPu5t+eWA/ycetzYAO5IOMcWAQ==} @@ -9885,6 +9914,7 @@ packages: /map-or-similar@1.5.0: resolution: {integrity: sha512-0aF7ZmVon1igznGI4VS30yugpduQW3y3GkcgGJOp7d8x8QrizhigUxjI/m2UojsXXto+jLAH3KSz+xOJTiORjg==} + dev: true /markdown-to-jsx@7.3.2(react@18.2.0): resolution: {integrity: sha512-B+28F5ucp83aQm+OxNrPkS8z0tMKaeHiy0lHJs3LqCyDQFtWuenaIrkaVTgAm1pf1AU85LXltva86hlaT17i8Q==} @@ -9914,10 +9944,15 @@ packages: engines: {node: '>= 0.6'} dev: true + /memoize-one@6.0.0: + resolution: {integrity: sha512-rkpe71W0N0c0Xz6QD0eJETuWAJGnJ9afsl1srmwPrI+yBCkge5EycXXbYRyvL29zZVUWQCY7InPRCv3GDXuZNw==} + dev: false + /memoizerific@1.11.3: resolution: {integrity: sha512-/EuHYwAPdLtXwAwSZkh/Gutery6pD2KYd44oQLhAvQp/50mpyduZh8Q7PYHXTCJ+wuXxt7oij2LXyIJOOYFPog==} dependencies: map-or-similar: 1.5.0 + dev: true /merge-descriptors@1.0.1: resolution: {integrity: sha512-cCi6g3/Zr1iqQi6ySbseM1Xvooa98N0w31jzUYrXPX2xqObmFGHJ0tQ5u74H3mVh7wLouTseZyYIq39g8cNp1w==} @@ -9943,6 +9978,7 @@ packages: dependencies: braces: 3.0.2 picomatch: 2.3.1 + dev: true /mime-db@1.52.0: resolution: {integrity: sha512-sPU4uV7dYlvtWJxwwxHD0PuihVNiE7TyAbQ5SWxDCB9mUYvOgroQOwYQQOKPJ8CIbE+1ETVlOoK1UC2nU3gYvg==} @@ -9982,6 +10018,7 @@ packages: resolution: {integrity: sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==} dependencies: brace-expansion: 1.1.11 + dev: true /minimatch@5.1.6: resolution: {integrity: sha512-lKwV/1brpG6mBUFHtb7NUmtABCb2WZZmm2wNiOA5hAb8VdCS4B3dtMWyvcoViccwAW/COERjXLt0zP1zXUN26g==} @@ -9999,6 +10036,7 @@ packages: /minimist@1.2.8: resolution: {integrity: sha512-2yyAR8qBkN3YuheJanUpWC5U3bb5osDywNB8RzDVlDwDHbocAJveqqj1u8+SVD7jkWT4yvsHCpWqqWqAxb0zCA==} + dev: true /minipass@3.3.6: resolution: {integrity: sha512-DxiNidxSEK+tHG6zOIklvNOwm3hvCrbUrdtzY74U6HKTJxvIDfOUL5W5P2Ghd3DTkhhKPYGqeNUIh5qcM4YBfw==} @@ -10226,6 +10264,7 @@ packages: /object-inspect@1.12.3: resolution: {integrity: sha512-geUvdk7c+eizMNUDkRpW1wJwgfOiOeHbxBR/hLXK1aT6zmVSO0jsQcs7fj6MGw89jC/cjGfLcNOrtMYtGqm81g==} + dev: true /object-is@1.1.5: resolution: {integrity: sha512-3cyDsyHgtmi7I7DfSSI2LDp6SK2lwvtbg0p0R1e0RvTqF5ceGx+K2dfSjm1bKDMVCFEDAQvy+o8c6a7VujOddw==} @@ -10267,6 +10306,24 @@ packages: es-abstract: 1.22.1 dev: true + /object.fromentries@2.0.7: + resolution: {integrity: sha512-UPbPHML6sL8PI/mOqPwsH4G6iyXcCGzLin8KvEPenOZN5lpCNBZZQ+V62vdjB1mQHrmqGQt5/OJzemUA+KJmEA==} + engines: {node: '>= 0.4'} + dependencies: + call-bind: 1.0.5 + define-properties: 1.2.0 + es-abstract: 1.22.1 + dev: true + + /object.groupby@1.0.1: + resolution: {integrity: sha512-HqaQtqLnp/8Bn4GL16cj+CUYbnpe1bh0TtEaWvybszDG4tgxCJuRpV8VGuvNaI1fAnI4lUJzDG55MXcOH4JZcQ==} + dependencies: + call-bind: 1.0.5 + define-properties: 1.2.0 + es-abstract: 1.22.1 + get-intrinsic: 1.2.2 + dev: true + /object.hasown@1.1.2: resolution: {integrity: sha512-B5UIT3J1W+WuWIU55h0mjlwaqxiE5vYENJXIXZ4VFe05pNYrkKuK0U/6aFcb0pKywYJh7IhfoqUfKVmrJJHZHw==} dependencies: @@ -10283,6 +10340,15 @@ packages: es-abstract: 1.22.1 dev: true + /object.values@1.1.7: + resolution: {integrity: sha512-aU6xnDFYT3x17e/f0IiiwlGPTy2jzMySGfUB4fq6z7CV8l85CWHDk5ErhyhpfDHhrOMwGFhSQkhMGHaIotA6Ng==} + engines: {node: '>= 0.4'} + dependencies: + call-bind: 1.0.5 + define-properties: 1.2.0 + es-abstract: 1.22.1 + dev: true + /on-finished@2.4.1: resolution: {integrity: sha512-oVlzkg3ENAhCk2zdv7IJwd/QUD4z2RxRwpkcGY8psCVcCYZNq4wYnVWALHM+brtuJjePWiYF/ClmuDr8Ch5+kg==} engines: {node: '>= 0.8'} @@ -10299,6 +10365,7 @@ packages: resolution: {integrity: sha512-lNaJgI+2Q5URQBkccEKHTQOPaXdUxnZZElQTZY0MFUAuaEqe1E+Nyvgdz/aIyNi6Z9MzO5dv1H8n58/GELp3+w==} dependencies: wrappy: 1.0.2 + dev: true /onetime@5.1.2: resolution: {integrity: sha512-kbpaSSGJTWdAY5KPVeMOKXSrPtr8C8C7wodJbcsd51jRnmD+GZu8Y0VoU6Dm5Z4vWr0Ig/1NKuWRKf7j5aaYSg==} @@ -10307,14 +10374,6 @@ packages: mimic-fn: 2.1.0 dev: true - /open@7.4.2: - resolution: {integrity: sha512-MVHddDVweXZF3awtlAS+6pgKLlm/JgxZ90+/NBurBoQctVOOB/zDdVjcyPzQ+0laDGbsWgrRkflI65sQeOgT9Q==} - engines: {node: '>=8'} - dependencies: - is-docker: 2.2.1 - is-wsl: 2.2.0 - dev: false - /open@8.4.2: resolution: {integrity: sha512-7x81NCL719oNbsq/3mh+hVrAWmFuEYUqrq/Iw3kUzH8ReypT9QQ0BLoJS7/G9k6N81XjW4qHWtjWwe/9eLy1EQ==} engines: {node: '>=12'} @@ -10367,11 +10426,6 @@ packages: wcwidth: 1.0.1 dev: true - /os-tmpdir@1.0.2: - resolution: {integrity: sha512-D2FR03Vir7FIu45XBY20mTb+/ZSWB00sjU9jdQXt83gDrI4Ztz5Fs7/yy74g2N5SVQY4xY1qDr4rNddwYRVX0g==} - engines: {node: '>=0.10.0'} - dev: false - /overlayscrollbars-react@0.5.3(overlayscrollbars@2.4.5)(react@18.2.0): resolution: {integrity: sha512-mq9D9tbfSeq0cti1kKMf3B3AzsEGwHcRIDX/K49CvYkHz/tKeU38GiahDkIPKTMEAp6lzKCo4x1eJZA6ZFYOxQ==} peerDependencies: @@ -10462,28 +10516,6 @@ packages: engines: {node: '>= 0.8'} dev: true - /patch-package@8.0.0: - resolution: {integrity: sha512-da8BVIhzjtgScwDJ2TtKsfT5JFWz1hYoBl9rUQ1f38MC2HwnEIkK8VN3dKMKcP7P7bvvgzNDbfNHtx3MsQb5vA==} - engines: {node: '>=14', npm: '>5'} - hasBin: true - dependencies: - '@yarnpkg/lockfile': 1.1.0 - chalk: 4.1.2 - ci-info: 3.9.0 - cross-spawn: 7.0.3 - find-yarn-workspace-root: 2.0.0 - fs-extra: 9.1.0 - json-stable-stringify: 1.0.2 - klaw-sync: 6.0.0 - minimist: 1.2.8 - open: 7.4.2 - rimraf: 2.7.1 - semver: 7.5.4 - slash: 2.0.0 - tmp: 0.0.33 - yaml: 2.3.1 - dev: false - /path-browserify@1.0.1: resolution: {integrity: sha512-b7uo2UCUOYZcnF/3ID0lulOJi/bafxa1xPe7ZPsammBSpjSWQkjNxlt635YGS2MiR9GjvuXCtz2emr3jbsz98g==} dev: true @@ -10501,10 +10533,12 @@ packages: /path-is-absolute@1.0.1: resolution: {integrity: sha512-AVbw3UJ2e9bq64vSaS9Am0fje1Pa8pbGqTTsmXfaIiMpnr5DlDhfJOuLj9Sf95ZPVDAUerDfEk88MPmPe7UCQg==} engines: {node: '>=0.10.0'} + dev: true /path-key@3.1.1: resolution: {integrity: sha512-ojmeN0qd+y0jszEtoY48r0Peq5dwMEkIlCOu6Q5f41lfkswXuKtYrhgoTpLnyIcHm24Uhqx+5Tqm2InSwLhE6Q==} engines: {node: '>=8'} + dev: true /path-parse@1.0.7: resolution: {integrity: sha512-LDJzPVEEEPR+y48z93A0Ed0yXb8pAByGWo/k5YYdYgpY2/2EsOsksJrq7lOHxryrVOn1ejG6oAp8ahvOIQD8sw==} @@ -10552,6 +10586,7 @@ packages: /picomatch@2.3.1: resolution: {integrity: sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA==} engines: {node: '>=8.6'} + dev: true /pify@4.0.1: resolution: {integrity: sha512-uB80kBFb/tfd68bVleG9T5GGsGPjJrLAUpR5PZIrhBnIaRTQRjqdJSsIKkOP6OAIFbj7GOrcudc5pNjZ+geV2g==} @@ -10816,6 +10851,7 @@ packages: engines: {node: '>=0.6'} dependencies: side-channel: 1.0.4 + dev: true /query-string@8.1.0: resolution: {integrity: sha512-BFQeWxJOZxZGix7y+SByG3F36dA0AbTy9o6pSmKFcFz7DAj0re9Frkty3saBn3nHo3D0oZJ/+rx3r8H8r8Jbpw==} @@ -10840,6 +10876,7 @@ packages: /ramda@0.29.0: resolution: {integrity: sha512-BBea6L67bYLtdbOqfp8f58fPMqEwx0doL+pAi8TZyp2YWz8R9G8z9x75CZI8W+ftqhFHCpEX2cRnUUXK130iKA==} + dev: true /randexp@0.4.6: resolution: {integrity: sha512-80WNmd9DA0tmZrw9qQa62GPPWfuXJknrmVmLcxvq4uZBdYqb1wYoKTmnlGUchvVWe0XiLupYkBoXVOxz3C8DYQ==} @@ -11162,6 +11199,27 @@ packages: react-dom: 18.2.0(react@18.2.0) dev: false + /react-select@5.7.7(@types/react@18.2.42)(react-dom@18.2.0)(react@18.2.0): + resolution: {integrity: sha512-HhashZZJDRlfF/AKj0a0Lnfs3sRdw/46VJIRd8IbB9/Ovr74+ZIwkAdSBjSPXsFMG+u72c5xShqwLSKIJllzqw==} + peerDependencies: + react: ^16.8.0 || ^17.0.0 || ^18.0.0 + react-dom: ^16.8.0 || ^17.0.0 || ^18.0.0 + dependencies: + '@babel/runtime': 7.23.5 + '@emotion/cache': 11.11.0 + '@emotion/react': 11.11.1(@types/react@18.2.42)(react@18.2.0) + '@floating-ui/dom': 1.5.3 + '@types/react-transition-group': 4.4.10 + memoize-one: 6.0.0 + prop-types: 15.8.1 + react: 18.2.0 + react-dom: 18.2.0(react@18.2.0) + react-transition-group: 4.4.5(react-dom@18.2.0)(react@18.2.0) + use-isomorphic-layout-effect: 1.1.2(@types/react@18.2.42)(react@18.2.0) + transitivePeerDependencies: + - '@types/react' + dev: false + /react-style-singleton@2.2.1(@types/react@18.2.42)(react@18.2.0): resolution: {integrity: sha512-ZWj0fHEMyWkHzKYUr2Bs/4zU6XLmq9HsgBURm7g5pAVfyn49DgUiNgY2d4lXRlYSiCif9YBGpQleewkcqddc7g==} engines: {node: '>=10'} @@ -11178,8 +11236,8 @@ packages: react: 18.2.0 tslib: 2.6.2 - /react-textarea-autosize@8.3.4(@types/react@18.2.42)(react@18.2.0): - resolution: {integrity: sha512-CdtmP8Dc19xL8/R6sWvtknD/eCXkQr30dtvC4VmGInhRsfF8X/ihXCq6+9l9qbxmKRiq407/7z5fxE7cVWQNgQ==} + /react-textarea-autosize@8.5.3(@types/react@18.2.42)(react@18.2.0): + resolution: {integrity: sha512-XT1024o2pqCuZSuBt9FwHlaDeNtVrtCXu0Rnz88t1jUGheCLa3PhjE1GH8Ctm2axEtvdCl5SUHYschyQ0L5QHQ==} engines: {node: '>=10'} peerDependencies: react: ^16.8.0 || ^17.0.0 || ^18.0.0 @@ -11192,6 +11250,20 @@ packages: - '@types/react' dev: false + /react-transition-group@4.4.5(react-dom@18.2.0)(react@18.2.0): + resolution: {integrity: sha512-pZcd1MCJoiKiBR2NRxeCRg13uCXbydPnmB4EOeRrY7480qNWO8IIgQG6zlDkm6uRMsURXPuKq0GWtiM59a5Q6g==} + peerDependencies: + react: '>=16.6.0' + react-dom: '>=16.6.0' + dependencies: + '@babel/runtime': 7.23.5 + dom-helpers: 5.2.1 + loose-envify: 1.4.0 + prop-types: 15.8.1 + react: 18.2.0 + react-dom: 18.2.0(react@18.2.0) + dev: false + /react-universal-interface@0.6.2(react@18.2.0)(tslib@2.6.2): resolution: {integrity: sha512-dg8yXdcQmvgR13RIlZbTRQOoUrDciFVoSBZILwjE2LFISxZZ8loVJKAkuzswl5js8BHda79bIb2b84ehU8IjXw==} peerDependencies: @@ -11530,6 +11602,7 @@ packages: hasBin: true dependencies: glob: 7.2.3 + dev: true /rimraf@3.0.2: resolution: {integrity: sha512-JZkJMZkAGFFPP2YqXZXPbMlMBgsxzE8ILs4lMIX/2o0L9UBw9O/Y3o6wFw/i9YLapcUJWwqbi3kdxIPdC62TIA==} @@ -11670,6 +11743,7 @@ packages: hasBin: true dependencies: lru-cache: 6.0.0 + dev: true /send@0.18.0: resolution: {integrity: sha512-qqWzuOjSFOuqPjFe4NOsMLafToQQwBSOEpS+FwEt3A2V3vKubTquT3vmLTQpFgMXp8AlFWFuP1qKaJZOtPpVXg==} @@ -11719,6 +11793,7 @@ packages: get-intrinsic: 1.2.2 gopd: 1.0.1 has-property-descriptors: 1.0.0 + dev: true /set-function-name@2.0.1: resolution: {integrity: sha512-tMNCiqYVkXIZgc2Hnoy2IvC/f8ezc5koaRFkCjrpWzGpCd3qbZXPzVy9MAZzK1ch/X0jvSkojys3oqJN0qCmdA==} @@ -11750,10 +11825,12 @@ packages: engines: {node: '>=8'} dependencies: shebang-regex: 3.0.0 + dev: true /shebang-regex@3.0.0: resolution: {integrity: sha512-7++dFhtcx3353uBaq8DDR4NuxBetBzC7ZQOhmTQInHEd6bSrXdiEyzCvG07Z44UYdLShWUyXt5M/yhz8ekcb1A==} engines: {node: '>=8'} + dev: true /shell-quote@1.8.1: resolution: {integrity: sha512-6j1W9l1iAs/4xYBI1SYOVZyFcCis9b4KCLQ8fgAGG07QvzaRLVVRQvAy85yNmmZSjYjg4MWh4gNvlPujU/5LpA==} @@ -11765,6 +11842,7 @@ packages: call-bind: 1.0.5 get-intrinsic: 1.2.2 object-inspect: 1.12.3 + dev: true /signal-exit@3.0.7: resolution: {integrity: sha512-wnD2ZE+l+SPC/uoS0vXeE9L1+0wuaMqKlfz9AMUo38JsyLSBWSFcHR1Rri62LZc12vLr1gb3jl7iwQhgwpAbGQ==} @@ -11786,11 +11864,6 @@ packages: resolution: {integrity: sha512-bLGGlR1QxBcynn2d5YmDX4MGjlZvy2MRBDRNHLJ8VI6l6+9FUiyTFNJ0IveOSP0bcXgVDPRcfGqA0pjaqUpfVg==} dev: true - /slash@2.0.0: - resolution: {integrity: sha512-ZYKh3Wh2z1PpEXWr0MpSBZ0V6mZHAQfYevttO11c51CaWjGTaadiKZ+wVt1PbMlDV5qhMFslpZCemhwOK7C89A==} - engines: {node: '>=6'} - dev: false - /slash@3.0.0: resolution: {integrity: sha512-g9Q1haeby36OSStwb4ntCGGGaKsaVSjQ68fBxoQcutl5fS1vuY18H3wSt3jFyFtrkx+Kz0V1G85A4MyAdDMi2Q==} engines: {node: '>=8'} @@ -11929,6 +12002,7 @@ packages: /store2@2.14.2: resolution: {integrity: sha512-siT1RiqlfQnGqgT/YzXVUNsom9S0H1OX+dpdGN1xkyYATo4I6sep5NmsRD/40s3IIOvlCq6akxkqG82urIZW1w==} + dev: true /storybook@7.6.4: resolution: {integrity: sha512-nQhs9XkrroxjqMoBnnToyc6M8ndbmpkOb1qmULO4chtfMy4k0p9Un3K4TJvDaP8c3wPUFGd4ZaJ1hZNVmIl56Q==} @@ -12112,6 +12186,7 @@ packages: engines: {node: '>=8'} dependencies: has-flag: 4.0.0 + dev: true /supports-color@8.1.1: resolution: {integrity: sha512-MpUEN2OodtUzxvKQl72cUF7RQ5EiHsGvSsVG0ia9c5RbWGL2CI4C7EpPS8UTBIplnlzZiNuV56w+FuNxy3ty2Q==} @@ -12133,10 +12208,6 @@ packages: resolution: {integrity: sha512-AsS729u2RHUfEra9xJrE39peJcc2stq2+poBXX8bcM08Y6g9j/i/PUzwNQqkaJde7Ntg1TO7bSREbR5sdosQ+g==} dev: true - /tabbable@6.2.0: - resolution: {integrity: sha512-Cat63mxsVJlzYvN51JmVXIgNoUokrIaT2zLclCXjRd8boZ0004U4KCs/sToJ75C6sdlByWxpYnb5Boif1VSFew==} - dev: false - /tapable@2.2.1: resolution: {integrity: sha512-GNzQvQTOIP6RyTfE2Qxb8ZVlNmw0n88vp1szwWRimP02mnTsx3Wtn5qRdqY9w2XduFNUgvOwhNnQsjwCp+kqaQ==} engines: {node: '>=6'} @@ -12178,6 +12249,7 @@ packages: resolution: {integrity: sha512-1QTEcJkJEhc8OnStBx/ILRu5J2p0GjvWsBx56bmZRqnrkdBMUe+nX92jxV+p3dB4CP6PZCdJMQJwCggkNBMzkQ==} dependencies: memoizerific: 1.11.3 + dev: true /temp-dir@2.0.0: resolution: {integrity: sha512-aoBAniQmmwtcKp/7BzsH8Cxzv8OL736p7v1ihGb5e9DJ9kTwGWHrQrVB5+lfVDzfGrdRzXch+ig7LHaY1JTOrg==} @@ -12235,13 +12307,6 @@ packages: engines: {node: '>=14.0.0'} dev: true - /tmp@0.0.33: - resolution: {integrity: sha512-jRCJlojKnZ3addtTOjdIqoRuPEKBvNXcGYqzO6zWZX8KfKEpnGY5jfggJQ3EjKuu8D4bJRr0y+cYJFmYbImXGw==} - engines: {node: '>=0.6.0'} - dependencies: - os-tmpdir: 1.0.2 - dev: false - /tmpl@1.0.5: resolution: {integrity: sha512-3f0uOEAQwIqGuWW2MVzYg8fV/QNnc/IpuJNG837rLuczAaLVHslWHZQj4IGiEl5Hs3kkbhwL9Ab7Hrsmuj+Smw==} dev: true @@ -12255,6 +12320,7 @@ packages: engines: {node: '>=8.0'} dependencies: is-number: 7.0.0 + dev: true /tocbot@4.23.0: resolution: {integrity: sha512-5DWuSZXsqG894mkGb8ZsQt9myyQyVxE50AiGRZ0obV0BVUTVkaZmc9jbgpknaAAPUm4FIrzGkEseD6FuQJYJDQ==} @@ -12289,6 +12355,7 @@ packages: /ts-dedent@2.2.0: resolution: {integrity: sha512-q5W7tVM71e2xjHZTlgfTDoPF/SmqKG5hddq9SzR49CH2hayqRKJtQ4mtRlSxKaJlR/+9rEM+mnBHf7I2/BQcpQ==} engines: {node: '>=6.10'} + dev: true /ts-easing@0.2.0: resolution: {integrity: sha512-Z86EW+fFFh/IFB1fqQ3/+7Zpf9t2ebOAxNI/V6Wo7r5gqiqtxmgTlQ1qbqQcjLKYeSHPTsEmvlJUDg/EuL0uHQ==} @@ -12329,6 +12396,15 @@ packages: strip-bom: 3.0.0 dev: true + /tsconfig-paths@3.15.0: + resolution: {integrity: sha512-2Ac2RgzDe/cn48GvOe3M+o82pEFewD3UPbyoUHHdKasHwJKjds4fLXWf/Ux5kATBKN20oaFGu+jbElp1pos0mg==} + dependencies: + '@types/json5': 0.0.29 + json5: 1.0.2 + minimist: 1.2.8 + strip-bom: 3.0.0 + dev: true + /tslib@1.14.1: resolution: {integrity: sha512-Xni35NKzjgMrwevysHTCArtLDpPvye8zV/0E4EyYn43P7/7qvQwPh9BGkHewbMulVntbigmcT7rdX3BNo9wRJg==} dev: true @@ -12504,6 +12580,7 @@ packages: /undici-types@5.26.5: resolution: {integrity: sha512-JlCMO+ehdEIKqlFxk6IfVoAUVmgz7cU7zD/h9XZ0qzeosSHmUJVOzSQvvYSYWXkFXC+IfLKSIffhv0sVZup6pA==} + dev: true /undici@5.27.2: resolution: {integrity: sha512-iS857PdOEy/y3wlM3yRp+6SNQQ6xU0mmZcwRSriqk+et/cwWAtwmIGf6WkoDN2EK/AMdCO/dfXzIwi+rFMrjjQ==} @@ -12573,6 +12650,7 @@ packages: /universalify@2.0.0: resolution: {integrity: sha512-hAZsKq7Yy11Zu1DE0OzWjw7nnLZmJZYTDZZyEFHZdUhV8FkH5MCfoU1XMaxXovpyW5nq5scPqq0ZDP9Zyl04oQ==} engines: {node: '>= 10.0.0'} + dev: true /unpipe@1.0.0: resolution: {integrity: sha512-pjy2bYhSsufwWlKwPc+l3cN7+wuJlK6uz0YdJEOlQDbl6jo/YlPi4mb8agUkVC8BF7V8NuzeyPNqRksA3hztKQ==} @@ -12971,6 +13049,7 @@ packages: hasBin: true dependencies: isexe: 2.0.0 + dev: true /wordwrap@1.0.0: resolution: {integrity: sha512-gvVzJFlPycKc5dZN4yPkP8w7Dc37BtP1yczEneOb4uq34pXZcvrtRTmWV8W+Ume+XCxKgbjM+nevkyFPMybd4Q==} @@ -12996,6 +13075,7 @@ packages: /wrappy@1.0.2: resolution: {integrity: sha512-l4Sp/DRseor9wL6EvV2+TuQn63dMkPjZ/sp9XkghTEbV9KlPS1xUsZ3u7/IQO4wxtcFB4bgpQPRcR3QCvezPcQ==} + dev: true /write-file-atomic@2.4.3: resolution: {integrity: sha512-GaETH5wwsX+GcnzhPgKcKjJ6M2Cq3/iZp1WyY/X1CSqrW+jVNM9Y7D8EC2sM4ZG/V8wZlSniJnCKWPmBYAucRQ==} @@ -13060,17 +13140,13 @@ packages: /yallist@4.0.0: resolution: {integrity: sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==} + dev: true /yaml@1.10.2: resolution: {integrity: sha512-r3vXyErRCYJ7wg28yvBY5VSoAF8ZvlcW9/BwUzEtUsjvX/DKs24dIkuwjtuprwJJHsbyUbLApepYTR1BN4uHrg==} engines: {node: '>= 6'} dev: false - /yaml@2.3.1: - resolution: {integrity: sha512-2eHWfjaoXgTBC2jNM1LRef62VQa0umtvRiDSk6HSzW7RvS5YtkabJrwYLLEKWBc8a5U2PTSCs+dJjUTJdlHsWQ==} - engines: {node: '>= 14'} - dev: false - /yargs-parser@21.1.1: resolution: {integrity: sha512-tVpsJW7DdjecAiFpbIB1e3qxIQsE6NoPc5/eTdrbbIC4h0LVsWhnoa3g+m2HclBIujHzsxZ4VJVA+GUuc2/LBw==} engines: {node: '>=12'} diff --git a/invokeai/frontend/web/public/locales/en.json b/invokeai/frontend/web/public/locales/en.json index f5f3f434f5..23dd8f9902 100644 --- a/invokeai/frontend/web/public/locales/en.json +++ b/invokeai/frontend/web/public/locales/en.json @@ -50,9 +50,33 @@ "uncategorized": "Uncategorized", "downloadBoard": "Download Board" }, + "accordions": { + "generation": { + "title": "Generation", + "modelTab": "Model", + "conceptsTab": "Concepts" + }, + "image": { + "title": "Image" + }, + "advanced": { + "title": "Advanced" + }, + "control": { + "title": "Control", + "controlAdaptersTab": "Control Adapters", + "ipTab": "Image Prompts" + }, + "compositing": { + "title": "Compositing", + "coherenceTab": "Coherence Pass", + "infillMaskTab": "Infill & Mask" + } + }, "common": { "accept": "Accept", "advanced": "Advanced", + "advancedOptions": "Advanced Options", "ai": "ai", "areYouSure": "Are you sure?", "auto": "Auto", @@ -79,6 +103,7 @@ "file": "File", "folder": "Folder", "format": "format", + "free": "Free", "generate": "Generate", "githubLabel": "Github", "hotkeysLabel": "Hotkeys", @@ -221,7 +246,6 @@ "colorMapTileSize": "Tile Size", "importImageFromCanvas": "Import Image From Canvas", "importMaskFromCanvas": "Import Mask From Canvas", - "incompatibleBaseModel": "Incompatible base model:", "lineart": "Lineart", "lineartAnime": "Lineart Anime", "lineartAnimeDescription": "Anime-style lineart processing", @@ -246,6 +270,7 @@ "prompt": "Prompt", "resetControlImage": "Reset Control Image", "resize": "Resize", + "resizeSimple": "Resize (Simple)", "resizeMode": "Resize Mode", "safe": "Safe", "saveControlImage": "Save Control Image", @@ -284,7 +309,7 @@ "queue": "Queue", "queueFront": "Add to Front of Queue", "queueBack": "Add to Queue", - "queueCountPrediction": "Add {{predicted}} to Queue", + "queueCountPrediction": "{{promptsCount}} prompts × {{iterations}} iterations -> {{count}} generations", "queueMaxExceeded": "Max of {{max_queue_size}} exceeded, would skip {{skip}}", "queuedCount": "{{pending}} Pending", "queueTotal": "{{total}} Total", @@ -788,17 +813,23 @@ }, "models": { "addLora": "Add LoRA", + "allLoRAsAdded": "All LoRAs added", + "loraAlreadyAdded": "LoRA already added", "esrganModel": "ESRGAN Model", "loading": "loading", + "incompatibleBaseModel": "Incompatible base model", + "noMainModelSelected": "No main model selected", "noLoRAsAvailable": "No LoRAs available", "noLoRAsLoaded": "No LoRAs Loaded", "noMatchingLoRAs": "No matching LoRAs", "noMatchingModels": "No matching Models", "noModelsAvailable": "No models available", + "lora": "LoRA", "selectLoRA": "Select a LoRA", "selectModel": "Select a Model", "noLoRAsInstalled": "No LoRAs installed", - "noRefinerModelsInstalled": "No SDXL Refiner models installed" + "noRefinerModelsInstalled": "No SDXL Refiner models installed", + "defaultVAE": "Default VAE" }, "nodes": { "addNode": "Add Node", @@ -1037,6 +1068,7 @@ "prototypeDesc": "This invocation is a prototype. It may have breaking changes during app updates and may be removed at any time." }, "parameters": { + "aspect": "Aspect", "aspectRatio": "Aspect Ratio", "aspectRatioFree": "Free", "boundingBoxHeader": "Bounding Box", @@ -1077,6 +1109,7 @@ "imageFit": "Fit Initial Image To Output Size", "images": "Images", "imageToImage": "Image to Image", + "imageSize": "Image Size", "img2imgStrength": "Image To Image Strength", "infillMethod": "Infill Method", "infillScalingHeader": "Infill and Scaling", @@ -1127,8 +1160,8 @@ "seamCorrectionHeader": "Seam Correction", "seamHighThreshold": "High", "seamlessTiling": "Seamless Tiling", - "seamlessXAxis": "X Axis", - "seamlessYAxis": "Y Axis", + "seamlessXAxis": "Seamless Tiling X Axis", + "seamlessYAxis": "Seamless Tiling Y Axis", "seamlessX": "Seamless X", "seamlessY": "Seamless Y", "seamlessX&Y": "Seamless X & Y", @@ -1171,6 +1204,7 @@ }, "dynamicPrompts": { "combinatorial": "Combinatorial Generation", + "showDynamicPrompts": "Show Dynamic Prompts", "dynamicPrompts": "Dynamic Prompts", "enableDynamicPrompts": "Enable Dynamic Prompts", "maxPrompts": "Max Prompts", @@ -1187,7 +1221,8 @@ }, "sdxl": { "cfgScale": "CFG Scale", - "concatPromptStyle": "Concatenate Prompt & Style", + "concatPromptStyle": "Concatenating Prompt & Style", + "freePromptStyle": "Manual Style Prompting", "denoisingStrength": "Denoising Strength", "loading": "Loading...", "negAestheticScore": "Negative Aesthetic Score", diff --git a/invokeai/frontend/web/scripts/typegen.js b/invokeai/frontend/web/scripts/typegen.js index 9e1b51eace..ce78e3e5ba 100644 --- a/invokeai/frontend/web/scripts/typegen.js +++ b/invokeai/frontend/web/scripts/typegen.js @@ -1,8 +1,9 @@ import fs from 'node:fs'; + import openapiTS from 'openapi-typescript'; const OPENAPI_URL = 'http://127.0.0.1:9090/openapi.json'; -const OUTPUT_FILE = 'src/services/api/schema.d.ts'; +const OUTPUT_FILE = 'src/services/api/schema.ts'; async function main() { process.stdout.write( diff --git a/invokeai/frontend/web/src/app/components/App.tsx b/invokeai/frontend/web/src/app/components/App.tsx index 73bd92ffab..f9e53f2ddd 100644 --- a/invokeai/frontend/web/src/app/components/App.tsx +++ b/invokeai/frontend/web/src/app/components/App.tsx @@ -1,13 +1,17 @@ import { Flex, Grid } from '@chakra-ui/react'; import { useStore } from '@nanostores/react'; +import { useSocketIO } from 'app/hooks/useSocketIO'; import { useLogger } from 'app/logging/useLogger'; import { appStarted } from 'app/store/middleware/listenerMiddleware/listeners/appStarted'; import { $headerComponent } from 'app/store/nanostores/headerComponent'; import { useAppDispatch, useAppSelector } from 'app/store/storeHooks'; -import { PartialAppConfig } from 'app/types/invokeai'; +import type { PartialAppConfig } from 'app/types/invokeai'; import ImageUploader from 'common/components/ImageUploader'; +import { useClearStorage } from 'common/hooks/useClearStorage'; +import { useGlobalModifiersInit } from 'common/hooks/useGlobalModifiers'; import ChangeBoardModal from 'features/changeBoardModal/components/ChangeBoardModal'; import DeleteImageModal from 'features/deleteImageModal/components/DeleteImageModal'; +import { DynamicPromptsModal } from 'features/dynamicPrompts/components/DynamicPromptsPreviewModal'; import SiteHeader from 'features/system/components/SiteHeader'; import { configChanged } from 'features/system/store/configSlice'; import { languageSelector } from 'features/system/store/systemSelectors'; @@ -16,12 +20,10 @@ import i18n from 'i18n'; import { size } from 'lodash-es'; import { memo, useCallback, useEffect } from 'react'; import { ErrorBoundary } from 'react-error-boundary'; + import AppErrorBoundaryFallback from './AppErrorBoundaryFallback'; -import GlobalHotkeys from './GlobalHotkeys'; import PreselectedImage from './PreselectedImage'; import Toaster from './Toaster'; -import { useSocketIO } from 'app/hooks/useSocketIO'; -import { useClearStorage } from 'common/hooks/useClearStorage'; const DEFAULT_CONFIG = {}; @@ -41,6 +43,7 @@ const App = ({ config = DEFAULT_CONFIG, selectedImage }: Props) => { // singleton! useSocketIO(); + useGlobalModifiersInit(); const handleReset = useCallback(() => { clearStorage(); @@ -96,8 +99,8 @@ const App = ({ config = DEFAULT_CONFIG, selectedImage }: Props) => { + - ); diff --git a/invokeai/frontend/web/src/app/components/AppErrorBoundaryFallback.tsx b/invokeai/frontend/web/src/app/components/AppErrorBoundaryFallback.tsx index 29f4016ad9..9a8a177f58 100644 --- a/invokeai/frontend/web/src/app/components/AppErrorBoundaryFallback.tsx +++ b/invokeai/frontend/web/src/app/components/AppErrorBoundaryFallback.tsx @@ -1,5 +1,6 @@ -import { Flex, Heading, Link, Text, useToast } from '@chakra-ui/react'; -import IAIButton from 'common/components/IAIButton'; +import { Flex, Heading, Link, useToast } from '@chakra-ui/react'; +import { InvButton } from 'common/components/InvButton/InvButton'; +import { InvText } from 'common/components/InvText/wrapper'; import newGithubIssueUrl from 'new-github-issue-url'; import { memo, useCallback, useMemo } from 'react'; import { useTranslation } from 'react-i18next'; @@ -67,30 +68,24 @@ const AppErrorBoundaryFallback = ({ error, resetErrorBoundary }: Props) => { alignItems: 'center', }} > - + {error.name}: {error.message} - + - } onClick={resetErrorBoundary} > {t('accessibility.resetUI')} - - } onClick={handleCopy}> + + } onClick={handleCopy}> {t('common.copyError')} - + - }> + }> {t('accessibility.createIssue')} - + diff --git a/invokeai/frontend/web/src/app/components/GlobalHotkeys.ts b/invokeai/frontend/web/src/app/components/GlobalHotkeys.ts deleted file mode 100644 index 211ecee81e..0000000000 --- a/invokeai/frontend/web/src/app/components/GlobalHotkeys.ts +++ /dev/null @@ -1,112 +0,0 @@ -import { createMemoizedSelector } from 'app/store/createMemoizedSelector'; -import { stateSelector } from 'app/store/store'; -import { useAppDispatch, useAppSelector } from 'app/store/storeHooks'; -import { useQueueBack } from 'features/queue/hooks/useQueueBack'; -import { useQueueFront } from 'features/queue/hooks/useQueueFront'; -import { - ctrlKeyPressed, - metaKeyPressed, - shiftKeyPressed, -} from 'features/ui/store/hotkeysSlice'; -import { setActiveTab } from 'features/ui/store/uiSlice'; -import React, { memo } from 'react'; -import { isHotkeyPressed, useHotkeys } from 'react-hotkeys-hook'; - -const globalHotkeysSelector = createMemoizedSelector( - [stateSelector], - ({ hotkeys }) => { - const { shift, ctrl, meta } = hotkeys; - return { shift, ctrl, meta }; - } -); - -// TODO: Does not catch keypresses while focused in an input. Maybe there is a way? - -/** - * Logical component. Handles app-level global hotkeys. - * @returns null - */ -const GlobalHotkeys: React.FC = () => { - const dispatch = useAppDispatch(); - const { shift, ctrl, meta } = useAppSelector(globalHotkeysSelector); - const { - queueBack, - isDisabled: isDisabledQueueBack, - isLoading: isLoadingQueueBack, - } = useQueueBack(); - - useHotkeys( - ['ctrl+enter', 'meta+enter'], - queueBack, - { - enabled: () => !isDisabledQueueBack && !isLoadingQueueBack, - preventDefault: true, - enableOnFormTags: ['input', 'textarea', 'select'], - }, - [queueBack, isDisabledQueueBack, isLoadingQueueBack] - ); - - const { - queueFront, - isDisabled: isDisabledQueueFront, - isLoading: isLoadingQueueFront, - } = useQueueFront(); - - useHotkeys( - ['ctrl+shift+enter', 'meta+shift+enter'], - queueFront, - { - enabled: () => !isDisabledQueueFront && !isLoadingQueueFront, - preventDefault: true, - enableOnFormTags: ['input', 'textarea', 'select'], - }, - [queueFront, isDisabledQueueFront, isLoadingQueueFront] - ); - - useHotkeys( - '*', - () => { - if (isHotkeyPressed('shift')) { - !shift && dispatch(shiftKeyPressed(true)); - } else { - shift && dispatch(shiftKeyPressed(false)); - } - if (isHotkeyPressed('ctrl')) { - !ctrl && dispatch(ctrlKeyPressed(true)); - } else { - ctrl && dispatch(ctrlKeyPressed(false)); - } - if (isHotkeyPressed('meta')) { - !meta && dispatch(metaKeyPressed(true)); - } else { - meta && dispatch(metaKeyPressed(false)); - } - }, - { keyup: true, keydown: true }, - [shift, ctrl, meta] - ); - - useHotkeys('1', () => { - dispatch(setActiveTab('txt2img')); - }); - - useHotkeys('2', () => { - dispatch(setActiveTab('img2img')); - }); - - useHotkeys('3', () => { - dispatch(setActiveTab('unifiedCanvas')); - }); - - useHotkeys('4', () => { - dispatch(setActiveTab('nodes')); - }); - - useHotkeys('5', () => { - dispatch(setActiveTab('modelManager')); - }); - - return null; -}; - -export default memo(GlobalHotkeys); diff --git a/invokeai/frontend/web/src/app/components/InvokeAIUI.tsx b/invokeai/frontend/web/src/app/components/InvokeAIUI.tsx index b190a36f06..e4ae4b61c6 100644 --- a/invokeai/frontend/web/src/app/components/InvokeAIUI.tsx +++ b/invokeai/frontend/web/src/app/components/InvokeAIUI.tsx @@ -1,29 +1,25 @@ -import { Middleware } from '@reduxjs/toolkit'; +import 'i18n'; + +import type { Middleware } from '@reduxjs/toolkit'; import { $socketOptions } from 'app/hooks/useSocketIO'; import { $authToken } from 'app/store/nanostores/authToken'; import { $baseUrl } from 'app/store/nanostores/baseUrl'; -import { $customStarUI, CustomStarUi } from 'app/store/nanostores/customStarUI'; +import type { CustomStarUi } from 'app/store/nanostores/customStarUI'; +import { $customStarUI } from 'app/store/nanostores/customStarUI'; import { $headerComponent } from 'app/store/nanostores/headerComponent'; import { $isDebugging } from 'app/store/nanostores/isDebugging'; import { $projectId } from 'app/store/nanostores/projectId'; import { $queueId, DEFAULT_QUEUE_ID } from 'app/store/nanostores/queueId'; import { $store } from 'app/store/nanostores/store'; import { createStore } from 'app/store/store'; -import { PartialAppConfig } from 'app/types/invokeai'; +import type { PartialAppConfig } from 'app/types/invokeai'; import Loading from 'common/components/Loading/Loading'; import AppDndContext from 'features/dnd/components/AppDndContext'; -import 'i18n'; -import React, { - PropsWithChildren, - ReactNode, - lazy, - memo, - useEffect, - useMemo, -} from 'react'; +import type { PropsWithChildren, ReactNode } from 'react'; +import React, { lazy, memo, useEffect, useMemo } from 'react'; import { Provider } from 'react-redux'; import { addMiddleware, resetMiddlewares } from 'redux-dynamic-middlewares'; -import { ManagerOptions, SocketOptions } from 'socket.io-client'; +import type { ManagerOptions, SocketOptions } from 'socket.io-client'; const App = lazy(() => import('./App')); const ThemeLocaleProvider = lazy(() => import('./ThemeLocaleProvider')); diff --git a/invokeai/frontend/web/src/app/components/ThemeLocaleProvider.tsx b/invokeai/frontend/web/src/app/components/ThemeLocaleProvider.tsx index ba0aaa5823..f2de4dc3be 100644 --- a/invokeai/frontend/web/src/app/components/ThemeLocaleProvider.tsx +++ b/invokeai/frontend/web/src/app/components/ThemeLocaleProvider.tsx @@ -1,24 +1,17 @@ -import { - ChakraProvider, - createLocalStorageManager, - extendTheme, -} from '@chakra-ui/react'; -import { ReactNode, memo, useEffect, useMemo } from 'react'; -import { useTranslation } from 'react-i18next'; -import { TOAST_OPTIONS, theme as invokeAITheme } from 'theme/theme'; - import '@fontsource-variable/inter'; -import { MantineProvider } from '@mantine/core'; -import { useMantineTheme } from 'mantine-theme/theme'; import 'overlayscrollbars/overlayscrollbars.css'; -import 'theme/css/overlayscrollbars.css'; +import 'common/components/OverlayScrollbars/overlayscrollbars.css'; + +import { ChakraProvider, extendTheme } from '@chakra-ui/react'; +import type { ReactNode } from 'react'; +import { memo, useEffect, useMemo } from 'react'; +import { useTranslation } from 'react-i18next'; +import { theme as invokeAITheme, TOAST_OPTIONS } from 'theme/theme'; type ThemeLocaleProviderProps = { children: ReactNode; }; -const manager = createLocalStorageManager('@@invokeai-color-mode'); - function ThemeLocaleProvider({ children }: ThemeLocaleProviderProps) { const { i18n } = useTranslation(); @@ -35,18 +28,10 @@ function ThemeLocaleProvider({ children }: ThemeLocaleProviderProps) { document.body.dir = direction; }, [direction]); - const mantineTheme = useMantineTheme(); - return ( - - - {children} - - + + {children} + ); } diff --git a/invokeai/frontend/web/src/app/components/Toaster.ts b/invokeai/frontend/web/src/app/components/Toaster.ts index e319bef59c..1ba47bdc8f 100644 --- a/invokeai/frontend/web/src/app/components/Toaster.ts +++ b/invokeai/frontend/web/src/app/components/Toaster.ts @@ -1,7 +1,8 @@ import { useToast } from '@chakra-ui/react'; import { useAppDispatch, useAppSelector } from 'app/store/storeHooks'; import { addToast, clearToastQueue } from 'features/system/store/systemSlice'; -import { MakeToastArg, makeToast } from 'features/system/util/makeToast'; +import type { MakeToastArg } from 'features/system/util/makeToast'; +import { makeToast } from 'features/system/util/makeToast'; import { memo, useCallback, useEffect } from 'react'; /** diff --git a/invokeai/frontend/web/src/app/features.ts b/invokeai/frontend/web/src/app/features.ts deleted file mode 100644 index bd6906f11c..0000000000 --- a/invokeai/frontend/web/src/app/features.ts +++ /dev/null @@ -1,94 +0,0 @@ -import { useMemo } from 'react'; -import { useTranslation } from 'react-i18next'; - -type FeatureHelpInfo = { - text: string; - href: string; - guideImage: string; -}; - -export enum Feature { - PROMPT, - GALLERY, - OTHER, - SEED, - VARIATIONS, - UPSCALE, - FACE_CORRECTION, - IMAGE_TO_IMAGE, - BOUNDING_BOX, - SEAM_CORRECTION, - INFILL_AND_SCALING, -} -/** For each tooltip in the UI, the below feature definitions & props will pull relevant information into the tooltip. - * - * To-do: href & GuideImages are placeholders, and are not currently utilized, but will be updated (along with the tooltip UI) as feature and UI develop and we get a better idea on where things "forever homes" will be . - */ -const useFeatures = (): Record => { - const { t } = useTranslation(); - return useMemo( - () => ({ - [Feature.PROMPT]: { - text: t('tooltip.feature.prompt'), - href: 'link/to/docs/feature3.html', - guideImage: 'asset/path.gif', - }, - [Feature.GALLERY]: { - text: t('tooltip.feature.gallery'), - href: 'link/to/docs/feature3.html', - guideImage: 'asset/path.gif', - }, - [Feature.OTHER]: { - text: t('tooltip.feature.other'), - href: 'link/to/docs/feature3.html', - guideImage: 'asset/path.gif', - }, - [Feature.SEED]: { - text: t('tooltip.feature.seed'), - href: 'link/to/docs/feature3.html', - guideImage: 'asset/path.gif', - }, - [Feature.VARIATIONS]: { - text: t('tooltip.feature.variations'), - href: 'link/to/docs/feature3.html', - guideImage: 'asset/path.gif', - }, - [Feature.UPSCALE]: { - text: t('tooltip.feature.upscale'), - href: 'link/to/docs/feature1.html', - guideImage: 'asset/path.gif', - }, - [Feature.FACE_CORRECTION]: { - text: t('tooltip.feature.faceCorrection'), - href: 'link/to/docs/feature3.html', - guideImage: 'asset/path.gif', - }, - [Feature.IMAGE_TO_IMAGE]: { - text: t('tooltip.feature.imageToImage'), - href: 'link/to/docs/feature3.html', - guideImage: 'asset/path.gif', - }, - [Feature.BOUNDING_BOX]: { - text: t('tooltip.feature.boundingBox'), - href: 'link/to/docs/feature3.html', - guideImage: 'asset/path.gif', - }, - [Feature.SEAM_CORRECTION]: { - text: t('tooltip.feature.seamCorrection'), - href: 'link/to/docs/feature3.html', - guideImage: 'asset/path.gif', - }, - [Feature.INFILL_AND_SCALING]: { - text: t('tooltip.feature.infillAndScaling'), - href: 'link/to/docs/feature3.html', - guideImage: 'asset/path.gif', - }, - }), - [t] - ); -}; - -export const useFeatureHelpInfo = (feature: Feature): FeatureHelpInfo => { - const features = useFeatures(); - return features[feature]; -}; diff --git a/invokeai/frontend/web/src/app/hooks/useSocketIO.ts b/invokeai/frontend/web/src/app/hooks/useSocketIO.ts index b2f08b2815..dffdbf6ca2 100644 --- a/invokeai/frontend/web/src/app/hooks/useSocketIO.ts +++ b/invokeai/frontend/web/src/app/hooks/useSocketIO.ts @@ -3,14 +3,16 @@ import { $authToken } from 'app/store/nanostores/authToken'; import { $baseUrl } from 'app/store/nanostores/baseUrl'; import { $isDebugging } from 'app/store/nanostores/isDebugging'; import { useAppDispatch } from 'app/store/storeHooks'; -import { MapStore, atom, map } from 'nanostores'; +import type { MapStore } from 'nanostores'; +import { atom, map } from 'nanostores'; import { useEffect, useMemo } from 'react'; -import { +import type { ClientToServerEvents, ServerToClientEvents, } from 'services/events/types'; import { setEventListeners } from 'services/events/util/setEventListeners'; -import { ManagerOptions, Socket, SocketOptions, io } from 'socket.io-client'; +import type { ManagerOptions, Socket, SocketOptions } from 'socket.io-client'; +import { io } from 'socket.io-client'; // Inject socket options and url into window for debugging declare global { diff --git a/invokeai/frontend/web/src/app/logging/logger.ts b/invokeai/frontend/web/src/app/logging/logger.ts index 0e0a1a7324..c0696c1f6a 100644 --- a/invokeai/frontend/web/src/app/logging/logger.ts +++ b/invokeai/frontend/web/src/app/logging/logger.ts @@ -1,6 +1,8 @@ import { createLogWriter } from '@roarr/browser-log-writer'; import { atom } from 'nanostores'; -import { Logger, ROARR, Roarr } from 'roarr'; +import type { Logger } from 'roarr'; +import { ROARR, Roarr } from 'roarr'; +import { z } from 'zod'; ROARR.write = createLogWriter(); @@ -26,19 +28,20 @@ export type LoggerNamespace = export const logger = (namespace: LoggerNamespace) => $logger.get().child({ namespace }); -export const VALID_LOG_LEVELS = [ +export const zLogLevel = z.enum([ 'trace', 'debug', 'info', 'warn', 'error', 'fatal', -] as const; - -export type InvokeLogLevel = (typeof VALID_LOG_LEVELS)[number]; +]); +export type LogLevel = z.infer; +export const isLogLevel = (v: unknown): v is LogLevel => + zLogLevel.safeParse(v).success; // Translate human-readable log levels to numbers, used for log filtering -export const LOG_LEVEL_MAP: Record = { +export const LOG_LEVEL_MAP: Record = { trace: 10, debug: 20, info: 30, diff --git a/invokeai/frontend/web/src/app/logging/useLogger.ts b/invokeai/frontend/web/src/app/logging/useLogger.ts index 1ec564d333..5028935514 100644 --- a/invokeai/frontend/web/src/app/logging/useLogger.ts +++ b/invokeai/frontend/web/src/app/logging/useLogger.ts @@ -4,13 +4,9 @@ import { stateSelector } from 'app/store/store'; import { useAppSelector } from 'app/store/storeHooks'; import { useEffect, useMemo } from 'react'; import { ROARR, Roarr } from 'roarr'; -import { - $logger, - BASE_CONTEXT, - LOG_LEVEL_MAP, - LoggerNamespace, - logger, -} from './logger'; + +import type { LoggerNamespace } from './logger'; +import { $logger, BASE_CONTEXT, LOG_LEVEL_MAP, logger } from './logger'; const selector = createMemoizedSelector(stateSelector, ({ system }) => { const { consoleLogLevel, shouldLogToConsole } = system; diff --git a/invokeai/frontend/web/src/app/store/actions.ts b/invokeai/frontend/web/src/app/store/actions.ts index 418440a5fb..0800d1a63b 100644 --- a/invokeai/frontend/web/src/app/store/actions.ts +++ b/invokeai/frontend/web/src/app/store/actions.ts @@ -1,6 +1,6 @@ import { createAction } from '@reduxjs/toolkit'; -import { InvokeTabName } from 'features/ui/store/tabMap'; -import { BatchConfig } from 'services/api/types'; +import type { InvokeTabName } from 'features/ui/store/tabMap'; +import type { BatchConfig } from 'services/api/types'; export const enqueueRequested = createAction<{ tabName: InvokeTabName; diff --git a/invokeai/frontend/web/src/app/store/enhancers/reduxRemember/serialize.ts b/invokeai/frontend/web/src/app/store/enhancers/reduxRemember/serialize.ts index 4741f08b16..7b5e1cef5d 100644 --- a/invokeai/frontend/web/src/app/store/enhancers/reduxRemember/serialize.ts +++ b/invokeai/frontend/web/src/app/store/enhancers/reduxRemember/serialize.ts @@ -8,7 +8,7 @@ import { postprocessingPersistDenylist } from 'features/parameters/store/postpro import { systemPersistDenylist } from 'features/system/store/systemPersistDenylist'; import { uiPersistDenylist } from 'features/ui/store/uiPersistDenylist'; import { omit } from 'lodash-es'; -import { SerializeFunction } from 'redux-remember'; +import type { SerializeFunction } from 'redux-remember'; const serializationDenylist: { [key: string]: string[]; diff --git a/invokeai/frontend/web/src/app/store/enhancers/reduxRemember/unserialize.ts b/invokeai/frontend/web/src/app/store/enhancers/reduxRemember/unserialize.ts index 0dcc9e5971..247961fed9 100644 --- a/invokeai/frontend/web/src/app/store/enhancers/reduxRemember/unserialize.ts +++ b/invokeai/frontend/web/src/app/store/enhancers/reduxRemember/unserialize.ts @@ -11,7 +11,7 @@ import { initialSystemState } from 'features/system/store/systemSlice'; import { initialHotkeysState } from 'features/ui/store/hotkeysSlice'; import { initialUIState } from 'features/ui/store/uiSlice'; import { defaultsDeep } from 'lodash-es'; -import { UnserializeFunction } from 'redux-remember'; +import type { UnserializeFunction } from 'redux-remember'; const initialStates: { [key: string]: object; // TODO: type this properly diff --git a/invokeai/frontend/web/src/app/store/middleware/devtools/actionSanitizer.ts b/invokeai/frontend/web/src/app/store/middleware/devtools/actionSanitizer.ts index 08f98f4f7e..da5fb224d2 100644 --- a/invokeai/frontend/web/src/app/store/middleware/devtools/actionSanitizer.ts +++ b/invokeai/frontend/web/src/app/store/middleware/devtools/actionSanitizer.ts @@ -1,8 +1,8 @@ -import { UnknownAction } from '@reduxjs/toolkit'; +import type { UnknownAction } from '@reduxjs/toolkit'; import { isAnyGraphBuilt } from 'features/nodes/store/actions'; import { nodeTemplatesBuilt } from 'features/nodes/store/nodesSlice'; import { receivedOpenAPISchema } from 'services/api/thunks/schema'; -import { Graph } from 'services/api/types'; +import type { Graph } from 'services/api/types'; export const actionSanitizer = (action: A): A => { if (isAnyGraphBuilt(action)) { diff --git a/invokeai/frontend/web/src/app/store/middleware/listenerMiddleware/index.ts b/invokeai/frontend/web/src/app/store/middleware/listenerMiddleware/index.ts index 8bcdd236e0..c3fdefbab9 100644 --- a/invokeai/frontend/web/src/app/store/middleware/listenerMiddleware/index.ts +++ b/invokeai/frontend/web/src/app/store/middleware/listenerMiddleware/index.ts @@ -1,11 +1,12 @@ -import type { TypedAddListener, TypedStartListening } from '@reduxjs/toolkit'; -import { - UnknownAction, +import type { ListenerEffect, - addListener, - createListenerMiddleware, + TypedAddListener, + TypedStartListening, + UnknownAction, } from '@reduxjs/toolkit'; +import { addListener, createListenerMiddleware } from '@reduxjs/toolkit'; import type { AppDispatch, RootState } from 'app/store/store'; + import { addCommitStagingAreaImageListener } from './listeners/addCommitStagingAreaImageListener'; import { addFirstListImagesListener } from './listeners/addFirstListImagesListener.ts'; import { addAnyEnqueuedListener } from './listeners/anyEnqueued'; @@ -42,13 +43,13 @@ import { addImageRemovedFromBoardFulfilledListener, addImageRemovedFromBoardRejectedListener, } from './listeners/imageRemovedFromBoard'; +import { addImagesStarredListener } from './listeners/imagesStarred'; +import { addImagesUnstarredListener } from './listeners/imagesUnstarred'; import { addImageToDeleteSelectedListener } from './listeners/imageToDeleteSelected'; import { addImageUploadedFulfilledListener, addImageUploadedRejectedListener, } from './listeners/imageUploaded'; -import { addImagesStarredListener } from './listeners/imagesStarred'; -import { addImagesUnstarredListener } from './listeners/imagesUnstarred'; import { addInitialImageSelectedListener } from './listeners/initialImageSelected'; import { addModelSelectedListener } from './listeners/modelSelected'; import { addModelsLoadedListener } from './listeners/modelsLoaded'; @@ -69,9 +70,9 @@ import { addSocketSubscribedEventListener as addSocketSubscribedListener } from import { addSocketUnsubscribedEventListener as addSocketUnsubscribedListener } from './listeners/socketio/socketUnsubscribed'; import { addStagingAreaImageSavedListener } from './listeners/stagingAreaImageSaved'; import { addTabChangedListener } from './listeners/tabChanged'; +import { addUpdateAllNodesRequestedListener } from './listeners/updateAllNodesRequested'; import { addUpscaleRequestedListener } from './listeners/upscaleRequested'; import { addWorkflowLoadRequestedListener } from './listeners/workflowLoadRequested'; -import { addUpdateAllNodesRequestedListener } from './listeners/updateAllNodesRequested'; export const listenerMiddleware = createListenerMiddleware(); diff --git a/invokeai/frontend/web/src/app/store/middleware/listenerMiddleware/listeners/addCommitStagingAreaImageListener.ts b/invokeai/frontend/web/src/app/store/middleware/listenerMiddleware/listeners/addCommitStagingAreaImageListener.ts index d302d50255..2dbf68a837 100644 --- a/invokeai/frontend/web/src/app/store/middleware/listenerMiddleware/listeners/addCommitStagingAreaImageListener.ts +++ b/invokeai/frontend/web/src/app/store/middleware/listenerMiddleware/listeners/addCommitStagingAreaImageListener.ts @@ -8,6 +8,7 @@ import { import { addToast } from 'features/system/store/systemSlice'; import { t } from 'i18next'; import { queueApi } from 'services/api/endpoints/queue'; + import { startAppListening } from '..'; const matcher = isAnyOf(commitStagingAreaImage, discardStagedImages); diff --git a/invokeai/frontend/web/src/app/store/middleware/listenerMiddleware/listeners/addFirstListImagesListener.ts.ts b/invokeai/frontend/web/src/app/store/middleware/listenerMiddleware/listeners/addFirstListImagesListener.ts.ts index 15e7d48708..82f1cbeb03 100644 --- a/invokeai/frontend/web/src/app/store/middleware/listenerMiddleware/listeners/addFirstListImagesListener.ts.ts +++ b/invokeai/frontend/web/src/app/store/middleware/listenerMiddleware/listeners/addFirstListImagesListener.ts.ts @@ -2,9 +2,10 @@ import { createAction } from '@reduxjs/toolkit'; import { imageSelected } from 'features/gallery/store/gallerySlice'; import { IMAGE_CATEGORIES } from 'features/gallery/store/types'; import { imagesApi } from 'services/api/endpoints/images'; -import { startAppListening } from '..'; +import type { ImageCache } from 'services/api/types'; import { getListImagesUrl, imagesAdapter } from 'services/api/util'; -import { ImageCache } from 'services/api/types'; + +import { startAppListening } from '..'; export const appStarted = createAction('app/appStarted'); diff --git a/invokeai/frontend/web/src/app/store/middleware/listenerMiddleware/listeners/anyEnqueued.ts b/invokeai/frontend/web/src/app/store/middleware/listenerMiddleware/listeners/anyEnqueued.ts index 3f0e3342f9..fa4ad727c4 100644 --- a/invokeai/frontend/web/src/app/store/middleware/listenerMiddleware/listeners/anyEnqueued.ts +++ b/invokeai/frontend/web/src/app/store/middleware/listenerMiddleware/listeners/anyEnqueued.ts @@ -1,4 +1,5 @@ import { queueApi } from 'services/api/endpoints/queue'; + import { startAppListening } from '..'; export const addAnyEnqueuedListener = () => { diff --git a/invokeai/frontend/web/src/app/store/middleware/listenerMiddleware/listeners/appConfigReceived.ts b/invokeai/frontend/web/src/app/store/middleware/listenerMiddleware/listeners/appConfigReceived.ts index 700b4e7626..52090f7ab7 100644 --- a/invokeai/frontend/web/src/app/store/middleware/listenerMiddleware/listeners/appConfigReceived.ts +++ b/invokeai/frontend/web/src/app/store/middleware/listenerMiddleware/listeners/appConfigReceived.ts @@ -4,6 +4,7 @@ import { shouldUseWatermarkerChanged, } from 'features/system/store/systemSlice'; import { appInfoApi } from 'services/api/endpoints/appInfo'; + import { startAppListening } from '..'; export const addAppConfigReceivedListener = () => { diff --git a/invokeai/frontend/web/src/app/store/middleware/listenerMiddleware/listeners/appStarted.ts b/invokeai/frontend/web/src/app/store/middleware/listenerMiddleware/listeners/appStarted.ts index 189a5a3530..9cbd1c4aca 100644 --- a/invokeai/frontend/web/src/app/store/middleware/listenerMiddleware/listeners/appStarted.ts +++ b/invokeai/frontend/web/src/app/store/middleware/listenerMiddleware/listeners/appStarted.ts @@ -1,4 +1,5 @@ import { createAction } from '@reduxjs/toolkit'; + import { startAppListening } from '..'; export const appStarted = createAction('app/appStarted'); diff --git a/invokeai/frontend/web/src/app/store/middleware/listenerMiddleware/listeners/batchEnqueued.ts b/invokeai/frontend/web/src/app/store/middleware/listenerMiddleware/listeners/batchEnqueued.ts index 99756cbadb..1e8608d884 100644 --- a/invokeai/frontend/web/src/app/store/middleware/listenerMiddleware/listeners/batchEnqueued.ts +++ b/invokeai/frontend/web/src/app/store/middleware/listenerMiddleware/listeners/batchEnqueued.ts @@ -5,7 +5,8 @@ import { zPydanticValidationError } from 'features/system/store/zodSchemas'; import { t } from 'i18next'; import { truncate, upperFirst } from 'lodash-es'; import { queueApi } from 'services/api/endpoints/queue'; -import { TOAST_OPTIONS, theme } from 'theme/theme'; +import { theme, TOAST_OPTIONS } from 'theme/theme'; + import { startAppListening } from '..'; const { toast } = createStandaloneToast({ diff --git a/invokeai/frontend/web/src/app/store/middleware/listenerMiddleware/listeners/boardAndImagesDeleted.ts b/invokeai/frontend/web/src/app/store/middleware/listenerMiddleware/listeners/boardAndImagesDeleted.ts index a1be8de312..19346f5acd 100644 --- a/invokeai/frontend/web/src/app/store/middleware/listenerMiddleware/listeners/boardAndImagesDeleted.ts +++ b/invokeai/frontend/web/src/app/store/middleware/listenerMiddleware/listeners/boardAndImagesDeleted.ts @@ -4,6 +4,7 @@ import { getImageUsage } from 'features/deleteImageModal/store/selectors'; import { nodeEditorReset } from 'features/nodes/store/nodesSlice'; import { clearInitialImage } from 'features/parameters/store/generationSlice'; import { imagesApi } from 'services/api/endpoints/images'; + import { startAppListening } from '..'; export const addDeleteBoardAndImagesFulfilledListener = () => { diff --git a/invokeai/frontend/web/src/app/store/middleware/listenerMiddleware/listeners/boardIdSelected.ts b/invokeai/frontend/web/src/app/store/middleware/listenerMiddleware/listeners/boardIdSelected.ts index 9e8844f9fe..0bf5e9e264 100644 --- a/invokeai/frontend/web/src/app/store/middleware/listenerMiddleware/listeners/boardIdSelected.ts +++ b/invokeai/frontend/web/src/app/store/middleware/listenerMiddleware/listeners/boardIdSelected.ts @@ -9,9 +9,10 @@ import { IMAGE_CATEGORIES, } from 'features/gallery/store/types'; import { imagesApi } from 'services/api/endpoints/images'; -import { startAppListening } from '..'; import { imagesSelectors } from 'services/api/util'; +import { startAppListening } from '..'; + export const addBoardIdSelectedListener = () => { startAppListening({ matcher: isAnyOf(boardIdSelected, galleryViewChanged), diff --git a/invokeai/frontend/web/src/app/store/middleware/listenerMiddleware/listeners/canvasCopiedToClipboard.ts b/invokeai/frontend/web/src/app/store/middleware/listenerMiddleware/listeners/canvasCopiedToClipboard.ts index 1ac80d219b..ec2c2388e5 100644 --- a/invokeai/frontend/web/src/app/store/middleware/listenerMiddleware/listeners/canvasCopiedToClipboard.ts +++ b/invokeai/frontend/web/src/app/store/middleware/listenerMiddleware/listeners/canvasCopiedToClipboard.ts @@ -1,11 +1,12 @@ -import { canvasCopiedToClipboard } from 'features/canvas/store/actions'; -import { startAppListening } from '..'; import { $logger } from 'app/logging/logger'; +import { canvasCopiedToClipboard } from 'features/canvas/store/actions'; import { getBaseLayerBlob } from 'features/canvas/util/getBaseLayerBlob'; import { addToast } from 'features/system/store/systemSlice'; import { copyBlobToClipboard } from 'features/system/util/copyBlobToClipboard'; import { t } from 'i18next'; +import { startAppListening } from '..'; + export const addCanvasCopiedToClipboardListener = () => { startAppListening({ actionCreator: canvasCopiedToClipboard, diff --git a/invokeai/frontend/web/src/app/store/middleware/listenerMiddleware/listeners/canvasDownloadedAsImage.ts b/invokeai/frontend/web/src/app/store/middleware/listenerMiddleware/listeners/canvasDownloadedAsImage.ts index cfaf20b64c..0cbdb8bfcc 100644 --- a/invokeai/frontend/web/src/app/store/middleware/listenerMiddleware/listeners/canvasDownloadedAsImage.ts +++ b/invokeai/frontend/web/src/app/store/middleware/listenerMiddleware/listeners/canvasDownloadedAsImage.ts @@ -1,11 +1,12 @@ -import { canvasDownloadedAsImage } from 'features/canvas/store/actions'; -import { startAppListening } from '..'; import { $logger } from 'app/logging/logger'; +import { canvasDownloadedAsImage } from 'features/canvas/store/actions'; import { downloadBlob } from 'features/canvas/util/downloadBlob'; import { getBaseLayerBlob } from 'features/canvas/util/getBaseLayerBlob'; import { addToast } from 'features/system/store/systemSlice'; import { t } from 'i18next'; +import { startAppListening } from '..'; + export const addCanvasDownloadedAsImageListener = () => { startAppListening({ actionCreator: canvasDownloadedAsImage, diff --git a/invokeai/frontend/web/src/app/store/middleware/listenerMiddleware/listeners/canvasImageToControlNet.ts b/invokeai/frontend/web/src/app/store/middleware/listenerMiddleware/listeners/canvasImageToControlNet.ts index 01eda311e5..b9b08d2b4e 100644 --- a/invokeai/frontend/web/src/app/store/middleware/listenerMiddleware/listeners/canvasImageToControlNet.ts +++ b/invokeai/frontend/web/src/app/store/middleware/listenerMiddleware/listeners/canvasImageToControlNet.ts @@ -1,11 +1,12 @@ import { logger } from 'app/logging/logger'; +import { canvasImageToControlAdapter } from 'features/canvas/store/actions'; import { getBaseLayerBlob } from 'features/canvas/util/getBaseLayerBlob'; import { controlAdapterImageChanged } from 'features/controlAdapters/store/controlAdaptersSlice'; import { addToast } from 'features/system/store/systemSlice'; import { t } from 'i18next'; import { imagesApi } from 'services/api/endpoints/images'; + import { startAppListening } from '..'; -import { canvasImageToControlAdapter } from 'features/canvas/store/actions'; export const addCanvasImageToControlNetListener = () => { startAppListening({ diff --git a/invokeai/frontend/web/src/app/store/middleware/listenerMiddleware/listeners/canvasMaskSavedToGallery.ts b/invokeai/frontend/web/src/app/store/middleware/listenerMiddleware/listeners/canvasMaskSavedToGallery.ts index f814d94f3a..d8a3c3827d 100644 --- a/invokeai/frontend/web/src/app/store/middleware/listenerMiddleware/listeners/canvasMaskSavedToGallery.ts +++ b/invokeai/frontend/web/src/app/store/middleware/listenerMiddleware/listeners/canvasMaskSavedToGallery.ts @@ -2,9 +2,10 @@ import { logger } from 'app/logging/logger'; import { canvasMaskSavedToGallery } from 'features/canvas/store/actions'; import { getCanvasData } from 'features/canvas/util/getCanvasData'; import { addToast } from 'features/system/store/systemSlice'; -import { imagesApi } from 'services/api/endpoints/images'; -import { startAppListening } from '..'; import { t } from 'i18next'; +import { imagesApi } from 'services/api/endpoints/images'; + +import { startAppListening } from '..'; export const addCanvasMaskSavedToGalleryListener = () => { startAppListening({ diff --git a/invokeai/frontend/web/src/app/store/middleware/listenerMiddleware/listeners/canvasMaskToControlNet.ts b/invokeai/frontend/web/src/app/store/middleware/listenerMiddleware/listeners/canvasMaskToControlNet.ts index ccd5a3972b..cf1658cb41 100644 --- a/invokeai/frontend/web/src/app/store/middleware/listenerMiddleware/listeners/canvasMaskToControlNet.ts +++ b/invokeai/frontend/web/src/app/store/middleware/listenerMiddleware/listeners/canvasMaskToControlNet.ts @@ -5,6 +5,7 @@ import { controlAdapterImageChanged } from 'features/controlAdapters/store/contr import { addToast } from 'features/system/store/systemSlice'; import { t } from 'i18next'; import { imagesApi } from 'services/api/endpoints/images'; + import { startAppListening } from '..'; export const addCanvasMaskToControlNetListener = () => { diff --git a/invokeai/frontend/web/src/app/store/middleware/listenerMiddleware/listeners/canvasMerged.ts b/invokeai/frontend/web/src/app/store/middleware/listenerMiddleware/listeners/canvasMerged.ts index 35c1affb97..defbb04402 100644 --- a/invokeai/frontend/web/src/app/store/middleware/listenerMiddleware/listeners/canvasMerged.ts +++ b/invokeai/frontend/web/src/app/store/middleware/listenerMiddleware/listeners/canvasMerged.ts @@ -4,9 +4,10 @@ import { setMergedCanvas } from 'features/canvas/store/canvasSlice'; import { getFullBaseLayerBlob } from 'features/canvas/util/getFullBaseLayerBlob'; import { getCanvasBaseLayer } from 'features/canvas/util/konvaInstanceProvider'; import { addToast } from 'features/system/store/systemSlice'; -import { imagesApi } from 'services/api/endpoints/images'; -import { startAppListening } from '..'; import { t } from 'i18next'; +import { imagesApi } from 'services/api/endpoints/images'; + +import { startAppListening } from '..'; export const addCanvasMergedListener = () => { startAppListening({ diff --git a/invokeai/frontend/web/src/app/store/middleware/listenerMiddleware/listeners/canvasSavedToGallery.ts b/invokeai/frontend/web/src/app/store/middleware/listenerMiddleware/listeners/canvasSavedToGallery.ts index 23e2cebe53..f09cbe12d1 100644 --- a/invokeai/frontend/web/src/app/store/middleware/listenerMiddleware/listeners/canvasSavedToGallery.ts +++ b/invokeai/frontend/web/src/app/store/middleware/listenerMiddleware/listeners/canvasSavedToGallery.ts @@ -2,9 +2,10 @@ import { logger } from 'app/logging/logger'; import { canvasSavedToGallery } from 'features/canvas/store/actions'; import { getBaseLayerBlob } from 'features/canvas/util/getBaseLayerBlob'; import { addToast } from 'features/system/store/systemSlice'; -import { imagesApi } from 'services/api/endpoints/images'; -import { startAppListening } from '..'; import { t } from 'i18next'; +import { imagesApi } from 'services/api/endpoints/images'; + +import { startAppListening } from '..'; export const addCanvasSavedToGalleryListener = () => { startAppListening({ diff --git a/invokeai/frontend/web/src/app/store/middleware/listenerMiddleware/listeners/controlNetAutoProcess.ts b/invokeai/frontend/web/src/app/store/middleware/listenerMiddleware/listeners/controlNetAutoProcess.ts index b16c2d8556..8f5e2964d5 100644 --- a/invokeai/frontend/web/src/app/store/middleware/listenerMiddleware/listeners/controlNetAutoProcess.ts +++ b/invokeai/frontend/web/src/app/store/middleware/listenerMiddleware/listeners/controlNetAutoProcess.ts @@ -1,6 +1,6 @@ -import { AnyListenerPredicate } from '@reduxjs/toolkit'; +import type { AnyListenerPredicate } from '@reduxjs/toolkit'; import { logger } from 'app/logging/logger'; -import { RootState } from 'app/store/store'; +import type { RootState } from 'app/store/store'; import { controlAdapterImageProcessed } from 'features/controlAdapters/store/actions'; import { controlAdapterAutoConfigToggled, @@ -10,9 +10,10 @@ import { controlAdapterProcessortTypeChanged, selectControlAdapterById, } from 'features/controlAdapters/store/controlAdaptersSlice'; -import { startAppListening } from '..'; import { isControlNetOrT2IAdapter } from 'features/controlAdapters/store/types'; +import { startAppListening } from '..'; + type AnyControlAdapterParamChangeAction = | ReturnType | ReturnType diff --git a/invokeai/frontend/web/src/app/store/middleware/listenerMiddleware/listeners/controlNetImageProcessed.ts b/invokeai/frontend/web/src/app/store/middleware/listenerMiddleware/listeners/controlNetImageProcessed.ts index 3d35caebf6..61316231cc 100644 --- a/invokeai/frontend/web/src/app/store/middleware/listenerMiddleware/listeners/controlNetImageProcessed.ts +++ b/invokeai/frontend/web/src/app/store/middleware/listenerMiddleware/listeners/controlNetImageProcessed.ts @@ -8,14 +8,15 @@ import { selectControlAdapterById, } from 'features/controlAdapters/store/controlAdaptersSlice'; import { isControlNetOrT2IAdapter } from 'features/controlAdapters/store/types'; +import { isImageOutput } from 'features/nodes/types/common'; import { addToast } from 'features/system/store/systemSlice'; import { t } from 'i18next'; import { imagesApi } from 'services/api/endpoints/images'; import { queueApi } from 'services/api/endpoints/queue'; -import { BatchConfig, ImageDTO } from 'services/api/types'; +import type { BatchConfig, ImageDTO } from 'services/api/types'; import { socketInvocationComplete } from 'services/events/actions'; + import { startAppListening } from '..'; -import { isImageOutput } from 'features/nodes/types/common'; export const addControlNetImageProcessedListener = () => { startAppListening({ diff --git a/invokeai/frontend/web/src/app/store/middleware/listenerMiddleware/listeners/enqueueRequestedCanvas.ts b/invokeai/frontend/web/src/app/store/middleware/listenerMiddleware/listeners/enqueueRequestedCanvas.ts index bcaf778b6e..a803441c59 100644 --- a/invokeai/frontend/web/src/app/store/middleware/listenerMiddleware/listeners/enqueueRequestedCanvas.ts +++ b/invokeai/frontend/web/src/app/store/middleware/listenerMiddleware/listeners/enqueueRequestedCanvas.ts @@ -14,7 +14,8 @@ import { buildCanvasGraph } from 'features/nodes/util/graph/buildCanvasGraph'; import { prepareLinearUIBatch } from 'features/nodes/util/graph/buildLinearBatchConfig'; import { imagesApi } from 'services/api/endpoints/images'; import { queueApi } from 'services/api/endpoints/queue'; -import { ImageDTO } from 'services/api/types'; +import type { ImageDTO } from 'services/api/types'; + import { startAppListening } from '..'; /** diff --git a/invokeai/frontend/web/src/app/store/middleware/listenerMiddleware/listeners/enqueueRequestedLinear.ts b/invokeai/frontend/web/src/app/store/middleware/listenerMiddleware/listeners/enqueueRequestedLinear.ts index faeecfb44c..547f5e5948 100644 --- a/invokeai/frontend/web/src/app/store/middleware/listenerMiddleware/listeners/enqueueRequestedLinear.ts +++ b/invokeai/frontend/web/src/app/store/middleware/listenerMiddleware/listeners/enqueueRequestedLinear.ts @@ -5,6 +5,7 @@ import { buildLinearSDXLImageToImageGraph } from 'features/nodes/util/graph/buil import { buildLinearSDXLTextToImageGraph } from 'features/nodes/util/graph/buildLinearSDXLTextToImageGraph'; import { buildLinearTextToImageGraph } from 'features/nodes/util/graph/buildLinearTextToImageGraph'; import { queueApi } from 'services/api/endpoints/queue'; + import { startAppListening } from '..'; export const addEnqueueRequestedLinear = () => { diff --git a/invokeai/frontend/web/src/app/store/middleware/listenerMiddleware/listeners/enqueueRequestedNodes.ts b/invokeai/frontend/web/src/app/store/middleware/listenerMiddleware/listeners/enqueueRequestedNodes.ts index 30c568342a..7fd98b890c 100644 --- a/invokeai/frontend/web/src/app/store/middleware/listenerMiddleware/listeners/enqueueRequestedNodes.ts +++ b/invokeai/frontend/web/src/app/store/middleware/listenerMiddleware/listeners/enqueueRequestedNodes.ts @@ -2,7 +2,8 @@ import { enqueueRequested } from 'app/store/actions'; import { buildNodesGraph } from 'features/nodes/util/graph/buildNodesGraph'; import { buildWorkflow } from 'features/nodes/util/workflow/buildWorkflow'; import { queueApi } from 'services/api/endpoints/queue'; -import { BatchConfig } from 'services/api/types'; +import type { BatchConfig } from 'services/api/types'; + import { startAppListening } from '..'; export const addEnqueueRequestedNodes = () => { diff --git a/invokeai/frontend/web/src/app/store/middleware/listenerMiddleware/listeners/imageAddedToBoard.ts b/invokeai/frontend/web/src/app/store/middleware/listenerMiddleware/listeners/imageAddedToBoard.ts index 039cbb657a..61da8ff669 100644 --- a/invokeai/frontend/web/src/app/store/middleware/listenerMiddleware/listeners/imageAddedToBoard.ts +++ b/invokeai/frontend/web/src/app/store/middleware/listenerMiddleware/listeners/imageAddedToBoard.ts @@ -1,5 +1,6 @@ import { logger } from 'app/logging/logger'; import { imagesApi } from 'services/api/endpoints/images'; + import { startAppListening } from '..'; export const addImageAddedToBoardFulfilledListener = () => { diff --git a/invokeai/frontend/web/src/app/store/middleware/listenerMiddleware/listeners/imageDeleted.ts b/invokeai/frontend/web/src/app/store/middleware/listenerMiddleware/listeners/imageDeleted.ts index f23b7284fe..bbceb016f9 100644 --- a/invokeai/frontend/web/src/app/store/middleware/listenerMiddleware/listeners/imageDeleted.ts +++ b/invokeai/frontend/web/src/app/store/middleware/listenerMiddleware/listeners/imageDeleted.ts @@ -18,6 +18,7 @@ import { clamp, forEach } from 'lodash-es'; import { api } from 'services/api'; import { imagesApi } from 'services/api/endpoints/images'; import { imagesAdapter } from 'services/api/util'; + import { startAppListening } from '..'; export const addRequestedSingleImageDeletionListener = () => { diff --git a/invokeai/frontend/web/src/app/store/middleware/listenerMiddleware/listeners/imageDropped.ts b/invokeai/frontend/web/src/app/store/middleware/listenerMiddleware/listeners/imageDropped.ts index 0ea5caf1d6..452f599fd4 100644 --- a/invokeai/frontend/web/src/app/store/middleware/listenerMiddleware/listeners/imageDropped.ts +++ b/invokeai/frontend/web/src/app/store/middleware/listenerMiddleware/listeners/imageDropped.ts @@ -6,16 +6,17 @@ import { controlAdapterImageChanged, controlAdapterIsEnabledChanged, } from 'features/controlAdapters/store/controlAdaptersSlice'; -import { +import type { TypesafeDraggableData, TypesafeDroppableData, } from 'features/dnd/types'; import { imageSelected } from 'features/gallery/store/gallerySlice'; import { fieldImageValueChanged } from 'features/nodes/store/nodesSlice'; +import { workflowExposedFieldAdded } from 'features/nodes/store/workflowSlice'; import { initialImageChanged } from 'features/parameters/store/generationSlice'; import { imagesApi } from 'services/api/endpoints/images'; + import { startAppListening } from '../'; -import { workflowExposedFieldAdded } from 'features/nodes/store/workflowSlice'; export const dndDropped = createAction<{ overData: TypesafeDroppableData; diff --git a/invokeai/frontend/web/src/app/store/middleware/listenerMiddleware/listeners/imageRemovedFromBoard.ts b/invokeai/frontend/web/src/app/store/middleware/listenerMiddleware/listeners/imageRemovedFromBoard.ts index a8bf0e6791..4c21a750f1 100644 --- a/invokeai/frontend/web/src/app/store/middleware/listenerMiddleware/listeners/imageRemovedFromBoard.ts +++ b/invokeai/frontend/web/src/app/store/middleware/listenerMiddleware/listeners/imageRemovedFromBoard.ts @@ -1,5 +1,6 @@ import { logger } from 'app/logging/logger'; import { imagesApi } from 'services/api/endpoints/images'; + import { startAppListening } from '..'; export const addImageRemovedFromBoardFulfilledListener = () => { diff --git a/invokeai/frontend/web/src/app/store/middleware/listenerMiddleware/listeners/imageToDeleteSelected.ts b/invokeai/frontend/web/src/app/store/middleware/listenerMiddleware/listeners/imageToDeleteSelected.ts index 1c07caad29..ccc14165a3 100644 --- a/invokeai/frontend/web/src/app/store/middleware/listenerMiddleware/listeners/imageToDeleteSelected.ts +++ b/invokeai/frontend/web/src/app/store/middleware/listenerMiddleware/listeners/imageToDeleteSelected.ts @@ -4,6 +4,7 @@ import { imagesToDeleteSelected, isModalOpenChanged, } from 'features/deleteImageModal/store/slice'; + import { startAppListening } from '..'; export const addImageToDeleteSelectedListener = () => { diff --git a/invokeai/frontend/web/src/app/store/middleware/listenerMiddleware/listeners/imageUploaded.ts b/invokeai/frontend/web/src/app/store/middleware/listenerMiddleware/listeners/imageUploaded.ts index 8b1a374207..196498a0f4 100644 --- a/invokeai/frontend/web/src/app/store/middleware/listenerMiddleware/listeners/imageUploaded.ts +++ b/invokeai/frontend/web/src/app/store/middleware/listenerMiddleware/listeners/imageUploaded.ts @@ -1,4 +1,4 @@ -import { UseToastOptions } from '@chakra-ui/react'; +import type { UseToastOptions } from '@chakra-ui/react'; import { logger } from 'app/logging/logger'; import { setInitialCanvasImage } from 'features/canvas/store/canvasSlice'; import { @@ -11,9 +11,10 @@ import { addToast } from 'features/system/store/systemSlice'; import { t } from 'i18next'; import { omit } from 'lodash-es'; import { boardsApi } from 'services/api/endpoints/boards'; -import { startAppListening } from '..'; import { imagesApi } from 'services/api/endpoints/images'; +import { startAppListening } from '..'; + export const addImageUploadedFulfilledListener = () => { startAppListening({ matcher: imagesApi.endpoints.uploadImage.matchFulfilled, diff --git a/invokeai/frontend/web/src/app/store/middleware/listenerMiddleware/listeners/imagesStarred.ts b/invokeai/frontend/web/src/app/store/middleware/listenerMiddleware/listeners/imagesStarred.ts index 624fd0aa00..064e9876fc 100644 --- a/invokeai/frontend/web/src/app/store/middleware/listenerMiddleware/listeners/imagesStarred.ts +++ b/invokeai/frontend/web/src/app/store/middleware/listenerMiddleware/listeners/imagesStarred.ts @@ -1,7 +1,8 @@ -import { imagesApi } from 'services/api/endpoints/images'; -import { startAppListening } from '..'; import { selectionChanged } from 'features/gallery/store/gallerySlice'; -import { ImageDTO } from 'services/api/types'; +import { imagesApi } from 'services/api/endpoints/images'; +import type { ImageDTO } from 'services/api/types'; + +import { startAppListening } from '..'; export const addImagesStarredListener = () => { startAppListening({ diff --git a/invokeai/frontend/web/src/app/store/middleware/listenerMiddleware/listeners/imagesUnstarred.ts b/invokeai/frontend/web/src/app/store/middleware/listenerMiddleware/listeners/imagesUnstarred.ts index f4fc12718e..7174bd066d 100644 --- a/invokeai/frontend/web/src/app/store/middleware/listenerMiddleware/listeners/imagesUnstarred.ts +++ b/invokeai/frontend/web/src/app/store/middleware/listenerMiddleware/listeners/imagesUnstarred.ts @@ -1,7 +1,8 @@ -import { imagesApi } from 'services/api/endpoints/images'; -import { startAppListening } from '..'; import { selectionChanged } from 'features/gallery/store/gallerySlice'; -import { ImageDTO } from 'services/api/types'; +import { imagesApi } from 'services/api/endpoints/images'; +import type { ImageDTO } from 'services/api/types'; + +import { startAppListening } from '..'; export const addImagesUnstarredListener = () => { startAppListening({ diff --git a/invokeai/frontend/web/src/app/store/middleware/listenerMiddleware/listeners/initialImageSelected.ts b/invokeai/frontend/web/src/app/store/middleware/listenerMiddleware/listeners/initialImageSelected.ts index 7748ca6fe5..09598440a5 100644 --- a/invokeai/frontend/web/src/app/store/middleware/listenerMiddleware/listeners/initialImageSelected.ts +++ b/invokeai/frontend/web/src/app/store/middleware/listenerMiddleware/listeners/initialImageSelected.ts @@ -3,6 +3,7 @@ import { initialImageChanged } from 'features/parameters/store/generationSlice'; import { addToast } from 'features/system/store/systemSlice'; import { makeToast } from 'features/system/util/makeToast'; import { t } from 'i18next'; + import { startAppListening } from '..'; export const addInitialImageSelectedListener = () => { diff --git a/invokeai/frontend/web/src/app/store/middleware/listenerMiddleware/listeners/modelSelected.ts b/invokeai/frontend/web/src/app/store/middleware/listenerMiddleware/listeners/modelSelected.ts index e4175affe6..dad75f9004 100644 --- a/invokeai/frontend/web/src/app/store/middleware/listenerMiddleware/listeners/modelSelected.ts +++ b/invokeai/frontend/web/src/app/store/middleware/listenerMiddleware/listeners/modelSelected.ts @@ -7,17 +7,18 @@ import { import { loraRemoved } from 'features/lora/store/loraSlice'; import { modelSelected } from 'features/parameters/store/actions'; import { + heightChanged, modelChanged, - setHeight, - setWidth, vaeSelected, + widthChanged, } from 'features/parameters/store/generationSlice'; +import { zParameterModel } from 'features/parameters/types/parameterSchemas'; import { addToast } from 'features/system/store/systemSlice'; import { makeToast } from 'features/system/util/makeToast'; import { t } from 'i18next'; import { forEach } from 'lodash-es'; + import { startAppListening } from '..'; -import { zParameterModel } from 'features/parameters/types/parameterSchemas'; export const addModelSelectedListener = () => { startAppListening({ @@ -89,12 +90,12 @@ export const addModelSelectedListener = () => { state.ui.shouldAutoChangeDimensions ) { if (['sdxl', 'sdxl-refiner'].includes(newModel.base_model)) { - dispatch(setWidth(1024)); - dispatch(setHeight(1024)); + dispatch(widthChanged(1024)); + dispatch(heightChanged(1024)); dispatch(setBoundingBoxDimensions({ width: 1024, height: 1024 })); } else { - dispatch(setWidth(512)); - dispatch(setHeight(512)); + dispatch(widthChanged(512)); + dispatch(heightChanged(512)); dispatch(setBoundingBoxDimensions({ width: 512, height: 512 })); } } diff --git a/invokeai/frontend/web/src/app/store/middleware/listenerMiddleware/listeners/modelsLoaded.ts b/invokeai/frontend/web/src/app/store/middleware/listenerMiddleware/listeners/modelsLoaded.ts index afb390470b..78cdcc36b8 100644 --- a/invokeai/frontend/web/src/app/store/middleware/listenerMiddleware/listeners/modelsLoaded.ts +++ b/invokeai/frontend/web/src/app/store/middleware/listenerMiddleware/listeners/modelsLoaded.ts @@ -12,20 +12,17 @@ import { } from 'features/parameters/store/generationSlice'; import { zParameterModel, - zParameterSDXLRefinerModel, zParameterVAEModel, } from 'features/parameters/types/parameterSchemas'; -import { - refinerModelChanged, - setShouldUseSDXLRefiner, -} from 'features/sdxl/store/sdxlSlice'; +import { refinerModelChanged } from 'features/sdxl/store/sdxlSlice'; import { forEach, some } from 'lodash-es'; import { mainModelsAdapter, modelsApi, vaeModelsAdapter, } from 'services/api/endpoints/models'; -import { TypeGuardFor } from 'services/api/types'; +import type { TypeGuardFor } from 'services/api/types'; + import { startAppListening } from '..'; export const addModelsLoadedListener = () => { @@ -102,7 +99,6 @@ export const addModelsLoadedListener = () => { if (models.length === 0) { // No models loaded at all dispatch(refinerModelChanged(null)); - dispatch(setShouldUseSDXLRefiner(false)); return; } @@ -115,21 +111,10 @@ export const addModelsLoadedListener = () => { ) : false; - if (isCurrentModelAvailable) { + if (!isCurrentModelAvailable) { + dispatch(refinerModelChanged(null)); return; } - - const result = zParameterSDXLRefinerModel.safeParse(models[0]); - - if (!result.success) { - log.error( - { error: result.error.format() }, - 'Failed to parse SDXL Refiner Model' - ); - return; - } - - dispatch(refinerModelChanged(result.data)); }, }); startAppListening({ diff --git a/invokeai/frontend/web/src/app/store/middleware/listenerMiddleware/listeners/promptChanged.ts b/invokeai/frontend/web/src/app/store/middleware/listenerMiddleware/listeners/promptChanged.ts index a48a84a30f..131926e628 100644 --- a/invokeai/frontend/web/src/app/store/middleware/listenerMiddleware/listeners/promptChanged.ts +++ b/invokeai/frontend/web/src/app/store/middleware/listenerMiddleware/listeners/promptChanged.ts @@ -11,6 +11,7 @@ import { import { setPositivePrompt } from 'features/parameters/store/generationSlice'; import { utilitiesApi } from 'services/api/endpoints/utilities'; import { appSocketConnected } from 'services/events/actions'; + import { startAppListening } from '..'; const matcher = isAnyOf( diff --git a/invokeai/frontend/web/src/app/store/middleware/listenerMiddleware/listeners/receivedOpenAPISchema.ts b/invokeai/frontend/web/src/app/store/middleware/listenerMiddleware/listeners/receivedOpenAPISchema.ts index ff44317fcf..05a509b155 100644 --- a/invokeai/frontend/web/src/app/store/middleware/listenerMiddleware/listeners/receivedOpenAPISchema.ts +++ b/invokeai/frontend/web/src/app/store/middleware/listenerMiddleware/listeners/receivedOpenAPISchema.ts @@ -4,6 +4,7 @@ import { nodeTemplatesBuilt } from 'features/nodes/store/nodesSlice'; import { parseSchema } from 'features/nodes/util/schema/parseSchema'; import { size } from 'lodash-es'; import { receivedOpenAPISchema } from 'services/api/thunks/schema'; + import { startAppListening } from '..'; export const addReceivedOpenAPISchemaListener = () => { diff --git a/invokeai/frontend/web/src/app/store/middleware/listenerMiddleware/listeners/socketio/socketConnected.ts b/invokeai/frontend/web/src/app/store/middleware/listenerMiddleware/listeners/socketio/socketConnected.ts index 9957b7f117..4039cf2406 100644 --- a/invokeai/frontend/web/src/app/store/middleware/listenerMiddleware/listeners/socketio/socketConnected.ts +++ b/invokeai/frontend/web/src/app/store/middleware/listenerMiddleware/listeners/socketio/socketConnected.ts @@ -1,10 +1,11 @@ import { logger } from 'app/logging/logger'; +import { isInitializedChanged } from 'features/system/store/systemSlice'; import { size } from 'lodash-es'; import { api } from 'services/api'; import { receivedOpenAPISchema } from 'services/api/thunks/schema'; import { appSocketConnected, socketConnected } from 'services/events/actions'; + import { startAppListening } from '../..'; -import { isInitializedChanged } from 'features/system/store/systemSlice'; export const addSocketConnectedEventListener = () => { startAppListening({ diff --git a/invokeai/frontend/web/src/app/store/middleware/listenerMiddleware/listeners/socketio/socketDisconnected.ts b/invokeai/frontend/web/src/app/store/middleware/listenerMiddleware/listeners/socketio/socketDisconnected.ts index 80e6fb0813..8157c5bf85 100644 --- a/invokeai/frontend/web/src/app/store/middleware/listenerMiddleware/listeners/socketio/socketDisconnected.ts +++ b/invokeai/frontend/web/src/app/store/middleware/listenerMiddleware/listeners/socketio/socketDisconnected.ts @@ -3,6 +3,7 @@ import { appSocketDisconnected, socketDisconnected, } from 'services/events/actions'; + import { startAppListening } from '../..'; export const addSocketDisconnectedEventListener = () => { diff --git a/invokeai/frontend/web/src/app/store/middleware/listenerMiddleware/listeners/socketio/socketGeneratorProgress.ts b/invokeai/frontend/web/src/app/store/middleware/listenerMiddleware/listeners/socketio/socketGeneratorProgress.ts index 44d6ceed63..77fcf85ad1 100644 --- a/invokeai/frontend/web/src/app/store/middleware/listenerMiddleware/listeners/socketio/socketGeneratorProgress.ts +++ b/invokeai/frontend/web/src/app/store/middleware/listenerMiddleware/listeners/socketio/socketGeneratorProgress.ts @@ -3,6 +3,7 @@ import { appSocketGeneratorProgress, socketGeneratorProgress, } from 'services/events/actions'; + import { startAppListening } from '../..'; export const addGeneratorProgressEventListener = () => { diff --git a/invokeai/frontend/web/src/app/store/middleware/listenerMiddleware/listeners/socketio/socketGraphExecutionStateComplete.ts b/invokeai/frontend/web/src/app/store/middleware/listenerMiddleware/listeners/socketio/socketGraphExecutionStateComplete.ts index 23ab9a8cb3..32946687e0 100644 --- a/invokeai/frontend/web/src/app/store/middleware/listenerMiddleware/listeners/socketio/socketGraphExecutionStateComplete.ts +++ b/invokeai/frontend/web/src/app/store/middleware/listenerMiddleware/listeners/socketio/socketGraphExecutionStateComplete.ts @@ -3,6 +3,7 @@ import { appSocketGraphExecutionStateComplete, socketGraphExecutionStateComplete, } from 'services/events/actions'; + import { startAppListening } from '../..'; export const addGraphExecutionStateCompleteEventListener = () => { diff --git a/invokeai/frontend/web/src/app/store/middleware/listenerMiddleware/listeners/socketio/socketInvocationComplete.ts b/invokeai/frontend/web/src/app/store/middleware/listenerMiddleware/listeners/socketio/socketInvocationComplete.ts index 364a2658bf..8eac0f51ae 100644 --- a/invokeai/frontend/web/src/app/store/middleware/listenerMiddleware/listeners/socketio/socketInvocationComplete.ts +++ b/invokeai/frontend/web/src/app/store/middleware/listenerMiddleware/listeners/socketio/socketInvocationComplete.ts @@ -7,6 +7,7 @@ import { imageSelected, } from 'features/gallery/store/gallerySlice'; import { IMAGE_CATEGORIES } from 'features/gallery/store/types'; +import { isImageOutput } from 'features/nodes/types/common'; import { LINEAR_UI_OUTPUT, nodeIDDenyList, @@ -18,8 +19,8 @@ import { appSocketInvocationComplete, socketInvocationComplete, } from 'services/events/actions'; + import { startAppListening } from '../..'; -import { isImageOutput } from 'features/nodes/types/common'; // These nodes output an image, but do not actually *save* an image, so we don't want to handle the gallery logic on them const nodeTypeDenylist = ['load_image', 'image']; diff --git a/invokeai/frontend/web/src/app/store/middleware/listenerMiddleware/listeners/socketio/socketInvocationError.ts b/invokeai/frontend/web/src/app/store/middleware/listenerMiddleware/listeners/socketio/socketInvocationError.ts index ce15b8398c..3f5d4c21c4 100644 --- a/invokeai/frontend/web/src/app/store/middleware/listenerMiddleware/listeners/socketio/socketInvocationError.ts +++ b/invokeai/frontend/web/src/app/store/middleware/listenerMiddleware/listeners/socketio/socketInvocationError.ts @@ -3,6 +3,7 @@ import { appSocketInvocationError, socketInvocationError, } from 'services/events/actions'; + import { startAppListening } from '../..'; export const addInvocationErrorEventListener = () => { diff --git a/invokeai/frontend/web/src/app/store/middleware/listenerMiddleware/listeners/socketio/socketInvocationRetrievalError.ts b/invokeai/frontend/web/src/app/store/middleware/listenerMiddleware/listeners/socketio/socketInvocationRetrievalError.ts index aa88457eb7..5700b73d39 100644 --- a/invokeai/frontend/web/src/app/store/middleware/listenerMiddleware/listeners/socketio/socketInvocationRetrievalError.ts +++ b/invokeai/frontend/web/src/app/store/middleware/listenerMiddleware/listeners/socketio/socketInvocationRetrievalError.ts @@ -3,6 +3,7 @@ import { appSocketInvocationRetrievalError, socketInvocationRetrievalError, } from 'services/events/actions'; + import { startAppListening } from '../..'; export const addInvocationRetrievalErrorEventListener = () => { diff --git a/invokeai/frontend/web/src/app/store/middleware/listenerMiddleware/listeners/socketio/socketInvocationStarted.ts b/invokeai/frontend/web/src/app/store/middleware/listenerMiddleware/listeners/socketio/socketInvocationStarted.ts index 50f52e2851..8dd7730143 100644 --- a/invokeai/frontend/web/src/app/store/middleware/listenerMiddleware/listeners/socketio/socketInvocationStarted.ts +++ b/invokeai/frontend/web/src/app/store/middleware/listenerMiddleware/listeners/socketio/socketInvocationStarted.ts @@ -3,6 +3,7 @@ import { appSocketInvocationStarted, socketInvocationStarted, } from 'services/events/actions'; + import { startAppListening } from '../..'; export const addInvocationStartedEventListener = () => { diff --git a/invokeai/frontend/web/src/app/store/middleware/listenerMiddleware/listeners/socketio/socketModelLoad.ts b/invokeai/frontend/web/src/app/store/middleware/listenerMiddleware/listeners/socketio/socketModelLoad.ts index 0f3fabbc1e..cef3b1fe6d 100644 --- a/invokeai/frontend/web/src/app/store/middleware/listenerMiddleware/listeners/socketio/socketModelLoad.ts +++ b/invokeai/frontend/web/src/app/store/middleware/listenerMiddleware/listeners/socketio/socketModelLoad.ts @@ -5,6 +5,7 @@ import { socketModelLoadCompleted, socketModelLoadStarted, } from 'services/events/actions'; + import { startAppListening } from '../..'; export const addModelLoadEventListener = () => { diff --git a/invokeai/frontend/web/src/app/store/middleware/listenerMiddleware/listeners/socketio/socketQueueItemStatusChanged.ts b/invokeai/frontend/web/src/app/store/middleware/listenerMiddleware/listeners/socketio/socketQueueItemStatusChanged.ts index 8136285248..370fd35407 100644 --- a/invokeai/frontend/web/src/app/store/middleware/listenerMiddleware/listeners/socketio/socketQueueItemStatusChanged.ts +++ b/invokeai/frontend/web/src/app/store/middleware/listenerMiddleware/listeners/socketio/socketQueueItemStatusChanged.ts @@ -4,6 +4,7 @@ import { appSocketQueueItemStatusChanged, socketQueueItemStatusChanged, } from 'services/events/actions'; + import { startAppListening } from '../..'; export const addSocketQueueItemStatusChangedEventListener = () => { diff --git a/invokeai/frontend/web/src/app/store/middleware/listenerMiddleware/listeners/socketio/socketSessionRetrievalError.ts b/invokeai/frontend/web/src/app/store/middleware/listenerMiddleware/listeners/socketio/socketSessionRetrievalError.ts index 7efb7f463a..e37b972064 100644 --- a/invokeai/frontend/web/src/app/store/middleware/listenerMiddleware/listeners/socketio/socketSessionRetrievalError.ts +++ b/invokeai/frontend/web/src/app/store/middleware/listenerMiddleware/listeners/socketio/socketSessionRetrievalError.ts @@ -3,6 +3,7 @@ import { appSocketSessionRetrievalError, socketSessionRetrievalError, } from 'services/events/actions'; + import { startAppListening } from '../..'; export const addSessionRetrievalErrorEventListener = () => { diff --git a/invokeai/frontend/web/src/app/store/middleware/listenerMiddleware/listeners/socketio/socketSubscribed.ts b/invokeai/frontend/web/src/app/store/middleware/listenerMiddleware/listeners/socketio/socketSubscribed.ts index 1f9354ee67..9c5e73981a 100644 --- a/invokeai/frontend/web/src/app/store/middleware/listenerMiddleware/listeners/socketio/socketSubscribed.ts +++ b/invokeai/frontend/web/src/app/store/middleware/listenerMiddleware/listeners/socketio/socketSubscribed.ts @@ -3,6 +3,7 @@ import { appSocketSubscribedSession, socketSubscribedSession, } from 'services/events/actions'; + import { startAppListening } from '../..'; export const addSocketSubscribedEventListener = () => { diff --git a/invokeai/frontend/web/src/app/store/middleware/listenerMiddleware/listeners/socketio/socketUnsubscribed.ts b/invokeai/frontend/web/src/app/store/middleware/listenerMiddleware/listeners/socketio/socketUnsubscribed.ts index 2f4f65edc6..05984ba67f 100644 --- a/invokeai/frontend/web/src/app/store/middleware/listenerMiddleware/listeners/socketio/socketUnsubscribed.ts +++ b/invokeai/frontend/web/src/app/store/middleware/listenerMiddleware/listeners/socketio/socketUnsubscribed.ts @@ -3,6 +3,7 @@ import { appSocketUnsubscribedSession, socketUnsubscribedSession, } from 'services/events/actions'; + import { startAppListening } from '../..'; export const addSocketUnsubscribedEventListener = () => { diff --git a/invokeai/frontend/web/src/app/store/middleware/listenerMiddleware/listeners/stagingAreaImageSaved.ts b/invokeai/frontend/web/src/app/store/middleware/listenerMiddleware/listeners/stagingAreaImageSaved.ts index c00cf78beb..8a38be1b77 100644 --- a/invokeai/frontend/web/src/app/store/middleware/listenerMiddleware/listeners/stagingAreaImageSaved.ts +++ b/invokeai/frontend/web/src/app/store/middleware/listenerMiddleware/listeners/stagingAreaImageSaved.ts @@ -1,8 +1,9 @@ import { stagingAreaImageSaved } from 'features/canvas/store/actions'; import { addToast } from 'features/system/store/systemSlice'; -import { imagesApi } from 'services/api/endpoints/images'; -import { startAppListening } from '..'; import { t } from 'i18next'; +import { imagesApi } from 'services/api/endpoints/images'; + +import { startAppListening } from '..'; export const addStagingAreaImageSavedListener = () => { startAppListening({ diff --git a/invokeai/frontend/web/src/app/store/middleware/listenerMiddleware/listeners/tabChanged.ts b/invokeai/frontend/web/src/app/store/middleware/listenerMiddleware/listeners/tabChanged.ts index 6791324fdd..f58c6c1f33 100644 --- a/invokeai/frontend/web/src/app/store/middleware/listenerMiddleware/listeners/tabChanged.ts +++ b/invokeai/frontend/web/src/app/store/middleware/listenerMiddleware/listeners/tabChanged.ts @@ -2,6 +2,7 @@ import { modelChanged } from 'features/parameters/store/generationSlice'; import { setActiveTab } from 'features/ui/store/uiSlice'; import { NON_REFINER_BASE_MODELS } from 'services/api/constants'; import { mainModelsAdapter, modelsApi } from 'services/api/endpoints/models'; + import { startAppListening } from '..'; export const addTabChangedListener = () => { diff --git a/invokeai/frontend/web/src/app/store/middleware/listenerMiddleware/listeners/updateAllNodesRequested.ts b/invokeai/frontend/web/src/app/store/middleware/listenerMiddleware/listeners/updateAllNodesRequested.ts index 1df083c795..11bad0c221 100644 --- a/invokeai/frontend/web/src/app/store/middleware/listenerMiddleware/listeners/updateAllNodesRequested.ts +++ b/invokeai/frontend/web/src/app/store/middleware/listenerMiddleware/listeners/updateAllNodesRequested.ts @@ -1,15 +1,16 @@ import { logger } from 'app/logging/logger'; import { updateAllNodesRequested } from 'features/nodes/store/actions'; import { nodeReplaced } from 'features/nodes/store/nodesSlice'; +import { NodeUpdateError } from 'features/nodes/types/error'; +import { isInvocationNode } from 'features/nodes/types/invocation'; import { getNeedsUpdate, updateNode, } from 'features/nodes/util/node/nodeUpdate'; -import { NodeUpdateError } from 'features/nodes/types/error'; -import { isInvocationNode } from 'features/nodes/types/invocation'; import { addToast } from 'features/system/store/systemSlice'; import { makeToast } from 'features/system/util/makeToast'; import { t } from 'i18next'; + import { startAppListening } from '..'; export const addUpdateAllNodesRequestedListener = () => { diff --git a/invokeai/frontend/web/src/app/store/middleware/listenerMiddleware/listeners/upscaleRequested.ts b/invokeai/frontend/web/src/app/store/middleware/listenerMiddleware/listeners/upscaleRequested.ts index 1b4211087a..75c67a08cc 100644 --- a/invokeai/frontend/web/src/app/store/middleware/listenerMiddleware/listeners/upscaleRequested.ts +++ b/invokeai/frontend/web/src/app/store/middleware/listenerMiddleware/listeners/upscaleRequested.ts @@ -2,12 +2,13 @@ import { createAction } from '@reduxjs/toolkit'; import { logger } from 'app/logging/logger'; import { parseify } from 'common/util/serialize'; import { buildAdHocUpscaleGraph } from 'features/nodes/util/graph/buildAdHocUpscaleGraph'; +import { createIsAllowedToUpscaleSelector } from 'features/parameters/hooks/useIsAllowedToUpscale'; import { addToast } from 'features/system/store/systemSlice'; import { t } from 'i18next'; import { queueApi } from 'services/api/endpoints/queue'; +import type { BatchConfig, ImageDTO } from 'services/api/types'; + import { startAppListening } from '..'; -import { BatchConfig, ImageDTO } from 'services/api/types'; -import { createIsAllowedToUpscaleSelector } from 'features/parameters/hooks/useIsAllowedToUpscale'; export const upscaleRequested = createAction<{ imageDTO: ImageDTO }>( `upscale/upscaleRequested` diff --git a/invokeai/frontend/web/src/app/store/middleware/listenerMiddleware/listeners/workflowLoadRequested.ts b/invokeai/frontend/web/src/app/store/middleware/listenerMiddleware/listeners/workflowLoadRequested.ts index 3dff9a906b..0a0803fc07 100644 --- a/invokeai/frontend/web/src/app/store/middleware/listenerMiddleware/listeners/workflowLoadRequested.ts +++ b/invokeai/frontend/web/src/app/store/middleware/listenerMiddleware/listeners/workflowLoadRequested.ts @@ -1,7 +1,9 @@ import { logger } from 'app/logging/logger'; import { parseify } from 'common/util/serialize'; -import { workflowLoadRequested } from 'features/nodes/store/actions'; -import { workflowLoaded } from 'features/nodes/store/actions'; +import { + workflowLoaded, + workflowLoadRequested, +} from 'features/nodes/store/actions'; import { $flow } from 'features/nodes/store/reactFlowInstance'; import { WorkflowMigrationError, @@ -14,6 +16,7 @@ import { setActiveTab } from 'features/ui/store/uiSlice'; import { t } from 'i18next'; import { z } from 'zod'; import { fromZodError } from 'zod-validation-error'; + import { startAppListening } from '..'; export const addWorkflowLoadRequestedListener = () => { diff --git a/invokeai/frontend/web/src/app/store/nanostores/README.md b/invokeai/frontend/web/src/app/store/nanostores/README.md new file mode 100644 index 0000000000..9b85e586ba --- /dev/null +++ b/invokeai/frontend/web/src/app/store/nanostores/README.md @@ -0,0 +1,3 @@ +# nanostores + +For non-serializable data that needs to be available throughout the app, or when redux is not appropriate, use nanostores. diff --git a/invokeai/frontend/web/src/app/store/nanostores/customStarUI.ts b/invokeai/frontend/web/src/app/store/nanostores/customStarUI.ts index 0459c2f31f..bb815164e5 100644 --- a/invokeai/frontend/web/src/app/store/nanostores/customStarUI.ts +++ b/invokeai/frontend/web/src/app/store/nanostores/customStarUI.ts @@ -1,4 +1,4 @@ -import { MenuItemProps } from '@chakra-ui/react'; +import type { MenuItemProps } from '@chakra-ui/react'; import { atom } from 'nanostores'; export type CustomStarUi = { diff --git a/invokeai/frontend/web/src/app/store/nanostores/headerComponent.ts b/invokeai/frontend/web/src/app/store/nanostores/headerComponent.ts index 90a4775ff9..0b8a1398ec 100644 --- a/invokeai/frontend/web/src/app/store/nanostores/headerComponent.ts +++ b/invokeai/frontend/web/src/app/store/nanostores/headerComponent.ts @@ -1,4 +1,4 @@ import { atom } from 'nanostores'; -import { ReactNode } from 'react'; +import type { ReactNode } from 'react'; export const $headerComponent = atom(undefined); diff --git a/invokeai/frontend/web/src/app/store/nanostores/index.ts b/invokeai/frontend/web/src/app/store/nanostores/index.ts deleted file mode 100644 index ae43ed3035..0000000000 --- a/invokeai/frontend/web/src/app/store/nanostores/index.ts +++ /dev/null @@ -1,3 +0,0 @@ -/** - * For non-serializable data that needs to be available throughout the app, or when redux is not appropriate, use nanostores. - */ diff --git a/invokeai/frontend/web/src/app/store/nanostores/store.ts b/invokeai/frontend/web/src/app/store/nanostores/store.ts index 4e16245c6c..2bf2700893 100644 --- a/invokeai/frontend/web/src/app/store/nanostores/store.ts +++ b/invokeai/frontend/web/src/app/store/nanostores/store.ts @@ -1,4 +1,4 @@ -import { createStore } from 'app/store/store'; +import type { createStore } from 'app/store/store'; import { atom } from 'nanostores'; export const $store = atom< diff --git a/invokeai/frontend/web/src/app/store/store.ts b/invokeai/frontend/web/src/app/store/store.ts index 6b31f6f8d4..56e879ced3 100644 --- a/invokeai/frontend/web/src/app/store/store.ts +++ b/invokeai/frontend/web/src/app/store/store.ts @@ -1,6 +1,5 @@ +import type { ThunkDispatch, UnknownAction } from '@reduxjs/toolkit'; import { - ThunkDispatch, - UnknownAction, autoBatchEnhancer, combineReducers, configureStore, @@ -11,6 +10,7 @@ import controlAdaptersReducer from 'features/controlAdapters/store/controlAdapte import deleteImageModalReducer from 'features/deleteImageModal/store/slice'; import dynamicPromptsReducer from 'features/dynamicPrompts/store/dynamicPromptsSlice'; import galleryReducer from 'features/gallery/store/gallerySlice'; +import hrfReducer from 'features/hrf/store/hrfSlice'; import loraReducer from 'features/lora/store/loraSlice'; import modelmanagerReducer from 'features/modelManager/store/modelManagerSlice'; import nodesReducer from 'features/nodes/store/nodesSlice'; @@ -21,12 +21,14 @@ import queueReducer from 'features/queue/store/queueSlice'; import sdxlReducer from 'features/sdxl/store/sdxlSlice'; import configReducer from 'features/system/store/configSlice'; import systemReducer from 'features/system/store/systemSlice'; -import hotkeysReducer from 'features/ui/store/hotkeysSlice'; import uiReducer from 'features/ui/store/uiSlice'; import { createStore as createIDBKeyValStore, get, set } from 'idb-keyval'; import dynamicMiddlewares from 'redux-dynamic-middlewares'; -import { Driver, rememberEnhancer, rememberReducer } from 'redux-remember'; +import type { Driver } from 'redux-remember'; +import { rememberEnhancer, rememberReducer } from 'redux-remember'; import { api } from 'services/api'; +import { authToastMiddleware } from 'services/api/authToastMiddleware'; + import { STORAGE_PREFIX } from './constants'; import { serialize } from './enhancers/reduxRemember/serialize'; import { unserialize } from './enhancers/reduxRemember/unserialize'; @@ -34,7 +36,6 @@ import { actionSanitizer } from './middleware/devtools/actionSanitizer'; import { actionsDenylist } from './middleware/devtools/actionsDenylist'; import { stateSanitizer } from './middleware/devtools/stateSanitizer'; import { listenerMiddleware } from './middleware/listenerMiddleware'; -import { authToastMiddleware } from 'services/api/authToastMiddleware'; const allReducers = { canvas: canvasReducer, @@ -45,7 +46,6 @@ const allReducers = { system: systemReducer, config: configReducer, ui: uiReducer, - hotkeys: hotkeysReducer, controlAdapters: controlAdaptersReducer, dynamicPrompts: dynamicPromptsReducer, deleteImageModal: deleteImageModalReducer, @@ -55,6 +55,7 @@ const allReducers = { sdxl: sdxlReducer, queue: queueReducer, workflow: workflowReducer, + hrf: hrfReducer, [api.reducerPath]: api.reducer, }; @@ -76,6 +77,7 @@ const rememberedKeys: (keyof typeof allReducers)[] = [ 'dynamicPrompts', 'lora', 'modelmanager', + 'hrf', ]; // Create a custom idb-keyval store (just needed to customize the name) @@ -147,4 +149,6 @@ export type RootState = ReturnType['getState']>; // eslint-disable-next-line @typescript-eslint/no-explicit-any export type AppThunkDispatch = ThunkDispatch; export type AppDispatch = ReturnType['dispatch']; -export const stateSelector = (state: RootState) => state; +export function stateSelector(state: RootState) { + return state; +} diff --git a/invokeai/frontend/web/src/app/store/storeHooks.ts b/invokeai/frontend/web/src/app/store/storeHooks.ts index f0400c3a3c..f1a9aa979c 100644 --- a/invokeai/frontend/web/src/app/store/storeHooks.ts +++ b/invokeai/frontend/web/src/app/store/storeHooks.ts @@ -1,5 +1,6 @@ -import { TypedUseSelectorHook, useDispatch, useSelector } from 'react-redux'; -import { AppThunkDispatch, RootState } from 'app/store/store'; +import type { AppThunkDispatch, RootState } from 'app/store/store'; +import type { TypedUseSelectorHook } from 'react-redux'; +import { useDispatch, useSelector } from 'react-redux'; // Use throughout your app instead of plain `useDispatch` and `useSelector` export const useAppDispatch = () => useDispatch(); diff --git a/invokeai/frontend/web/src/app/types/invokeai.ts b/invokeai/frontend/web/src/app/types/invokeai.ts index 7e4cfb39aa..8658b9dcb7 100644 --- a/invokeai/frontend/web/src/app/types/invokeai.ts +++ b/invokeai/frontend/web/src/app/types/invokeai.ts @@ -1,6 +1,6 @@ -import { CONTROLNET_PROCESSORS } from 'features/controlAdapters/store/constants'; -import { InvokeTabName } from 'features/ui/store/tabMap'; -import { O } from 'ts-toolbelt'; +import type { CONTROLNET_PROCESSORS } from 'features/controlAdapters/store/constants'; +import type { InvokeTabName } from 'features/ui/store/tabMap'; +import type { O } from 'ts-toolbelt'; /** * A disable-able application feature diff --git a/invokeai/frontend/web/src/common/components/AspectRatioPreview/AspectRatioPreview.stories.tsx b/invokeai/frontend/web/src/common/components/AspectRatioPreview/AspectRatioPreview.stories.tsx new file mode 100644 index 0000000000..0b6e6b0a59 --- /dev/null +++ b/invokeai/frontend/web/src/common/components/AspectRatioPreview/AspectRatioPreview.stories.tsx @@ -0,0 +1,64 @@ +import { Flex } from '@chakra-ui/layout'; +import type { Meta, StoryObj } from '@storybook/react'; +import { InvControl } from 'common/components/InvControl/InvControl'; +import { InvSlider } from 'common/components/InvSlider/InvSlider'; +import { useState } from 'react'; + +import { AspectRatioPreview } from './AspectRatioPreview'; + +const meta: Meta = { + title: 'Components/AspectRatioPreview', + tags: ['autodocs'], + component: AspectRatioPreview, +}; + +export default meta; +type Story = StoryObj; + +const MIN = 64; +const MAX = 1024; +const STEP = 64; +const FINE_STEP = 8; +const INITIAL = 512; +const MARKS = Array.from( + { length: Math.floor(MAX / STEP) }, + (_, i) => MIN + i * STEP +); + +const Component = () => { + const [width, setWidth] = useState(INITIAL); + const [height, setHeight] = useState(INITIAL); + return ( + + + + + + + + + + + + ); +}; + +export const AspectRatioWithSliderInvControls: Story = { + render: Component, +}; diff --git a/invokeai/frontend/web/src/common/components/AspectRatioPreview/AspectRatioPreview.tsx b/invokeai/frontend/web/src/common/components/AspectRatioPreview/AspectRatioPreview.tsx new file mode 100644 index 0000000000..0a05fbd2c3 --- /dev/null +++ b/invokeai/frontend/web/src/common/components/AspectRatioPreview/AspectRatioPreview.tsx @@ -0,0 +1,60 @@ +import { Flex, Icon } from '@chakra-ui/react'; +import { useSize } from '@chakra-ui/react-use-size'; +import { AnimatePresence, motion } from 'framer-motion'; +import { useRef } from 'react'; +import { FaImage } from 'react-icons/fa'; + +import { + BOX_SIZE_CSS_CALC, + ICON_CONTAINER_STYLES, + MOTION_ICON_ANIMATE, + MOTION_ICON_EXIT, + MOTION_ICON_INITIAL, +} from './constants'; +import { useAspectRatioPreviewState } from './hooks'; +import type { AspectRatioPreviewProps } from './types'; + +export const AspectRatioPreview = (props: AspectRatioPreviewProps) => { + const { width: _width, height: _height, icon = FaImage } = props; + const containerRef = useRef(null); + const containerSize = useSize(containerRef); + + const { width, height, shouldShowIcon } = useAspectRatioPreviewState({ + width: _width, + height: _height, + containerSize, + }); + + return ( + + + + {shouldShowIcon && ( + + + + )} + + + + ); +}; diff --git a/invokeai/frontend/web/src/common/components/AspectRatioPreview/constants.ts b/invokeai/frontend/web/src/common/components/AspectRatioPreview/constants.ts new file mode 100644 index 0000000000..34f3a6941a --- /dev/null +++ b/invokeai/frontend/web/src/common/components/AspectRatioPreview/constants.ts @@ -0,0 +1,23 @@ +// When the aspect ratio is between these two values, we show the icon (experimentally determined) +export const ICON_LOW_CUTOFF = 0.23; +export const ICON_HIGH_CUTOFF = 1 / ICON_LOW_CUTOFF; +export const ICON_SIZE_PX = 48; +export const ICON_PADDING_PX = 16; +export const BOX_SIZE_CSS_CALC = `min(${ICON_SIZE_PX}px, calc(100% - ${ICON_PADDING_PX}px))`; +export const MOTION_ICON_INITIAL = { + opacity: 0, +}; +export const MOTION_ICON_ANIMATE = { + opacity: 1, + transition: { duration: 0.1 }, +}; +export const MOTION_ICON_EXIT = { + opacity: 0, + transition: { duration: 0.1 }, +}; +export const ICON_CONTAINER_STYLES = { + width: '100%', + height: '100%', + alignItems: 'center', + justifyContent: 'center', +}; diff --git a/invokeai/frontend/web/src/common/components/AspectRatioPreview/hooks.ts b/invokeai/frontend/web/src/common/components/AspectRatioPreview/hooks.ts new file mode 100644 index 0000000000..47eab46844 --- /dev/null +++ b/invokeai/frontend/web/src/common/components/AspectRatioPreview/hooks.ts @@ -0,0 +1,48 @@ +import { useMemo } from 'react'; + +import { ICON_HIGH_CUTOFF, ICON_LOW_CUTOFF } from './constants'; + +type Dimensions = { + width: number; + height: number; +}; + +type UseAspectRatioPreviewStateArg = { + width: number; + height: number; + containerSize?: Dimensions; +}; +type UseAspectRatioPreviewState = ( + arg: UseAspectRatioPreviewStateArg +) => Dimensions & { shouldShowIcon: boolean }; + +export const useAspectRatioPreviewState: UseAspectRatioPreviewState = ({ + width: _width, + height: _height, + containerSize, +}) => { + const dimensions = useMemo(() => { + if (!containerSize) { + return { width: 0, height: 0, shouldShowIcon: false }; + } + + const aspectRatio = _width / _height; + let width = _width; + let height = _height; + + if (_width > _height) { + width = containerSize.width; + height = width / aspectRatio; + } else { + height = containerSize.height; + width = height * aspectRatio; + } + + const shouldShowIcon = + aspectRatio < ICON_HIGH_CUTOFF && aspectRatio > ICON_LOW_CUTOFF; + + return { width, height, shouldShowIcon }; + }, [_height, _width, containerSize]); + + return dimensions; +}; diff --git a/invokeai/frontend/web/src/common/components/AspectRatioPreview/types.ts b/invokeai/frontend/web/src/common/components/AspectRatioPreview/types.ts new file mode 100644 index 0000000000..7319e7112b --- /dev/null +++ b/invokeai/frontend/web/src/common/components/AspectRatioPreview/types.ts @@ -0,0 +1,7 @@ +import type { IconType } from 'react-icons'; + +export type AspectRatioPreviewProps = { + width: number; + height: number; + icon?: IconType; +}; diff --git a/invokeai/frontend/web/src/common/components/GreyscaleInvokeAIIcon.tsx b/invokeai/frontend/web/src/common/components/GreyscaleInvokeAIIcon.tsx deleted file mode 100644 index a6c6cdca18..0000000000 --- a/invokeai/frontend/web/src/common/components/GreyscaleInvokeAIIcon.tsx +++ /dev/null @@ -1,22 +0,0 @@ -import { Box, Image } from '@chakra-ui/react'; -import InvokeAILogoImage from 'assets/images/logo.png'; -import { memo } from 'react'; - -const GreyscaleInvokeAIIcon = () => ( - - invoke-ai-logo - -); - -export default memo(GreyscaleInvokeAIIcon); diff --git a/invokeai/frontend/web/src/common/components/IAIAlertDialog.tsx b/invokeai/frontend/web/src/common/components/IAIAlertDialog.tsx deleted file mode 100644 index a82095daa3..0000000000 --- a/invokeai/frontend/web/src/common/components/IAIAlertDialog.tsx +++ /dev/null @@ -1,93 +0,0 @@ -import { - AlertDialog, - AlertDialogBody, - AlertDialogContent, - AlertDialogFooter, - AlertDialogHeader, - AlertDialogOverlay, - forwardRef, - useDisclosure, -} from '@chakra-ui/react'; -import { - cloneElement, - memo, - ReactElement, - ReactNode, - useCallback, - useRef, -} from 'react'; -import { useTranslation } from 'react-i18next'; -import IAIButton from './IAIButton'; - -type Props = { - acceptButtonText?: string; - acceptCallback: () => void; - cancelButtonText?: string; - cancelCallback?: () => void; - children: ReactNode; - title: string; - triggerComponent: ReactElement; -}; - -const IAIAlertDialog = forwardRef((props: Props, ref) => { - const { t } = useTranslation(); - - const { - acceptButtonText = t('common.accept'), - acceptCallback, - cancelButtonText = t('common.cancel'), - cancelCallback, - children, - title, - triggerComponent, - } = props; - - const { isOpen, onOpen, onClose } = useDisclosure(); - const cancelRef = useRef(null); - - const handleAccept = useCallback(() => { - acceptCallback(); - onClose(); - }, [acceptCallback, onClose]); - - const handleCancel = useCallback(() => { - cancelCallback && cancelCallback(); - onClose(); - }, [cancelCallback, onClose]); - - return ( - <> - {cloneElement(triggerComponent, { - onClick: onOpen, - ref: ref, - })} - - - - - - {title} - - - {children} - - - - {cancelButtonText} - - - {acceptButtonText} - - - - - - - ); -}); -export default memo(IAIAlertDialog); diff --git a/invokeai/frontend/web/src/common/components/IAIButton.tsx b/invokeai/frontend/web/src/common/components/IAIButton.tsx deleted file mode 100644 index 4058296aaf..0000000000 --- a/invokeai/frontend/web/src/common/components/IAIButton.tsx +++ /dev/null @@ -1,43 +0,0 @@ -import { - Button, - ButtonProps, - forwardRef, - Tooltip, - TooltipProps, -} from '@chakra-ui/react'; -import { memo, ReactNode } from 'react'; - -export interface IAIButtonProps extends ButtonProps { - tooltip?: TooltipProps['label']; - tooltipProps?: Omit; - isChecked?: boolean; - children: ReactNode; -} - -const IAIButton = forwardRef((props: IAIButtonProps, forwardedRef) => { - const { - children, - tooltip = '', - tooltipProps: { placement = 'top', hasArrow = true, ...tooltipProps } = {}, - isChecked, - ...rest - } = props; - return ( - - - - ); -}); - -export default memo(IAIButton); diff --git a/invokeai/frontend/web/src/common/components/IAICollapse.tsx b/invokeai/frontend/web/src/common/components/IAICollapse.tsx deleted file mode 100644 index ca7140ffa5..0000000000 --- a/invokeai/frontend/web/src/common/components/IAICollapse.tsx +++ /dev/null @@ -1,106 +0,0 @@ -import { ChevronUpIcon } from '@chakra-ui/icons'; -import { - Box, - Collapse, - Flex, - Spacer, - Text, - useColorMode, - useDisclosure, -} from '@chakra-ui/react'; -import { AnimatePresence, motion } from 'framer-motion'; -import { PropsWithChildren, memo } from 'react'; -import { mode } from 'theme/util/mode'; - -export type IAIToggleCollapseProps = PropsWithChildren & { - label: string; - activeLabel?: string; - defaultIsOpen?: boolean; -}; - -const IAICollapse = (props: IAIToggleCollapseProps) => { - const { label, activeLabel, children, defaultIsOpen = false } = props; - const { isOpen, onToggle } = useDisclosure({ defaultIsOpen }); - const { colorMode } = useColorMode(); - - return ( - - - {label} - - {activeLabel && ( - - - {activeLabel} - - - )} - - - - - - - {children} - - - - ); -}; - -export default memo(IAICollapse); diff --git a/invokeai/frontend/web/src/common/components/IAIColorPicker.tsx b/invokeai/frontend/web/src/common/components/IAIColorPicker.tsx index b61693c86a..7be6537dfe 100644 --- a/invokeai/frontend/web/src/common/components/IAIColorPicker.tsx +++ b/invokeai/frontend/web/src/common/components/IAIColorPicker.tsx @@ -1,8 +1,14 @@ -import { ChakraProps, Flex } from '@chakra-ui/react'; +import type { ChakraProps } from '@chakra-ui/react'; +import { Flex } from '@chakra-ui/react'; import { memo, useCallback } from 'react'; import { RgbaColorPicker } from 'react-colorful'; -import { ColorPickerBaseProps, RgbaColor } from 'react-colorful/dist/types'; -import IAINumberInput from './IAINumberInput'; +import type { + ColorPickerBaseProps, + RgbaColor, +} from 'react-colorful/dist/types'; + +import { InvControl } from './InvControl/InvControl'; +import { InvNumberInput } from './InvNumberInput/InvNumberInput'; type IAIColorPickerProps = ColorPickerBaseProps & { withNumberInput?: boolean; @@ -52,43 +58,46 @@ const IAIColorPicker = (props: IAIColorPickerProps) => { /> {withNumberInput && ( - - - - + + + + + + + + + + + + )} diff --git a/invokeai/frontend/web/src/common/components/IAIDndImage.tsx b/invokeai/frontend/web/src/common/components/IAIDndImage.tsx index eed8a1e49c..65c4a0e3bf 100644 --- a/invokeai/frontend/web/src/common/components/IAIDndImage.tsx +++ b/invokeai/frontend/web/src/common/components/IAIDndImage.tsx @@ -1,37 +1,29 @@ -import { - ChakraProps, - Flex, - FlexProps, - Icon, - Image, - useColorMode, -} from '@chakra-ui/react'; +import type { ChakraProps, FlexProps } from '@chakra-ui/react'; +import { Flex, Icon, Image } from '@chakra-ui/react'; import { IAILoadingImageFallback, IAINoContentFallback, } from 'common/components/IAIImageFallback'; import ImageMetadataOverlay from 'common/components/ImageMetadataOverlay'; import { useImageUploadButton } from 'common/hooks/useImageUploadButton'; +import type { + TypesafeDraggableData, + TypesafeDroppableData, +} from 'features/dnd/types'; import ImageContextMenu from 'features/gallery/components/ImageContextMenu/ImageContextMenu'; -import { +import type { MouseEvent, ReactElement, ReactNode, SyntheticEvent, - memo, - useCallback, - useState, } from 'react'; +import { memo, useCallback, useState } from 'react'; import { FaImage, FaUpload } from 'react-icons/fa'; -import { ImageDTO, PostUploadAction } from 'services/api/types'; -import { mode } from 'theme/util/mode'; +import type { ImageDTO, PostUploadAction } from 'services/api/types'; + import IAIDraggable from './IAIDraggable'; import IAIDroppable from './IAIDroppable'; import SelectionOverlay from './SelectionOverlay'; -import { - TypesafeDraggableData, - TypesafeDroppableData, -} from 'features/dnd/types'; const defaultUploadElement = ( { dataTestId, } = props; - const { colorMode } = useColorMode(); const [isHovered, setIsHovered] = useState(false); const handleMouseOver = useCallback( (e: MouseEvent) => { @@ -128,10 +119,10 @@ const IAIDndImage = (props: IAIDndImageProps) => { ? {} : { cursor: 'pointer', - bg: mode('base.200', 'base.700')(colorMode), + bg: 'base.700', _hover: { - bg: mode('base.300', 'base.650')(colorMode), - color: mode('base.500', 'base.300')(colorMode), + bg: 'base.650', + color: 'base.300', }, }; @@ -208,7 +199,7 @@ const IAIDndImage = (props: IAIDndImageProps) => { borderRadius: 'base', transitionProperty: 'common', transitionDuration: '0.1s', - color: mode('base.500', 'base.500')(colorMode), + color: 'base.500', ...uploadButtonStyles, }} {...getUploadButtonProps()} diff --git a/invokeai/frontend/web/src/common/components/IAIDndImageIcon.tsx b/invokeai/frontend/web/src/common/components/IAIDndImageIcon.tsx index 01755b764a..9975917203 100644 --- a/invokeai/frontend/web/src/common/components/IAIDndImageIcon.tsx +++ b/invokeai/frontend/web/src/common/components/IAIDndImageIcon.tsx @@ -1,6 +1,8 @@ -import { SystemStyleObject, useColorModeValue } from '@chakra-ui/react'; -import { MouseEvent, ReactElement, memo } from 'react'; -import IAIIconButton from './IAIIconButton'; +import type { SystemStyleObject } from '@chakra-ui/react'; +import type { MouseEvent, ReactElement } from 'react'; +import { memo } from 'react'; + +import { InvIconButton } from './InvIconButton/InvIconButton'; type Props = { onClick: (event: MouseEvent) => void; @@ -12,12 +14,8 @@ type Props = { const IAIDndImageIcon = (props: Props) => { const { onClick, tooltip, icon, styleOverrides } = props; - const resetIconShadow = useColorModeValue( - `drop-shadow(0px 0px 0.1rem var(--invokeai-colors-base-600))`, - `drop-shadow(0px 0px 0.1rem var(--invokeai-colors-base-800))` - ); return ( - { transitionDuration: 'normal', fill: 'base.100', _hover: { fill: 'base.50' }, - filter: resetIconShadow, + filter: 'drop-shadow(0px 0px 0.1rem var(--invokeai-colors-base-800))', }, ...styleOverrides, }} diff --git a/invokeai/frontend/web/src/common/components/IAIDraggable.tsx b/invokeai/frontend/web/src/common/components/IAIDraggable.tsx index 363799a573..1efabab12c 100644 --- a/invokeai/frontend/web/src/common/components/IAIDraggable.tsx +++ b/invokeai/frontend/web/src/common/components/IAIDraggable.tsx @@ -1,6 +1,7 @@ -import { Box, BoxProps } from '@chakra-ui/react'; +import type { BoxProps } from '@chakra-ui/react'; +import { Box } from '@chakra-ui/react'; import { useDraggableTypesafe } from 'features/dnd/hooks/typesafeHooks'; -import { TypesafeDraggableData } from 'features/dnd/types'; +import type { TypesafeDraggableData } from 'features/dnd/types'; import { memo, useRef } from 'react'; import { v4 as uuidv4 } from 'uuid'; diff --git a/invokeai/frontend/web/src/common/components/IAIDropOverlay.tsx b/invokeai/frontend/web/src/common/components/IAIDropOverlay.tsx index f9bb36cc50..83f4e8858c 100644 --- a/invokeai/frontend/web/src/common/components/IAIDropOverlay.tsx +++ b/invokeai/frontend/web/src/common/components/IAIDropOverlay.tsx @@ -1,7 +1,7 @@ -import { Box, Flex, useColorMode } from '@chakra-ui/react'; +import { Box, Flex } from '@chakra-ui/react'; import { motion } from 'framer-motion'; -import { ReactNode, memo, useRef } from 'react'; -import { mode } from 'theme/util/mode'; +import type { ReactNode } from 'react'; +import { memo, useRef } from 'react'; import { v4 as uuidv4 } from 'uuid'; type Props = { @@ -12,7 +12,6 @@ type Props = { export const IAIDropOverlay = (props: Props) => { const { isOver, label = 'Drop' } = props; const motionId = useRef(uuidv4()); - const { colorMode } = useColorMode(); return ( { insetInlineStart: 0, w: 'full', h: 'full', - bg: mode('base.700', 'base.900')(colorMode), + bg: 'base.900', opacity: 0.7, borderRadius: 'base', alignItems: 'center', @@ -63,9 +62,7 @@ export const IAIDropOverlay = (props: Props) => { bottom: 0.5, opacity: 1, borderWidth: 2, - borderColor: isOver - ? mode('base.50', 'base.50')(colorMode) - : mode('base.200', 'base.300')(colorMode), + borderColor: isOver ? 'base.50' : 'base.300', borderRadius: 'lg', borderStyle: 'dashed', transitionProperty: 'common', @@ -77,11 +74,9 @@ export const IAIDropOverlay = (props: Props) => { ; - isChecked?: boolean; -}; - -const IAIIconButton = forwardRef((props: IAIIconButtonProps, forwardedRef) => { - const { role, tooltip = '', tooltipProps, isChecked, ...rest } = props; - - return ( - - - - ); -}); - -IAIIconButton.displayName = 'IAIIconButton'; -export default memo(IAIIconButton); diff --git a/invokeai/frontend/web/src/common/components/IAIImageFallback.tsx b/invokeai/frontend/web/src/common/components/IAIImageFallback.tsx index 3c1a05d527..83f3d79f4a 100644 --- a/invokeai/frontend/web/src/common/components/IAIImageFallback.tsx +++ b/invokeai/frontend/web/src/common/components/IAIImageFallback.tsx @@ -1,15 +1,9 @@ -import { - As, - Flex, - FlexProps, - Icon, - Skeleton, - Spinner, - StyleProps, - Text, -} from '@chakra-ui/react'; +import type { As, FlexProps, StyleProps } from '@chakra-ui/react'; +import { Flex, Icon, Skeleton, Spinner } from '@chakra-ui/react'; import { FaImage } from 'react-icons/fa'; -import { ImageDTO } from 'services/api/types'; +import type { ImageDTO } from 'services/api/types'; + +import { InvText } from './InvText/wrapper'; type Props = { image: ImageDTO | undefined }; @@ -36,10 +30,7 @@ export const IAILoadingImageFallback = (props: Props) => { alignItems: 'center', justifyContent: 'center', borderRadius: 'base', - bg: 'base.200', - _dark: { - bg: 'base.900', - }, + bg: 'base.900', }} > @@ -68,16 +59,13 @@ export const IAINoContentFallback = (props: IAINoImageFallbackProps) => { gap: 2, userSelect: 'none', opacity: 0.7, - color: 'base.700', - _dark: { - color: 'base.500', - }, + color: 'base.500', ...sx, }} {...rest} > {icon && } - {props.label && {props.label}} + {props.label && {props.label}} ); }; @@ -103,16 +91,13 @@ export const IAINoContentFallbackWithSpinner = ( gap: 2, userSelect: 'none', opacity: 0.7, - color: 'base.700', - _dark: { - color: 'base.500', - }, + color: 'base.500', ...sx, }} {...rest} > - {props.label && {props.label}} + {props.label && {props.label}} ); }; diff --git a/invokeai/frontend/web/src/common/components/IAIInformationalPopover/IAIInformationalPopover.tsx b/invokeai/frontend/web/src/common/components/IAIInformationalPopover/IAIInformationalPopover.tsx index 6313bf1dc7..ed9ff41eb2 100644 --- a/invokeai/frontend/web/src/common/components/IAIInformationalPopover/IAIInformationalPopover.tsx +++ b/invokeai/frontend/web/src/common/components/IAIInformationalPopover/IAIInformationalPopover.tsx @@ -1,155 +1,155 @@ +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 { - Box, - BoxProps, - Button, - Divider, - Flex, - Heading, - Image, - Popover, - PopoverBody, - PopoverCloseButton, - PopoverContent, - PopoverProps, - PopoverTrigger, - Portal, - Text, - forwardRef, -} from '@chakra-ui/react'; + InvPopover, + InvPopoverBody, + InvPopoverCloseButton, + InvPopoverContent, + InvPopoverTrigger, +} from 'common/components/InvPopover/wrapper'; +import { InvText } from 'common/components/InvText/wrapper'; import { merge, omit } from 'lodash-es'; -import { PropsWithChildren, memo, useCallback, useMemo } from 'react'; +import type { ReactElement } from 'react'; +import { memo, useCallback, useMemo } from 'react'; import { useTranslation } from 'react-i18next'; import { FaExternalLinkAlt } from 'react-icons/fa'; -import { useAppSelector } from 'app/store/storeHooks'; -import { - Feature, - OPEN_DELAY, - POPOVER_DATA, - POPPER_MODIFIERS, -} from './constants'; -type Props = PropsWithChildren & { +import type { Feature, PopoverData } from './constants'; +import { OPEN_DELAY, POPOVER_DATA, POPPER_MODIFIERS } from './constants'; + +type Props = { feature: Feature; - wrapperProps?: BoxProps; - popoverProps?: PopoverProps; + inPortal?: boolean; + children: ReactElement; }; -const IAIInformationalPopover = forwardRef( - ({ feature, children, wrapperProps, ...rest }: Props, ref) => { - const { t } = useTranslation(); - const shouldEnableInformationalPopovers = useAppSelector( - (state) => state.system.shouldEnableInformationalPopovers - ); +const IAIInformationalPopover = ({ + feature, + children, + inPortal = true, + ...rest +}: Props) => { + const shouldEnableInformationalPopovers = useAppSelector( + (state) => state.system.shouldEnableInformationalPopovers + ); - const data = useMemo(() => POPOVER_DATA[feature], [feature]); + const data = useMemo(() => POPOVER_DATA[feature], [feature]); - const popoverProps = useMemo( - () => merge(omit(data, ['image', 'href', 'buttonLabel']), rest), - [data, rest] - ); + const popoverProps = useMemo( + () => merge(omit(data, ['image', 'href', 'buttonLabel']), rest), + [data, rest] + ); - const heading = useMemo( - () => t(`popovers.${feature}.heading`), - [feature, t] - ); - - const paragraphs = useMemo( - () => - t(`popovers.${feature}.paragraphs`, { - returnObjects: true, - }) ?? [], - [feature, t] - ); - - const handleClick = useCallback(() => { - if (!data?.href) { - return; - } - window.open(data.href); - }, [data?.href]); - - if (!shouldEnableInformationalPopovers) { - return ( - - {children} - - ); - } - - return ( - - - - {children} - - - - - - - - {heading && ( - <> - {heading} - - - )} - {data?.image && ( - <> - Optional Image - - - )} - {paragraphs.map((p) => ( - {p} - ))} - {data?.href && ( - <> - - - - )} - - - - - - ); + if (!shouldEnableInformationalPopovers) { + return children; } -); -IAIInformationalPopover.displayName = 'IAIInformationalPopover'; + return ( + + {children} + {inPortal ? ( + + + + ) : ( + + )} + + ); +}; export default memo(IAIInformationalPopover); + +type PopoverContentProps = { + data?: PopoverData; + feature: Feature; +}; + +const PopoverContent = ({ data, feature }: PopoverContentProps) => { + const { t } = useTranslation(); + + const heading = useMemo( + () => t(`popovers.${feature}.heading`), + [feature, t] + ); + + const paragraphs = useMemo( + () => + t(`popovers.${feature}.paragraphs`, { + returnObjects: true, + }) ?? [], + [feature, t] + ); + + const handleClick = useCallback(() => { + if (!data?.href) { + return; + } + window.open(data.href); + }, [data?.href]); + + return ( + + + + + {heading && ( + <> + {heading} + + + )} + {data?.image && ( + <> + Optional Image + + + )} + {paragraphs.map((p) => ( + {p} + ))} + {data?.href && ( + <> + + } + alignSelf="flex-end" + variant="link" + > + {t('common.learnMore') ?? heading} + + + )} + + + + ); +}; diff --git a/invokeai/frontend/web/src/common/components/IAIInformationalPopover/constants.ts b/invokeai/frontend/web/src/common/components/IAIInformationalPopover/constants.ts index 8960399b48..c48df92794 100644 --- a/invokeai/frontend/web/src/common/components/IAIInformationalPopover/constants.ts +++ b/invokeai/frontend/web/src/common/components/IAIInformationalPopover/constants.ts @@ -1,4 +1,4 @@ -import { PopoverProps } from '@chakra-ui/react'; +import type { PopoverProps } from '@chakra-ui/react'; export type Feature = | 'clipSkip' diff --git a/invokeai/frontend/web/src/common/components/IAIInput.tsx b/invokeai/frontend/web/src/common/components/IAIInput.tsx deleted file mode 100644 index 31dac20998..0000000000 --- a/invokeai/frontend/web/src/common/components/IAIInput.tsx +++ /dev/null @@ -1,82 +0,0 @@ -import { - FormControl, - FormControlProps, - FormLabel, - Input, - InputProps, -} from '@chakra-ui/react'; -import { useAppDispatch } from 'app/store/storeHooks'; -import { stopPastePropagation } from 'common/util/stopPastePropagation'; -import { shiftKeyPressed } from 'features/ui/store/hotkeysSlice'; -import { - CSSProperties, - ChangeEvent, - KeyboardEvent, - memo, - useCallback, -} from 'react'; - -interface IAIInputProps extends InputProps { - label?: string; - labelPos?: 'top' | 'side'; - value?: string; - size?: string; - onChange?: (e: ChangeEvent) => void; - formControlProps?: Omit; -} - -const labelPosVerticalStyle: CSSProperties = { - display: 'flex', - flexDirection: 'row', - alignItems: 'center', - gap: 10, -}; - -const IAIInput = (props: IAIInputProps) => { - const { - label = '', - labelPos = 'top', - isDisabled = false, - isInvalid, - formControlProps, - ...rest - } = props; - - const dispatch = useAppDispatch(); - const handleKeyDown = useCallback( - (e: KeyboardEvent) => { - if (e.shiftKey) { - dispatch(shiftKeyPressed(true)); - } - }, - [dispatch] - ); - - const handleKeyUp = useCallback( - (e: KeyboardEvent) => { - if (!e.shiftKey) { - dispatch(shiftKeyPressed(false)); - } - }, - [dispatch] - ); - - return ( - - {label !== '' && {label}} - - - ); -}; - -export default memo(IAIInput); diff --git a/invokeai/frontend/web/src/common/components/IAIMantineInput.tsx b/invokeai/frontend/web/src/common/components/IAIMantineInput.tsx deleted file mode 100644 index a324f80770..0000000000 --- a/invokeai/frontend/web/src/common/components/IAIMantineInput.tsx +++ /dev/null @@ -1,57 +0,0 @@ -import { useColorMode } from '@chakra-ui/react'; -import { TextInput, TextInputProps } from '@mantine/core'; -import { useChakraThemeTokens } from 'common/hooks/useChakraThemeTokens'; -import { useCallback } from 'react'; -import { mode } from 'theme/util/mode'; - -type IAIMantineTextInputProps = TextInputProps; - -export default function IAIMantineTextInput(props: IAIMantineTextInputProps) { - const { ...rest } = props; - const { - base50, - base100, - base200, - base300, - base800, - base700, - base900, - accent500, - accent300, - } = useChakraThemeTokens(); - const { colorMode } = useColorMode(); - - const stylesFunc = useCallback( - () => ({ - input: { - color: mode(base900, base100)(colorMode), - backgroundColor: mode(base50, base900)(colorMode), - borderColor: mode(base200, base800)(colorMode), - borderWidth: 2, - outline: 'none', - ':focus': { - borderColor: mode(accent300, accent500)(colorMode), - }, - }, - label: { - color: mode(base700, base300)(colorMode), - fontWeight: 'normal' as const, - marginBottom: 4, - }, - }), - [ - accent300, - accent500, - base100, - base200, - base300, - base50, - base700, - base800, - base900, - colorMode, - ] - ); - - return ; -} diff --git a/invokeai/frontend/web/src/common/components/IAIMantineMultiSelect.tsx b/invokeai/frontend/web/src/common/components/IAIMantineMultiSelect.tsx deleted file mode 100644 index 5ea17f788c..0000000000 --- a/invokeai/frontend/web/src/common/components/IAIMantineMultiSelect.tsx +++ /dev/null @@ -1,66 +0,0 @@ -import { FormControl, FormLabel, Tooltip, forwardRef } from '@chakra-ui/react'; -import { MultiSelect, MultiSelectProps } from '@mantine/core'; -import { useAppDispatch } from 'app/store/storeHooks'; -import { shiftKeyPressed } from 'features/ui/store/hotkeysSlice'; -import { useMantineMultiSelectStyles } from 'mantine-theme/hooks/useMantineMultiSelectStyles'; -import { KeyboardEvent, RefObject, memo, useCallback } from 'react'; - -type IAIMultiSelectProps = Omit & { - tooltip?: string | null; - inputRef?: RefObject; - label?: string; -}; - -const IAIMantineMultiSelect = forwardRef((props: IAIMultiSelectProps, ref) => { - const { - searchable = true, - tooltip, - inputRef, - label, - disabled, - ...rest - } = props; - const dispatch = useAppDispatch(); - - const handleKeyDown = useCallback( - (e: KeyboardEvent) => { - if (e.shiftKey) { - dispatch(shiftKeyPressed(true)); - } - }, - [dispatch] - ); - - const handleKeyUp = useCallback( - (e: KeyboardEvent) => { - if (!e.shiftKey) { - dispatch(shiftKeyPressed(false)); - } - }, - [dispatch] - ); - - const styles = useMantineMultiSelectStyles(); - - return ( - - - {label && {label}} - - - - ); -}); - -IAIMantineMultiSelect.displayName = 'IAIMantineMultiSelect'; - -export default memo(IAIMantineMultiSelect); diff --git a/invokeai/frontend/web/src/common/components/IAIMantineSearchableSelect.tsx b/invokeai/frontend/web/src/common/components/IAIMantineSearchableSelect.tsx deleted file mode 100644 index 675314b421..0000000000 --- a/invokeai/frontend/web/src/common/components/IAIMantineSearchableSelect.tsx +++ /dev/null @@ -1,100 +0,0 @@ -import { FormControl, FormLabel, Tooltip, forwardRef } from '@chakra-ui/react'; -import { Select, SelectProps } from '@mantine/core'; -import { useAppDispatch } from 'app/store/storeHooks'; -import { shiftKeyPressed } from 'features/ui/store/hotkeysSlice'; -import { useMantineSelectStyles } from 'mantine-theme/hooks/useMantineSelectStyles'; -import { KeyboardEvent, RefObject, memo, useCallback, useState } from 'react'; - -export type IAISelectDataType = { - value: string; - label: string; - tooltip?: string; -}; - -type IAISelectProps = Omit & { - tooltip?: string | null; - label?: string; - inputRef?: RefObject; -}; - -const IAIMantineSearchableSelect = forwardRef((props: IAISelectProps, ref) => { - const { - searchable = true, - tooltip, - inputRef, - onChange, - label, - disabled, - ...rest - } = props; - const dispatch = useAppDispatch(); - - const [searchValue, setSearchValue] = useState(''); - - // we want to capture shift keypressed even when an input is focused - const handleKeyDown = useCallback( - (e: KeyboardEvent) => { - if (e.shiftKey) { - dispatch(shiftKeyPressed(true)); - } - }, - [dispatch] - ); - - const handleKeyUp = useCallback( - (e: KeyboardEvent) => { - if (!e.shiftKey) { - dispatch(shiftKeyPressed(false)); - } - }, - [dispatch] - ); - - // wrap onChange to clear search value on select - const handleChange = useCallback( - (v: string | null) => { - // cannot figure out why we were doing this, but it was causing an issue where if you - // select the currently-selected item, it reset the search value to empty - // setSearchValue(''); - - if (!onChange) { - return; - } - - onChange(v); - }, - [onChange] - ); - - const styles = useMantineSelectStyles(); - - return ( - - - {label && {label}} - - - - ); -}); - -IAIMantineSelect.displayName = 'IAIMantineSelect'; - -export default memo(IAIMantineSelect); diff --git a/invokeai/frontend/web/src/common/components/IAIMantineSelectItemWithDescription.tsx b/invokeai/frontend/web/src/common/components/IAIMantineSelectItemWithDescription.tsx deleted file mode 100644 index a61268c99e..0000000000 --- a/invokeai/frontend/web/src/common/components/IAIMantineSelectItemWithDescription.tsx +++ /dev/null @@ -1,29 +0,0 @@ -import { Box, Text } from '@chakra-ui/react'; -import { forwardRef, memo } from 'react'; - -interface ItemProps extends React.ComponentPropsWithoutRef<'div'> { - label: string; - value: string; - description?: string; -} - -const IAIMantineSelectItemWithDescription = forwardRef< - HTMLDivElement, - ItemProps ->(({ label, description, ...rest }: ItemProps, ref) => ( - - - {label} - {description && ( - - {description} - - )} - - -)); - -IAIMantineSelectItemWithDescription.displayName = - 'IAIMantineSelectItemWithDescription'; - -export default memo(IAIMantineSelectItemWithDescription); diff --git a/invokeai/frontend/web/src/common/components/IAIMantineSelectItemWithTooltip.tsx b/invokeai/frontend/web/src/common/components/IAIMantineSelectItemWithTooltip.tsx deleted file mode 100644 index 056bd4a8fa..0000000000 --- a/invokeai/frontend/web/src/common/components/IAIMantineSelectItemWithTooltip.tsx +++ /dev/null @@ -1,34 +0,0 @@ -import { Box, Tooltip } from '@chakra-ui/react'; -import { Text } from '@mantine/core'; -import { forwardRef, memo } from 'react'; - -interface ItemProps extends React.ComponentPropsWithoutRef<'div'> { - label: string; - description?: string; - tooltip?: string; - disabled?: boolean; -} - -const IAIMantineSelectItemWithTooltip = forwardRef( - ( - { label, tooltip, description, disabled: _disabled, ...others }: ItemProps, - ref - ) => ( - - - - {label} - {description && ( - - {description} - - )} - - - - ) -); - -IAIMantineSelectItemWithTooltip.displayName = 'IAIMantineSelectItemWithTooltip'; - -export default memo(IAIMantineSelectItemWithTooltip); diff --git a/invokeai/frontend/web/src/common/components/IAINumberInput.tsx b/invokeai/frontend/web/src/common/components/IAINumberInput.tsx deleted file mode 100644 index cef39d7b96..0000000000 --- a/invokeai/frontend/web/src/common/components/IAINumberInput.tsx +++ /dev/null @@ -1,186 +0,0 @@ -import { - FormControl, - FormControlProps, - FormLabel, - FormLabelProps, - NumberDecrementStepper, - NumberIncrementStepper, - NumberInput, - NumberInputField, - NumberInputFieldProps, - NumberInputProps, - NumberInputStepper, - NumberInputStepperProps, - Tooltip, - TooltipProps, - forwardRef, -} from '@chakra-ui/react'; -import { useAppDispatch } from 'app/store/storeHooks'; -import { stopPastePropagation } from 'common/util/stopPastePropagation'; -import { shiftKeyPressed } from 'features/ui/store/hotkeysSlice'; -import { clamp } from 'lodash-es'; -import { - FocusEvent, - KeyboardEvent, - memo, - useCallback, - useEffect, - useState, -} from 'react'; - -export const numberStringRegex = /^-?(0\.)?\.?$/; - -interface Props extends Omit { - label?: string; - showStepper?: boolean; - value?: number; - onChange: (v: number) => void; - min: number; - max: number; - clamp?: boolean; - isInteger?: boolean; - formControlProps?: FormControlProps; - formLabelProps?: FormLabelProps; - numberInputProps?: NumberInputProps; - numberInputFieldProps?: NumberInputFieldProps; - numberInputStepperProps?: NumberInputStepperProps; - tooltipProps?: Omit; -} - -/** - * Customized Chakra FormControl + NumberInput multi-part component. - */ -const IAINumberInput = forwardRef((props: Props, ref) => { - const { - label, - isDisabled = false, - showStepper = true, - isInvalid, - value, - onChange, - min, - max, - isInteger = true, - formControlProps, - formLabelProps, - numberInputFieldProps, - numberInputStepperProps, - tooltipProps, - ...rest - } = props; - - const dispatch = useAppDispatch(); - - /** - * Using a controlled input with a value that accepts decimals needs special - * handling. If the user starts to type in "1.5", by the time they press the - * 5, the value has been parsed from "1." to "1" and they end up with "15". - * - * To resolve this, this component keeps a the value as a string internally, - * and the UI component uses that. When a change is made, that string is parsed - * as a number and given to the `onChange` function. - */ - - const [valueAsString, setValueAsString] = useState(String(value)); - - /** - * 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 ( - !valueAsString.match(numberStringRegex) && - value !== Number(valueAsString) - ) { - setValueAsString(String(value)); - } - }, [value, valueAsString]); - - const handleOnChange = useCallback( - (v: string) => { - setValueAsString(v); - // This allows negatives and decimals e.g. '-123', `.5`, `-0.2`, etc. - if (!v.match(numberStringRegex)) { - // Cast the value to number. Floor it if it should be an integer. - onChange(isInteger ? Math.floor(Number(v)) : Number(v)); - } - }, - [isInteger, onChange] - ); - - /** - * Clicking the steppers allows the value to go outside bounds; we need to - * clamp it on blur and floor it if needed. - */ - const handleBlur = useCallback( - (e: FocusEvent) => { - const clamped = clamp( - isInteger ? Math.floor(Number(e.target.value)) : Number(e.target.value), - min, - max - ); - setValueAsString(String(clamped)); - onChange(clamped); - }, - [isInteger, max, min, onChange] - ); - - const handleKeyDown = useCallback( - (e: KeyboardEvent) => { - if (e.shiftKey) { - dispatch(shiftKeyPressed(true)); - } - }, - [dispatch] - ); - - const handleKeyUp = useCallback( - (e: KeyboardEvent) => { - if (!e.shiftKey) { - dispatch(shiftKeyPressed(false)); - } - }, - [dispatch] - ); - - return ( - - - {label && {label}} - - - {showStepper && ( - - - - - )} - - - - ); -}); - -IAINumberInput.displayName = 'IAINumberInput'; - -export default memo(IAINumberInput); diff --git a/invokeai/frontend/web/src/common/components/IAIOption.tsx b/invokeai/frontend/web/src/common/components/IAIOption.tsx deleted file mode 100644 index 9c8a611160..0000000000 --- a/invokeai/frontend/web/src/common/components/IAIOption.tsx +++ /dev/null @@ -1,18 +0,0 @@ -import { useToken } from '@chakra-ui/react'; -import { ReactNode } from 'react'; - -type IAIOptionProps = { - children: ReactNode | string | number; - value: string | number; -}; - -export default function IAIOption(props: IAIOptionProps) { - const { children, value } = props; - const [base800, base200] = useToken('colors', ['base.800', 'base.200']); - - return ( - - ); -} diff --git a/invokeai/frontend/web/src/common/components/IAIPopover.tsx b/invokeai/frontend/web/src/common/components/IAIPopover.tsx deleted file mode 100644 index 51562b969c..0000000000 --- a/invokeai/frontend/web/src/common/components/IAIPopover.tsx +++ /dev/null @@ -1,38 +0,0 @@ -import { - BoxProps, - Popover, - PopoverArrow, - PopoverContent, - PopoverProps, - PopoverTrigger, -} from '@chakra-ui/react'; -import { memo, ReactNode } from 'react'; - -export type IAIPopoverProps = PopoverProps & { - triggerComponent: ReactNode; - triggerContainerProps?: BoxProps; - children: ReactNode; - hasArrow?: boolean; -}; - -const IAIPopover = (props: IAIPopoverProps) => { - const { - triggerComponent, - children, - hasArrow = true, - isLazy = true, - ...rest - } = props; - - return ( - - {triggerComponent} - - {hasArrow && } - {children} - - - ); -}; - -export default memo(IAIPopover); diff --git a/invokeai/frontend/web/src/common/components/IAIScrollArea.tsx b/invokeai/frontend/web/src/common/components/IAIScrollArea.tsx deleted file mode 100644 index 5dc96859b5..0000000000 --- a/invokeai/frontend/web/src/common/components/IAIScrollArea.tsx +++ /dev/null @@ -1,12 +0,0 @@ -import { ScrollArea, ScrollAreaProps } from '@mantine/core'; - -type IAIScrollArea = ScrollAreaProps; - -export default function IAIScrollArea(props: IAIScrollArea) { - const { ...rest } = props; - return ( - - {props.children} - - ); -} diff --git a/invokeai/frontend/web/src/common/components/IAISelect.tsx b/invokeai/frontend/web/src/common/components/IAISelect.tsx deleted file mode 100644 index faa5732017..0000000000 --- a/invokeai/frontend/web/src/common/components/IAISelect.tsx +++ /dev/null @@ -1,85 +0,0 @@ -import { - FormControl, - FormLabel, - Select, - SelectProps, - Tooltip, - TooltipProps, -} from '@chakra-ui/react'; -import { memo, MouseEvent, useCallback } from 'react'; -import IAIOption from './IAIOption'; - -type IAISelectProps = SelectProps & { - label?: string; - tooltip?: string; - tooltipProps?: Omit; - validValues: - | Array - | Array<{ key: string; value: string | number }>; - horizontal?: boolean; - spaceEvenly?: boolean; -}; -/** - * Customized Chakra FormControl + Select multi-part component. - */ -const IAISelect = (props: IAISelectProps) => { - const { - label, - isDisabled, - validValues, - tooltip, - tooltipProps, - horizontal, - spaceEvenly, - ...rest - } = props; - const handleClick = useCallback((e: MouseEvent) => { - e.stopPropagation(); - e.nativeEvent.stopImmediatePropagation(); - e.nativeEvent.stopPropagation(); - e.nativeEvent.cancelBubble = true; - }, []); - return ( - - {label && ( - - {label} - - )} - - - - - ); -}; - -export default memo(IAISelect); diff --git a/invokeai/frontend/web/src/common/components/IAISimpleCheckbox.tsx b/invokeai/frontend/web/src/common/components/IAISimpleCheckbox.tsx deleted file mode 100644 index 47e328727d..0000000000 --- a/invokeai/frontend/web/src/common/components/IAISimpleCheckbox.tsx +++ /dev/null @@ -1,26 +0,0 @@ -import { Checkbox, CheckboxProps, Text, useColorMode } from '@chakra-ui/react'; -import { memo, ReactElement } from 'react'; -import { mode } from 'theme/util/mode'; - -type IAISimpleCheckboxProps = CheckboxProps & { - label: string | ReactElement; -}; - -const IAISimpleCheckbox = (props: IAISimpleCheckboxProps) => { - const { label, ...rest } = props; - const { colorMode } = useColorMode(); - return ( - - - {label} - - - ); -}; - -export default memo(IAISimpleCheckbox); diff --git a/invokeai/frontend/web/src/common/components/IAISimpleMenu.tsx b/invokeai/frontend/web/src/common/components/IAISimpleMenu.tsx deleted file mode 100644 index 83a60887b5..0000000000 --- a/invokeai/frontend/web/src/common/components/IAISimpleMenu.tsx +++ /dev/null @@ -1,88 +0,0 @@ -import { - Menu, - MenuButton, - MenuItem, - MenuList, - MenuProps, - MenuListProps, - MenuItemProps, - IconButton, - Button, - IconButtonProps, - ButtonProps, -} from '@chakra-ui/react'; -import { memo, MouseEventHandler, ReactNode } from 'react'; -import { MdArrowDropDown, MdArrowDropUp } from 'react-icons/md'; - -interface IAIMenuItem { - item: ReactNode | string; - onClick: MouseEventHandler | undefined; -} - -interface IAIMenuProps { - menuType?: 'icon' | 'regular'; - buttonText?: string; - iconTooltip?: string; - isLazy?: boolean; - menuItems: IAIMenuItem[]; - menuProps?: MenuProps; - menuButtonProps?: IconButtonProps | ButtonProps; - menuListProps?: MenuListProps; - menuItemProps?: MenuItemProps; -} - -const IAISimpleMenu = (props: IAIMenuProps) => { - const { - menuType = 'icon', - iconTooltip, - buttonText, - isLazy = true, - menuItems, - menuProps, - menuButtonProps, - menuListProps, - menuItemProps, - } = props; - - const renderMenuItems = () => { - const menuItemsToRender: ReactNode[] = []; - menuItems.forEach((menuItem, index) => { - menuItemsToRender.push( - - {menuItem.item} - - ); - }); - return menuItemsToRender; - }; - - return ( - - {({ isOpen }) => ( - <> - : } - paddingX={0} - paddingY={menuType === 'regular' ? 2 : 0} - {...menuButtonProps} - > - {menuType === 'regular' && buttonText} - - - {renderMenuItems()} - - - )} - - ); -}; - -export default memo(IAISimpleMenu); diff --git a/invokeai/frontend/web/src/common/components/IAISlider.tsx b/invokeai/frontend/web/src/common/components/IAISlider.tsx deleted file mode 100644 index 3ed3ee1920..0000000000 --- a/invokeai/frontend/web/src/common/components/IAISlider.tsx +++ /dev/null @@ -1,366 +0,0 @@ -import { - FormControl, - FormControlProps, - FormLabel, - FormLabelProps, - HStack, - NumberDecrementStepper, - NumberIncrementStepper, - NumberInput, - NumberInputField, - NumberInputFieldProps, - NumberInputProps, - NumberInputStepper, - NumberInputStepperProps, - Slider, - SliderFilledTrack, - SliderMark, - SliderMarkProps, - SliderThumb, - SliderThumbProps, - SliderTrack, - SliderTrackProps, - Tooltip, - TooltipProps, - forwardRef, -} from '@chakra-ui/react'; -import { useAppDispatch } from 'app/store/storeHooks'; -import { roundDownToMultiple } from 'common/util/roundDownToMultiple'; -import { shiftKeyPressed } from 'features/ui/store/hotkeysSlice'; -import { clamp } from 'lodash-es'; -import { - FocusEvent, - KeyboardEvent, - MouseEvent, - memo, - useCallback, - useEffect, - useMemo, - useState, -} from 'react'; -import { useTranslation } from 'react-i18next'; -import { BiReset } from 'react-icons/bi'; -import IAIIconButton, { IAIIconButtonProps } from './IAIIconButton'; - -export type IAIFullSliderProps = { - label?: string; - value: number; - min?: number; - max?: number; - step?: number; - onChange: (v: number) => void; - withSliderMarks?: boolean; - withInput?: boolean; - isInteger?: boolean; - inputWidth?: string | number; - withReset?: boolean; - handleReset?: () => void; - tooltipSuffix?: string; - hideTooltip?: boolean; - isCompact?: boolean; - isDisabled?: boolean; - sliderMarks?: number[]; - sliderFormControlProps?: FormControlProps; - sliderFormLabelProps?: FormLabelProps; - sliderMarkProps?: Omit; - sliderTrackProps?: SliderTrackProps; - sliderThumbProps?: SliderThumbProps; - sliderNumberInputProps?: NumberInputProps; - sliderNumberInputFieldProps?: NumberInputFieldProps; - sliderNumberInputStepperProps?: NumberInputStepperProps; - sliderTooltipProps?: Omit; - sliderIAIIconButtonProps?: IAIIconButtonProps; -}; - -const IAISlider = forwardRef((props: IAIFullSliderProps, ref) => { - const [showTooltip, setShowTooltip] = useState(false); - const { - label, - value, - min = 1, - max = 100, - step = 1, - onChange, - tooltipSuffix = '', - withSliderMarks = false, - withInput = false, - isInteger = false, - inputWidth = 16, - withReset = false, - hideTooltip = false, - isCompact = false, - isDisabled = false, - sliderMarks, - handleReset, - sliderFormControlProps, - sliderFormLabelProps, - sliderMarkProps, - sliderTrackProps, - sliderThumbProps, - sliderNumberInputProps, - sliderNumberInputFieldProps, - sliderNumberInputStepperProps, - sliderTooltipProps, - sliderIAIIconButtonProps, - ...rest - } = props; - const dispatch = useAppDispatch(); - const { t } = useTranslation(); - - const [localInputValue, setLocalInputValue] = useState< - string | number | undefined - >(String(value)); - - useEffect(() => { - setLocalInputValue(value); - }, [value]); - - const numberInputMin = useMemo( - () => (sliderNumberInputProps?.min ? sliderNumberInputProps.min : min), - [min, sliderNumberInputProps?.min] - ); - - const numberInputMax = useMemo( - () => (sliderNumberInputProps?.max ? sliderNumberInputProps.max : max), - [max, sliderNumberInputProps?.max] - ); - - const handleSliderChange = useCallback( - (v: number) => { - onChange(v); - }, - [onChange] - ); - - const handleInputBlur = useCallback( - (e: FocusEvent) => { - if (e.target.value === '') { - e.target.value = String(numberInputMin); - } - const clamped = clamp( - isInteger - ? Math.floor(Number(e.target.value)) - : Number(localInputValue), - numberInputMin, - numberInputMax - ); - const quantized = roundDownToMultiple(clamped, step); - onChange(quantized); - setLocalInputValue(quantized); - }, - [isInteger, localInputValue, numberInputMin, numberInputMax, onChange, step] - ); - - const handleInputChange = useCallback((v: number | string) => { - setLocalInputValue(v); - }, []); - - const handleResetDisable = useCallback(() => { - if (!handleReset) { - return; - } - handleReset(); - }, [handleReset]); - - const forceInputBlur = useCallback((e: MouseEvent) => { - if (e.target instanceof HTMLDivElement) { - e.target.focus(); - } - }, []); - - const handleKeyDown = useCallback( - (e: KeyboardEvent) => { - if (e.shiftKey) { - dispatch(shiftKeyPressed(true)); - } - }, - [dispatch] - ); - - const handleKeyUp = useCallback( - (e: KeyboardEvent) => { - if (!e.shiftKey) { - dispatch(shiftKeyPressed(false)); - } - }, - [dispatch] - ); - - const handleMouseEnter = useCallback(() => setShowTooltip(true), []); - const handleMouseLeave = useCallback(() => setShowTooltip(false), []); - const handleStepperClick = useCallback( - () => onChange(Number(localInputValue)), - [localInputValue, onChange] - ); - - return ( - - {label && ( - - {label} - - )} - - - - {withSliderMarks && !sliderMarks && ( - <> - - {min} - - - {max} - - - )} - {withSliderMarks && sliderMarks && ( - <> - {sliderMarks.map((m, i) => { - if (i === 0) { - return ( - - {m} - - ); - } else if (i === sliderMarks.length - 1) { - return ( - - {m} - - ); - } else { - return ( - - {m} - - ); - } - })} - - )} - - - - - - - - - {withInput && ( - - - - - - - - )} - - {withReset && ( - } - isDisabled={isDisabled} - onClick={handleResetDisable} - {...sliderIAIIconButtonProps} - /> - )} - - - ); -}); - -IAISlider.displayName = 'IAISlider'; - -export default memo(IAISlider); diff --git a/invokeai/frontend/web/src/common/components/IAISwitch.tsx b/invokeai/frontend/web/src/common/components/IAISwitch.tsx deleted file mode 100644 index 8773be49e5..0000000000 --- a/invokeai/frontend/web/src/common/components/IAISwitch.tsx +++ /dev/null @@ -1,77 +0,0 @@ -import { - Flex, - FormControl, - FormControlProps, - FormHelperText, - FormLabel, - FormLabelProps, - Switch, - SwitchProps, - Text, - Tooltip, -} from '@chakra-ui/react'; -import { memo } from 'react'; - -export interface IAISwitchProps extends SwitchProps { - label?: string; - width?: string | number; - formControlProps?: FormControlProps; - formLabelProps?: FormLabelProps; - tooltip?: string; - helperText?: string; -} - -/** - * Customized Chakra FormControl + Switch multi-part component. - */ -const IAISwitch = (props: IAISwitchProps) => { - const { - label, - isDisabled = false, - width = 'auto', - formControlProps, - formLabelProps, - tooltip, - helperText, - ...rest - } = props; - return ( - - - - - {label && ( - - {label} - - )} - - - {helperText && ( - - {helperText} - - )} - - - - ); -}; - -IAISwitch.displayName = 'IAISwitch'; - -export default memo(IAISwitch); diff --git a/invokeai/frontend/web/src/common/components/IAITextarea.tsx b/invokeai/frontend/web/src/common/components/IAITextarea.tsx deleted file mode 100644 index e29c6fe513..0000000000 --- a/invokeai/frontend/web/src/common/components/IAITextarea.tsx +++ /dev/null @@ -1,38 +0,0 @@ -import { Textarea, TextareaProps, forwardRef } from '@chakra-ui/react'; -import { useAppDispatch } from 'app/store/storeHooks'; -import { stopPastePropagation } from 'common/util/stopPastePropagation'; -import { shiftKeyPressed } from 'features/ui/store/hotkeysSlice'; -import { KeyboardEvent, memo, useCallback } from 'react'; - -const IAITextarea = forwardRef((props: TextareaProps, ref) => { - const dispatch = useAppDispatch(); - const handleKeyDown = useCallback( - (e: KeyboardEvent) => { - if (e.shiftKey) { - dispatch(shiftKeyPressed(true)); - } - }, - [dispatch] - ); - - const handleKeyUp = useCallback( - (e: KeyboardEvent) => { - if (!e.shiftKey) { - dispatch(shiftKeyPressed(false)); - } - }, - [dispatch] - ); - - return ( -