From 6c7191712fe16a1f57052e366676f16824c2a7fb Mon Sep 17 00:00:00 2001 From: psychedelicious <4822129+psychedelicious@users.noreply.github.com> Date: Fri, 11 Nov 2022 06:54:06 +1100 Subject: [PATCH] Rebases against development --- backend/invoke_ai_web_server.py | 365 ++++- .../get_outpainting_generation_mode.py | 117 ++ .../init-img_full_transparency.png | Bin 0 -> 2731 bytes .../modules/test_images/init-img_opaque.png | Bin 0 -> 299473 bytes .../init-img_partial_transparency.png | Bin 0 -> 167798 bytes .../test_images/init-mask_has_mask.png | Bin 0 -> 9684 bytes .../modules/test_images/init-mask_no_mask.png | Bin 0 -> 3513 bytes frontend/README.md | 4 +- frontend/eslintconfig.json | 23 + frontend/package.json | 9 +- frontend/src/app/App.scss | 4 + frontend/src/app/App.tsx | 42 +- frontend/src/app/constants.ts | 2 +- frontend/src/app/invokeai.d.ts | 25 +- .../src/app/selectors/readinessSelector.ts | 31 +- frontend/src/app/socketio/actions.ts | 6 +- frontend/src/app/socketio/emitters.ts | 45 +- frontend/src/app/socketio/listeners.ts | 35 +- frontend/src/app/socketio/middleware.ts | 11 +- frontend/src/app/store.ts | 133 +- frontend/src/common/components/GuideIcon.tsx | 2 +- .../src/common/components/GuidePopover.scss | 8 +- .../src/common/components/GuidePopover.tsx | 8 +- frontend/src/common/components/IAIButton.scss | 7 +- .../src/common/components/IAICheckbox.scss | 2 +- .../src/common/components/IAIIconButton.scss | 55 +- .../src/common/components/IAIIconButton.tsx | 16 +- .../src/common/components/IAINumberInput.scss | 12 +- .../src/common/components/IAINumberInput.tsx | 3 + .../src/common/components/IAIPopover.scss | 8 +- frontend/src/common/components/IAIPopover.tsx | 2 +- frontend/src/common/components/IAISelect.scss | 1 + frontend/src/common/components/IAISelect.tsx | 23 +- frontend/src/common/components/IAISlider.scss | 80 +- frontend/src/common/components/IAISlider.tsx | 248 ++- .../common/components/ImageUploadOverlay.tsx | 1 + .../src/common/components/ImageUploader.scss | 11 +- .../src/common/components/ImageUploader.tsx | 30 +- .../common/components/ImageUploaderButton.tsx | 2 +- .../components/ImageUploaderIconButton.tsx | 2 +- .../WorkInProgress/ImageToImageWIP.tsx | 2 +- .../src/common/util/openBase64ImageInTab.ts | 21 + .../src/common/util/parameterTranslation.ts | 106 +- frontend/src/common/util/promptToString.ts | 2 +- frontend/src/common/util/seedWeightPairs.ts | 2 +- frontend/src/features/canvas/IAICanvas.tsx | 275 ++++ .../IAICanvasBoundingBoxPreview.tsx} | 298 ++-- .../canvas/IAICanvasBrushButtonPopover.tsx | 95 ++ .../features/canvas/IAICanvasBrushPreview.tsx | 121 ++ .../src/features/canvas/IAICanvasControls.tsx | 100 ++ .../IAICanvasBrushControl.tsx} | 56 +- .../IAICanvasClearImageControl.tsx} | 9 +- .../IAICanvasEraserControl.tsx | 61 + .../IAICanvasImageEraserControl.tsx | 60 + .../IAICanvasLockBoundingBoxControl.tsx | 47 + .../IAICanvasMaskControl.tsx | 38 + .../IAICanvasBrushColorPicker.tsx | 75 + .../IAICanvasMaskClear.tsx | 77 + .../IAICanvasMaskColorPicker.tsx} | 50 +- .../IAICanvasMaskInvertControl.tsx} | 41 +- .../IAICanvasMaskVisibilityControl.tsx | 60 + .../IAICanvasControls/IAICanvasRedoButton.tsx | 57 + .../IAICanvasShowHideBoundingBoxControl.tsx | 46 + .../IAICanvasSplitLayoutControl.tsx} | 17 +- .../IAICanvasControls/IAICanvasUndoButton.tsx | 58 + .../canvas/IAICanvasEraserButtonPopover.tsx | 71 + .../features/canvas/IAICanvasEraserLines.tsx | 49 + .../src/features/canvas/IAICanvasGrid.tsx | 88 ++ .../src/features/canvas/IAICanvasImage.tsx | 15 + .../canvas/IAICanvasIntermediateImage.tsx | 59 + .../canvas/IAICanvasMaskButtonPopover.tsx | 69 + .../canvas/IAICanvasMaskCompositer.tsx | 49 + .../features/canvas/IAICanvasMaskLines.tsx | 64 + .../canvas/IAICanvasOutpaintingControls.tsx | 112 ++ .../canvas/IAICanvasOutpaintingObjects.tsx | 65 + .../src/features/canvas/IAICanvasResizer.tsx | 78 + .../canvas/IAICanvasSettingsButtonPopover.tsx | 101 ++ .../features/canvas/IAICanvasStatusText.tsx | 74 + frontend/src/features/canvas/canvasSlice.ts | 764 +++++++++ .../canvas/hooks/useCanvasDragMove.ts | 49 + .../features/canvas/hooks/useCanvasHotkeys.ts | 111 ++ .../canvas/hooks/useCanvasMouseDown.ts | 56 + .../canvas/hooks/useCanvasMouseEnter.ts | 48 + .../canvas/hooks/useCanvasMouseMove.ts | 64 + .../canvas/hooks/useCanvasMouseOut.ts | 15 + .../features/canvas/hooks/useCanvasMouseUp.ts | 64 + .../features/canvas/hooks/useCanvasZoom.ts | 83 + .../canvas/hooks/useUnscaleCanvasValue.ts | 23 + .../util/colorToString.ts | 0 .../Inpainting => canvas}/util/constants.ts | 4 + .../src/features/canvas/util/generateMask.ts | 64 + .../util/getScaledCursorPosition.ts | 0 .../features/gallery/CurrentImageButtons.scss | 7 + .../features/gallery/CurrentImageButtons.tsx | 89 +- .../features/gallery/CurrentImageDisplay.scss | 1 + .../features/gallery/CurrentImageDisplay.tsx | 6 +- .../features/gallery/CurrentImagePreview.tsx | 9 +- .../src/features/gallery/DeleteImageModal.tsx | 10 +- .../src/features/gallery/HoverableImage.tsx | 32 +- .../src/features/gallery/ImageGallery.scss | 35 +- .../src/features/gallery/ImageGallery.tsx | 141 +- .../ImageMetadataViewer.tsx | 10 +- frontend/src/features/gallery/gallerySlice.ts | 13 +- .../features/gallery/gallerySliceSelectors.ts | 12 +- frontend/src/features/lightbox/Lightbox.scss | 74 + frontend/src/features/lightbox/Lightbox.tsx | 116 ++ .../src/features/lightbox/ReactPanZoom.tsx | 155 ++ .../AccordionItems/AdvancedSettings.scss | 17 +- .../AccordionItems/InvokeAccordionItem.tsx | 4 +- .../FaceRestore/FaceRestoreHeader.tsx | 6 +- .../FaceRestore/FaceRestoreOptions.tsx | 14 +- .../AdvancedOptions/ImageToImage/ImageFit.tsx | 6 +- .../ImageToImage/ImageToImageStrength.tsx | 33 +- .../BoundingBoxDarkenOutside.tsx | 29 +- .../BoundingBoxDimensionSlider.tsx | 86 +- .../BoundingBoxSettings/BoundingBoxLock.tsx | 22 +- .../BoundingBoxSettings.scss | 14 +- .../BoundingBoxSettings.tsx | 4 +- .../BoundingBoxVisibility.tsx | 22 +- .../Inpainting/ClearBrushHistory.tsx | 24 +- .../Inpainting/InpaintReplace.tsx | 49 +- .../AdvancedOptions/Output/HiresOptions.tsx | 6 +- .../Output/SeamlessOptions.tsx | 6 +- .../options/AdvancedOptions/Seed/Perlin.tsx | 6 +- .../AdvancedOptions/Seed/RandomizeSeed.tsx | 6 +- .../options/AdvancedOptions/Seed/Seed.tsx | 8 +- .../AdvancedOptions/Seed/ShuffleSeed.tsx | 12 +- .../AdvancedOptions/Seed/Threshold.tsx | 6 +- .../AdvancedOptions/Upscale/UpscaleHeader.tsx | 6 +- .../Upscale/UpscaleOptions.tsx | 14 +- .../Variations/GenerateVariations.tsx | 6 +- .../Variations/SeedWeights.tsx | 8 +- .../Variations/VariationAmount.tsx | 6 +- .../MainAdvancedOptionsCheckbox.tsx | 6 +- .../options/MainOptions/MainCFGScale.tsx | 9 +- .../options/MainOptions/MainHeight.tsx | 12 +- .../options/MainOptions/MainIterations.tsx | 12 +- .../options/MainOptions/MainOptions.scss | 21 +- .../options/MainOptions/MainOptions.tsx | 1 - .../options/MainOptions/MainSampler.tsx | 10 +- .../options/MainOptions/MainSteps.tsx | 9 +- .../options/MainOptions/MainWidth.tsx | 12 +- .../src/features/options/OptionsAccordion.tsx | 4 +- .../options/ProcessButtons/CancelButton.tsx | 8 +- .../options/ProcessButtons/InvokeButton.tsx | 36 +- .../options/ProcessButtons/Loopback.tsx | 6 +- .../ProcessButtons/ProcessButtons.scss | 19 +- .../options/PromptInput/PromptInput.tsx | 10 +- .../src/features/options/optionsSelectors.ts | 4 +- frontend/src/features/options/optionsSlice.ts | 22 +- frontend/src/features/system/Console.scss | 20 +- frontend/src/features/system/Console.tsx | 4 +- .../system/HotkeysModal/HotkeysModal.scss | 9 +- .../system/HotkeysModal/HotkeysModal.tsx | 47 +- frontend/src/features/system/Modal.scss | 10 + frontend/src/features/system/ProgressBar.scss | 2 +- frontend/src/features/system/ProgressBar.tsx | 6 +- .../system/SettingsModal/ModelList.scss | 11 +- .../system/SettingsModal/ModelList.tsx | 8 +- .../system/SettingsModal/SettingsModal.scss | 1 - .../system/SettingsModal/SettingsModal.tsx | 45 +- frontend/src/features/system/SiteHeader.scss | 11 + frontend/src/features/system/SiteHeader.tsx | 32 +- .../src/features/system/StatusIndicator.tsx | 2 +- frontend/src/features/system/ThemeChanger.tsx | 29 + frontend/src/features/system/systemSlice.ts | 8 +- .../src/features/tabs/FloatingButton.scss | 28 +- .../features/tabs/FloatingGalleryButton.tsx | 17 +- .../tabs/FloatingOptionsPanelButtons.tsx | 20 +- .../tabs/ImageToImage/ImageToImage.scss | 9 +- .../tabs/ImageToImage/ImageToImageDisplay.tsx | 6 +- .../tabs/ImageToImage/ImageToImagePanel.tsx | 40 +- .../tabs/ImageToImage/InitImagePreview.tsx | 6 +- .../tabs/ImageToImage/InitialImageOverlay.tsx | 2 +- .../src/features/tabs/ImageToImage/index.tsx | 2 +- .../tabs/Inpainting/InpaintingCanvas.tsx | 309 ---- .../InpaintingCanvasPlaceholder.tsx | 36 - .../InpaintingCanvasStatusIcons.scss | 29 - .../InpaintingCanvasStatusIcons.tsx | 126 -- .../tabs/Inpainting/InpaintingControls.tsx | 40 - .../InpaintingEraserControl.tsx | 67 - .../InpaintingLockBoundingBoxControl.tsx | 29 - .../InpaintingMaskControl.tsx | 38 - .../InpaintingMaskClear.tsx | 70 - .../InpaintingMaskVisibilityControl.tsx | 61 - .../InpaintingRedoControl.tsx | 66 - .../InpaintingShowHideBoundingBoxControl.tsx | 29 - .../InpaintingUndoControl.tsx | 66 - .../tabs/Inpainting/InpaintingDisplay.tsx | 47 +- .../tabs/Inpainting/InpaintingPanel.tsx | 41 +- ...npainting.scss => InpaintingWorkarea.scss} | 4 +- .../tabs/Inpainting/InpaintingWorkarea.tsx | 22 + .../tabs/Inpainting/KeyboardEventManager.tsx | 143 -- .../tabs/Inpainting/components/Cacher.tsx | 97 -- .../InpaintingCanvasBrushPreview.tsx | 75 - .../InpaintingCanvasBrushPreviewOutline.tsx | 80 - .../components/InpaintingCanvasLines.tsx | 37 - .../Inpainting/hooks/_useInpaintingHotkeys.ts | 146 -- .../src/features/tabs/Inpainting/index.tsx | 14 - .../tabs/Inpainting/inpaintingSlice.ts | 383 ----- .../Inpainting/inpaintingSliceSelectors.ts | 129 -- .../tabs/Inpainting/util/generateMask.ts | 109 -- .../src/features/tabs/InvokeOptionsPanel.scss | 2 +- .../src/features/tabs/InvokeOptionsPanel.tsx | 20 +- frontend/src/features/tabs/InvokeTabs.scss | 2 +- frontend/src/features/tabs/InvokeTabs.tsx | 79 +- .../src/features/tabs/InvokeWorkarea.scss | 14 +- frontend/src/features/tabs/InvokeWorkarea.tsx | 36 +- .../tabs/Outpainting/OutpaintingDisplay.tsx | 74 + .../tabs/Outpainting/OutpaintingPanel.tsx | 65 + .../tabs/Outpainting/OutpaintingWorkarea.scss | 98 ++ .../tabs/Outpainting/OutpaintingWorkarea.tsx | 22 + .../tabs/TextToImage/TextToImageDisplay.tsx | 2 +- .../tabs/TextToImage/TextToImagePanel.tsx | 36 +- .../src/features/tabs/TextToImage/index.tsx | 2 +- frontend/src/global.d.ts | 39 + frontend/src/main.tsx | 19 +- frontend/src/styles/Mixins/Buttons.scss | 22 +- .../src/styles/{ => Themes}/_Colors_Dark.scss | 73 +- frontend/src/styles/Themes/_Colors_Green.scss | 132 ++ .../styles/{ => Themes}/_Colors_Light.scss | 53 +- frontend/src/styles/_Misc.scss | 29 +- frontend/src/styles/index.scss | 19 +- frontend/tsconfig.json | 1 + frontend/tsconfig.node.json | 3 +- frontend/vite.config.ts | 8 +- frontend/yarn.lock | 1381 +++++++++-------- ldm/generate.py | 8 +- ldm/invoke/args.py | 5 + ldm/invoke/generator/base.py | 52 +- ldm/invoke/generator/inpaint.py | 82 +- ldm/invoke/generator/omnibus.py | 22 +- ldm/util.py | 18 + 233 files changed, 7487 insertions(+), 4316 deletions(-) create mode 100644 backend/modules/get_outpainting_generation_mode.py create mode 100644 backend/modules/test_images/init-img_full_transparency.png create mode 100644 backend/modules/test_images/init-img_opaque.png create mode 100644 backend/modules/test_images/init-img_partial_transparency.png create mode 100644 backend/modules/test_images/init-mask_has_mask.png create mode 100644 backend/modules/test_images/init-mask_no_mask.png create mode 100644 frontend/eslintconfig.json create mode 100644 frontend/src/common/util/openBase64ImageInTab.ts create mode 100644 frontend/src/features/canvas/IAICanvas.tsx rename frontend/src/features/{tabs/Inpainting/components/InpaintingBoundingBoxPreview.tsx => canvas/IAICanvasBoundingBoxPreview.tsx} (62%) create mode 100644 frontend/src/features/canvas/IAICanvasBrushButtonPopover.tsx create mode 100644 frontend/src/features/canvas/IAICanvasBrushPreview.tsx create mode 100644 frontend/src/features/canvas/IAICanvasControls.tsx rename frontend/src/features/{tabs/Inpainting/InpaintingControls/InpaintingBrushControl.tsx => canvas/IAICanvasControls/IAICanvasBrushControl.tsx} (60%) rename frontend/src/features/{tabs/Inpainting/InpaintingControls/InpaintingClearImageControl.tsx => canvas/IAICanvasControls/IAICanvasClearImageControl.tsx} (55%) create mode 100644 frontend/src/features/canvas/IAICanvasControls/IAICanvasEraserControl.tsx create mode 100644 frontend/src/features/canvas/IAICanvasControls/IAICanvasImageEraserControl.tsx create mode 100644 frontend/src/features/canvas/IAICanvasControls/IAICanvasLockBoundingBoxControl.tsx create mode 100644 frontend/src/features/canvas/IAICanvasControls/IAICanvasMaskControl.tsx create mode 100644 frontend/src/features/canvas/IAICanvasControls/IAICanvasMaskControls/IAICanvasBrushColorPicker.tsx create mode 100644 frontend/src/features/canvas/IAICanvasControls/IAICanvasMaskControls/IAICanvasMaskClear.tsx rename frontend/src/features/{tabs/Inpainting/InpaintingControls/InpaintingMaskControls/InpaintingMaskColorPicker.tsx => canvas/IAICanvasControls/IAICanvasMaskControls/IAICanvasMaskColorPicker.tsx} (51%) rename frontend/src/features/{tabs/Inpainting/InpaintingControls/InpaintingMaskControls/InpaintingMaskInvertControl.tsx => canvas/IAICanvasControls/IAICanvasMaskControls/IAICanvasMaskInvertControl.tsx} (50%) create mode 100644 frontend/src/features/canvas/IAICanvasControls/IAICanvasMaskControls/IAICanvasMaskVisibilityControl.tsx create mode 100644 frontend/src/features/canvas/IAICanvasControls/IAICanvasRedoButton.tsx create mode 100644 frontend/src/features/canvas/IAICanvasControls/IAICanvasShowHideBoundingBoxControl.tsx rename frontend/src/features/{tabs/Inpainting/InpaintingControls/InpaintingSplitLayoutControl.tsx => canvas/IAICanvasControls/IAICanvasSplitLayoutControl.tsx} (64%) create mode 100644 frontend/src/features/canvas/IAICanvasControls/IAICanvasUndoButton.tsx create mode 100644 frontend/src/features/canvas/IAICanvasEraserButtonPopover.tsx create mode 100644 frontend/src/features/canvas/IAICanvasEraserLines.tsx create mode 100644 frontend/src/features/canvas/IAICanvasGrid.tsx create mode 100644 frontend/src/features/canvas/IAICanvasImage.tsx create mode 100644 frontend/src/features/canvas/IAICanvasIntermediateImage.tsx create mode 100644 frontend/src/features/canvas/IAICanvasMaskButtonPopover.tsx create mode 100644 frontend/src/features/canvas/IAICanvasMaskCompositer.tsx create mode 100644 frontend/src/features/canvas/IAICanvasMaskLines.tsx create mode 100644 frontend/src/features/canvas/IAICanvasOutpaintingControls.tsx create mode 100644 frontend/src/features/canvas/IAICanvasOutpaintingObjects.tsx create mode 100644 frontend/src/features/canvas/IAICanvasResizer.tsx create mode 100644 frontend/src/features/canvas/IAICanvasSettingsButtonPopover.tsx create mode 100644 frontend/src/features/canvas/IAICanvasStatusText.tsx create mode 100644 frontend/src/features/canvas/canvasSlice.ts create mode 100644 frontend/src/features/canvas/hooks/useCanvasDragMove.ts create mode 100644 frontend/src/features/canvas/hooks/useCanvasHotkeys.ts create mode 100644 frontend/src/features/canvas/hooks/useCanvasMouseDown.ts create mode 100644 frontend/src/features/canvas/hooks/useCanvasMouseEnter.ts create mode 100644 frontend/src/features/canvas/hooks/useCanvasMouseMove.ts create mode 100644 frontend/src/features/canvas/hooks/useCanvasMouseOut.ts create mode 100644 frontend/src/features/canvas/hooks/useCanvasMouseUp.ts create mode 100644 frontend/src/features/canvas/hooks/useCanvasZoom.ts create mode 100644 frontend/src/features/canvas/hooks/useUnscaleCanvasValue.ts rename frontend/src/features/{tabs/Inpainting => canvas}/util/colorToString.ts (100%) rename frontend/src/features/{tabs/Inpainting => canvas}/util/constants.ts (68%) create mode 100644 frontend/src/features/canvas/util/generateMask.ts rename frontend/src/features/{tabs/Inpainting => canvas}/util/getScaledCursorPosition.ts (100%) create mode 100644 frontend/src/features/lightbox/Lightbox.scss create mode 100644 frontend/src/features/lightbox/Lightbox.tsx create mode 100644 frontend/src/features/lightbox/ReactPanZoom.tsx create mode 100644 frontend/src/features/system/Modal.scss create mode 100644 frontend/src/features/system/ThemeChanger.tsx delete mode 100644 frontend/src/features/tabs/Inpainting/InpaintingCanvas.tsx delete mode 100644 frontend/src/features/tabs/Inpainting/InpaintingCanvasPlaceholder.tsx delete mode 100644 frontend/src/features/tabs/Inpainting/InpaintingCanvasStatusIcons.scss delete mode 100644 frontend/src/features/tabs/Inpainting/InpaintingCanvasStatusIcons.tsx delete mode 100644 frontend/src/features/tabs/Inpainting/InpaintingControls.tsx delete mode 100644 frontend/src/features/tabs/Inpainting/InpaintingControls/InpaintingEraserControl.tsx delete mode 100644 frontend/src/features/tabs/Inpainting/InpaintingControls/InpaintingLockBoundingBoxControl.tsx delete mode 100644 frontend/src/features/tabs/Inpainting/InpaintingControls/InpaintingMaskControl.tsx delete mode 100644 frontend/src/features/tabs/Inpainting/InpaintingControls/InpaintingMaskControls/InpaintingMaskClear.tsx delete mode 100644 frontend/src/features/tabs/Inpainting/InpaintingControls/InpaintingMaskControls/InpaintingMaskVisibilityControl.tsx delete mode 100644 frontend/src/features/tabs/Inpainting/InpaintingControls/InpaintingRedoControl.tsx delete mode 100644 frontend/src/features/tabs/Inpainting/InpaintingControls/InpaintingShowHideBoundingBoxControl.tsx delete mode 100644 frontend/src/features/tabs/Inpainting/InpaintingControls/InpaintingUndoControl.tsx rename frontend/src/features/tabs/Inpainting/{Inpainting.scss => InpaintingWorkarea.scss} (94%) create mode 100644 frontend/src/features/tabs/Inpainting/InpaintingWorkarea.tsx delete mode 100644 frontend/src/features/tabs/Inpainting/KeyboardEventManager.tsx delete mode 100644 frontend/src/features/tabs/Inpainting/components/Cacher.tsx delete mode 100644 frontend/src/features/tabs/Inpainting/components/InpaintingCanvasBrushPreview.tsx delete mode 100644 frontend/src/features/tabs/Inpainting/components/InpaintingCanvasBrushPreviewOutline.tsx delete mode 100644 frontend/src/features/tabs/Inpainting/components/InpaintingCanvasLines.tsx delete mode 100644 frontend/src/features/tabs/Inpainting/hooks/_useInpaintingHotkeys.ts delete mode 100644 frontend/src/features/tabs/Inpainting/index.tsx delete mode 100644 frontend/src/features/tabs/Inpainting/inpaintingSlice.ts delete mode 100644 frontend/src/features/tabs/Inpainting/inpaintingSliceSelectors.ts delete mode 100644 frontend/src/features/tabs/Inpainting/util/generateMask.ts create mode 100644 frontend/src/features/tabs/Outpainting/OutpaintingDisplay.tsx create mode 100644 frontend/src/features/tabs/Outpainting/OutpaintingPanel.tsx create mode 100644 frontend/src/features/tabs/Outpainting/OutpaintingWorkarea.scss create mode 100644 frontend/src/features/tabs/Outpainting/OutpaintingWorkarea.tsx create mode 100644 frontend/src/global.d.ts rename frontend/src/styles/{ => Themes}/_Colors_Dark.scss (77%) create mode 100644 frontend/src/styles/Themes/_Colors_Green.scss rename frontend/src/styles/{ => Themes}/_Colors_Light.scss (89%) diff --git a/backend/invoke_ai_web_server.py b/backend/invoke_ai_web_server.py index c123f4435c..93f19bb8fa 100644 --- a/backend/invoke_ai_web_server.py +++ b/backend/invoke_ai_web_server.py @@ -7,10 +7,13 @@ import traceback import math import io import base64 +import os -from flask import Flask, redirect, send_from_directory +from werkzeug.utils import secure_filename +from flask import Flask, redirect, send_from_directory, flash, request, url_for, jsonify from flask_socketio import SocketIO from PIL import Image +from PIL.Image import Image as ImageType from uuid import uuid4 from threading import Event @@ -19,6 +22,9 @@ from ldm.invoke.pngwriter import PngWriter, retrieve_metadata from ldm.invoke.prompt_parser import split_weighted_subprompts from backend.modules.parameters import parameters_to_command +from backend.modules.get_outpainting_generation_mode import ( + get_outpainting_generation_mode, +) # Loading Arguments opt = Args() @@ -91,6 +97,43 @@ class InvokeAIWebServer: else: return send_from_directory(self.app.static_folder, "index.html") + @self.app.route("/upload", methods=["POST"]) + def upload_base64_file(): + try: + data = request.get_json() + dataURL = data["dataURL"] + name = data["name"] + + print(f'>> Image upload requested "{name}"') + + if dataURL is not None: + bytes = dataURL_to_bytes(dataURL) + + file_path = self.save_file_unique_uuid_name( + bytes=bytes, name=name, path=self.result_path + ) + + mtime = os.path.getmtime(file_path) + (width, height) = Image.open(file_path).size + + response = { + "url": self.get_url_from_image_path(file_path), + "mtime": mtime, + "width": width, + "height": height, + "category": "result", + "destination": "outpainting_merge", + } + return response + else: + return "No dataURL provided" + except Exception as e: + self.socketio.emit("error", {"message": (str(e))}) + print("\n") + + traceback.print_exc() + print("\n") + self.load_socketio_listeners(self.socketio) if args.gui: @@ -308,19 +351,24 @@ class InvokeAIWebServer: generation_parameters, esrgan_parameters, facetool_parameters ): try: - # truncate long init_mask base64 if needed + # truncate long init_mask/init_img base64 if needed + printable_parameters = { + **generation_parameters, + } + + if "init_img" in generation_parameters: + printable_parameters["init_img"] = ( + printable_parameters["init_img"][:64] + "..." + ) + if "init_mask" in generation_parameters: - printable_parameters = { - **generation_parameters, - "init_mask": generation_parameters["init_mask"][:20] + "...", - } - print( - f">> Image generation requested: {printable_parameters}\nESRGAN parameters: {esrgan_parameters}\nFacetool parameters: {facetool_parameters}" - ) - else: - print( - f">> Image generation requested: {generation_parameters}\nESRGAN parameters: {esrgan_parameters}\nFacetool parameters: {facetool_parameters}" + printable_parameters["init_mask"] = ( + printable_parameters["init_mask"][:64] + "..." ) + + print( + f">> Image generation requested: {printable_parameters}\nESRGAN parameters: {esrgan_parameters}\nFacetool parameters: {facetool_parameters}" + ) self.generate_images( generation_parameters, esrgan_parameters, @@ -456,7 +504,7 @@ class InvokeAIWebServer: from send2trash import send2trash path = self.get_image_path_from_url(url) - print(path) + send2trash(path) socketio.emit( "imageDeleted", @@ -479,7 +527,7 @@ class InvokeAIWebServer: ) mtime = os.path.getmtime(file_path) (width, height) = Image.open(file_path).size - print(file_path) + socketio.emit( "imageUploaded", { @@ -499,17 +547,18 @@ class InvokeAIWebServer: print("\n") # TODO: I think this needs a safety mechanism. - @socketio.on("uploadMaskImage") - def handle_upload_mask_image(bytes, name): + @socketio.on("uploadOutpaintingMergeImage") + def handle_upload_outpainting_merge_image(dataURL, name): try: - print(f'>> Mask image upload requested "{name}"') + print(f'>> Outpainting merge image upload requested "{name}"') - file_path = self.save_file_unique_uuid_name( - bytes=bytes, name=name, path=self.mask_image_path - ) + image = dataURL_to_image(dataURL) + file_name = self.make_unique_init_image_filename(name) + file_path = os.path.join(self.result_path, file_name) + image.save(file_path) socketio.emit( - "maskImageUploaded", + "outpaintingMergeImageUploaded", { "url": self.get_url_from_image_path(file_path), }, @@ -546,59 +595,146 @@ class InvokeAIWebServer: else [] ) + actual_generation_mode = generation_parameters["generation_mode"] + original_bounding_box = None """ TODO: If a result image is used as an init image, and then deleted, we will want to be able to use it as an init image in the future. Need to handle this case. """ - # We need to give absolute paths to the generator, stash the URLs for later - init_img_url = None - mask_img_url = None + """ + Prepare for generation based on generation_mode + """ + if generation_parameters["generation_mode"] == "outpainting": + """ + generation_parameters["init_img"] is a base64 image + generation_parameters["init_mask"] is a base64 image - if "init_img" in generation_parameters: + So we need to convert each into a PIL Image. + """ + + truncated_outpaint_image_b64 = generation_parameters["init_img"][:64] + truncated_outpaint_mask_b64 = generation_parameters["init_mask"][:64] + + outpaint_image = dataURL_to_image( + generation_parameters["init_img"] + ).convert("RGBA") + + # Convert mask dataURL to an image and convert to greyscale + outpaint_mask = dataURL_to_image( + generation_parameters["init_mask"] + ).convert("L") + + actual_generation_mode = get_outpainting_generation_mode( + outpaint_image, outpaint_mask + ) + + """ + The outpaint image and mask are pre-cropped by the UI, so the bounding box we pass + to the generator should be: + { + "x": 0, + "y": 0, + "width": original_bounding_box["width"], + "height": original_bounding_box["height"] + } + + Save the original bounding box, we need to give it back to the UI when finished, + because the UI needs to know where to put the inpainted image on the canvas. + """ + original_bounding_box = generation_parameters["bounding_box"].copy() + + generation_parameters["bounding_box"]["x"] = 0 + generation_parameters["bounding_box"]["y"] = 0 + + """ + Apply the mask to the init image, creating a "mask" image with + transparency where inpainting should occur. This is the kind of + mask that prompt2image() needs. + """ + alpha_mask = outpaint_image.copy() + alpha_mask.putalpha(outpaint_mask) + + generation_parameters["init_img"] = outpaint_image + generation_parameters["init_mask"] = alpha_mask + + # Remove the unneeded parameters for whichever mode we are doing + if actual_generation_mode == "inpainting": + generation_parameters.pop("seam_size", None) + generation_parameters.pop("seam_blur", None) + generation_parameters.pop("seam_strength", None) + generation_parameters.pop("seam_steps", None) + generation_parameters.pop("tile_size", None) + generation_parameters.pop("force_outpaint", None) + elif actual_generation_mode == "img2img": + generation_parameters["height"] = original_bounding_box["height"] + generation_parameters["width"] = original_bounding_box["width"] + generation_parameters.pop("init_mask", None) + generation_parameters.pop("seam_size", None) + generation_parameters.pop("seam_blur", None) + generation_parameters.pop("seam_strength", None) + generation_parameters.pop("seam_steps", None) + generation_parameters.pop("tile_size", None) + generation_parameters.pop("force_outpaint", None) + elif actual_generation_mode == "txt2img": + generation_parameters["height"] = original_bounding_box["height"] + generation_parameters["width"] = original_bounding_box["width"] + generation_parameters.pop("strength", None) + generation_parameters.pop("fit", None) + generation_parameters.pop("init_img", None) + generation_parameters.pop("init_mask", None) + generation_parameters.pop("seam_size", None) + generation_parameters.pop("seam_blur", None) + generation_parameters.pop("seam_strength", None) + generation_parameters.pop("seam_steps", None) + generation_parameters.pop("tile_size", None) + generation_parameters.pop("force_outpaint", None) + + elif generation_parameters["generation_mode"] == "inpainting": + """ + generation_parameters["init_img"] is a url + generation_parameters["init_mask"] is a base64 image + + So we need to convert each into a PIL Image. + """ init_img_url = generation_parameters["init_img"] + truncated_outpaint_mask_b64 = generation_parameters["init_mask"][:64] + + init_img_url = generation_parameters["init_img"] + init_img_path = self.get_image_path_from_url(init_img_url) - generation_parameters["init_img"] = init_img_path - # if 'init_mask' in generation_parameters: - # mask_img_url = generation_parameters['init_mask'] - # generation_parameters[ - # 'init_mask' - # ] = self.get_image_path_from_url( - # generation_parameters['init_mask'] - # ) - - if "init_mask" in generation_parameters: - # grab an Image of the init image original_image = Image.open(init_img_path) + rgba_image = original_image.convert("RGBA") + # copy a region from it which we will inpaint cropped_init_image = copy_image_from_bounding_box( - original_image, **generation_parameters["bounding_box"] + rgba_image, **generation_parameters["bounding_box"] ) + generation_parameters["init_img"] = cropped_init_image - if generation_parameters["is_mask_empty"]: - generation_parameters["init_mask"] = None - else: - # grab an Image of the mask - mask_image = Image.open( - io.BytesIO( - base64.decodebytes( - bytes(generation_parameters["init_mask"], "utf-8") - ) - ) - ) - generation_parameters["init_mask"] = mask_image + # Convert mask dataURL to an image and convert to greyscale + mask_image = dataURL_to_image( + generation_parameters["init_mask"] + ).convert("L") - totalSteps = self.calculate_real_steps( - steps=generation_parameters["steps"], - strength=generation_parameters["strength"] - if "strength" in generation_parameters - else None, - has_init_image="init_img" in generation_parameters, - ) + """ + Apply the mask to the init image, creating a "mask" image with + transparency where inpainting should occur. This is the kind of + mask that prompt2image() needs. + """ + alpha_mask = cropped_init_image.copy() + alpha_mask.putalpha(mask_image) + + generation_parameters["init_mask"] = alpha_mask + + elif generation_parameters["generation_mode"] == "img2img": + init_img_url = generation_parameters["init_img"] + init_img_path = self.get_image_path_from_url(init_img_url) + generation_parameters["init_img"] = init_img_path progress = Progress(generation_parameters=generation_parameters) @@ -613,13 +749,22 @@ class InvokeAIWebServer: nonlocal generation_parameters nonlocal progress + generation_messages = { + "txt2img": "Text to Image", + "img2img": "Image to Image", + "inpainting": "Inpainting", + "outpainting": "Outpainting", + } + progress.set_current_step(step + 1) - progress.set_current_status("Generating") + progress.set_current_status( + f"Generating ({generation_messages[actual_generation_mode]})" + ) progress.set_current_status_has_steps(True) if ( generation_parameters["progress_images"] - and step % generation_parameters['save_intermediates'] == 0 + and step % generation_parameters["save_intermediates"] == 0 and step < generation_parameters["steps"] - 1 ): image = self.generate.sample_to_image(sample) @@ -648,6 +793,8 @@ class InvokeAIWebServer: "metadata": metadata, "width": width, "height": height, + "generationMode": generation_parameters["generation_mode"], + "boundingBox": original_bounding_box, }, ) @@ -670,6 +817,8 @@ class InvokeAIWebServer: "metadata": {}, "width": width, "height": height, + "generationMode": generation_parameters["generation_mode"], + "boundingBox": original_bounding_box, }, ) @@ -688,8 +837,11 @@ class InvokeAIWebServer: step_index = 1 nonlocal prior_variations + """ + Tidy up after generation based on generation_mode + """ # paste the inpainting image back onto the original - if "init_mask" in generation_parameters: + if generation_parameters["generation_mode"] == "inpainting": image = paste_image_into_bounding_box( Image.open(init_img_path), image, @@ -786,11 +938,14 @@ class InvokeAIWebServer: # restore the stashed URLS and discard the paths, we are about to send the result to client if "init_img" in all_parameters: - all_parameters["init_img"] = init_img_url + all_parameters["init_img"] = "" if "init_mask" in all_parameters: all_parameters["init_mask"] = "" # TODO: store the mask in metadata + if generation_parameters["generation_mode"] == "outpainting": + all_parameters["bounding_box"] = original_bounding_box + metadata = self.parameters_to_generated_image_metadata(all_parameters) command = parameters_to_command(all_parameters) @@ -826,6 +981,8 @@ class InvokeAIWebServer: "metadata": metadata, "width": width, "height": height, + "boundingBox": original_bounding_box, + "generationMode": generation_parameters["generation_mode"], }, ) eventlet.sleep(0) @@ -933,25 +1090,25 @@ class InvokeAIWebServer: rfc_dict["variations"] = variations - if "init_img" in parameters: - rfc_dict["type"] = "img2img" - rfc_dict["strength"] = parameters["strength"] - rfc_dict["fit"] = parameters["fit"] # TODO: Noncompliant - rfc_dict["orig_hash"] = calculate_init_img_hash( - self.get_image_path_from_url(parameters["init_img"]) - ) - rfc_dict["init_image_path"] = parameters[ - "init_img" - ] # TODO: Noncompliant - # if 'init_mask' in parameters: - # rfc_dict['mask_hash'] = calculate_init_img_hash( - # self.get_image_path_from_url(parameters['init_mask']) - # ) # TODO: Noncompliant - # rfc_dict['mask_image_path'] = parameters[ - # 'init_mask' - # ] # TODO: Noncompliant - else: - rfc_dict["type"] = "txt2img" + # if "init_img" in parameters: + # rfc_dict["type"] = "img2img" + # rfc_dict["strength"] = parameters["strength"] + # rfc_dict["fit"] = parameters["fit"] # TODO: Noncompliant + # rfc_dict["orig_hash"] = calculate_init_img_hash( + # self.get_image_path_from_url(parameters["init_img"]) + # ) + # rfc_dict["init_image_path"] = parameters[ + # "init_img" + # ] # TODO: Noncompliant + # # if 'init_mask' in parameters: + # # rfc_dict['mask_hash'] = calculate_init_img_hash( + # # self.get_image_path_from_url(parameters['init_mask']) + # # ) # TODO: Noncompliant + # # rfc_dict['mask_image_path'] = parameters[ + # # 'init_mask' + # # ] # TODO: Noncompliant + # else: + # rfc_dict["type"] = "txt2img" metadata["image"] = rfc_dict @@ -1244,23 +1401,67 @@ class CanceledException(Exception): """ -Crops an image to a bounding box. +Returns a copy an image, cropped to a bounding box. """ -def copy_image_from_bounding_box(image, x, y, width, height): +def copy_image_from_bounding_box( + image: ImageType, x: int, y: int, width: int, height: int +) -> ImageType: with image as im: bounds = (x, y, x + width, y + height) im_cropped = im.crop(bounds) return im_cropped +""" +Converts a base64 image dataURL into an image. +The dataURL is split on the first commma. +""" + + +def dataURL_to_image(dataURL: str) -> ImageType: + image = Image.open( + io.BytesIO( + base64.decodebytes( + bytes( + dataURL.split(",", 1)[1], + "utf-8", + ) + ) + ) + ) + return image + + +""" +Converts a base64 image dataURL into bytes. +The dataURL is split on the first commma. +""" + + +def dataURL_to_bytes(dataURL: str) -> bytes: + return base64.decodebytes( + bytes( + dataURL.split(",", 1)[1], + "utf-8", + ) + ) + + """ Pastes an image onto another with a bounding box. """ -def paste_image_into_bounding_box(recipient_image, donor_image, x, y, width, height): +def paste_image_into_bounding_box( + recipient_image: ImageType, + donor_image: ImageType, + x: int, + y: int, + width: int, + height: int, +) -> ImageType: with recipient_image as im: bounds = (x, y, x + width, y + height) im.paste(donor_image, bounds) diff --git a/backend/modules/get_outpainting_generation_mode.py b/backend/modules/get_outpainting_generation_mode.py new file mode 100644 index 0000000000..d21e231671 --- /dev/null +++ b/backend/modules/get_outpainting_generation_mode.py @@ -0,0 +1,117 @@ +from PIL import Image, ImageChops +from PIL.Image import Image as ImageType +from typing import Union, Literal + +# https://stackoverflow.com/questions/43864101/python-pil-check-if-image-is-transparent +def check_for_any_transparency(img: Union[ImageType, str]) -> bool: + if type(img) is str: + img = Image.open(str) + + if img.info.get("transparency", None) is not None: + return True + if img.mode == "P": + transparent = img.info.get("transparency", -1) + for _, index in img.getcolors(): + if index == transparent: + return True + elif img.mode == "RGBA": + extrema = img.getextrema() + if extrema[3][0] < 255: + return True + return False + + +def get_outpainting_generation_mode( + init_img: Union[ImageType, str], init_mask: Union[ImageType, str] +) -> Literal["txt2img", "outpainting", "inpainting", "img2img",]: + if type(init_img) is str: + init_img = Image.open(init_img) + + if type(init_mask) is str: + init_mask = Image.open(init_mask) + + init_img = init_img.convert("RGBA") + + # Get alpha from init_img + init_img_alpha = init_img.split()[-1] + init_img_alpha_mask = init_img_alpha.convert("L") + init_img_has_transparency = check_for_any_transparency(init_img) + + if init_img_has_transparency: + init_img_is_fully_transparent = ( + True if init_img_alpha_mask.getbbox() is None else False + ) + + """ + Mask images are white in areas where no change should be made, black where changes + should be made. + """ + + # Fit the mask to init_img's size and convert it to greyscale + init_mask = init_mask.resize(init_img.size).convert("L") + + """ + PIL.Image.getbbox() returns the bounding box of non-zero areas of the image, so we first + invert the mask image so that masked areas are white and other areas black == zero. + getbbox() now tells us if the are any masked areas. + """ + init_mask_bbox = ImageChops.invert(init_mask).getbbox() + init_mask_exists = False if init_mask_bbox is None else True + + if init_img_has_transparency: + if init_img_is_fully_transparent: + return "txt2img" + else: + return "outpainting" + else: + if init_mask_exists: + return "inpainting" + else: + return "img2img" + + +def main(): + # Testing + init_img_opaque = "test_images/init-img_opaque.png" + init_img_partial_transparency = "test_images/init-img_partial_transparency.png" + init_img_full_transparency = "test_images/init-img_full_transparency.png" + init_mask_no_mask = "test_images/init-mask_no_mask.png" + init_mask_has_mask = "test_images/init-mask_has_mask.png" + + print( + "OPAQUE IMAGE, NO MASK, expect img2img, got ", + get_outpainting_generation_mode(init_img_opaque, init_mask_no_mask), + ) + + print( + "IMAGE WITH TRANSPARENCY, NO MASK, expect outpainting, got ", + get_outpainting_generation_mode( + init_img_partial_transparency, init_mask_no_mask + ), + ) + + print( + "FULLY TRANSPARENT IMAGE NO MASK, expect txt2img, got ", + get_outpainting_generation_mode(init_img_full_transparency, init_mask_no_mask), + ) + + print( + "OPAQUE IMAGE, WITH MASK, expect inpainting, got ", + get_outpainting_generation_mode(init_img_opaque, init_mask_has_mask), + ) + + print( + "IMAGE WITH TRANSPARENCY, WITH MASK, expect outpainting, got ", + get_outpainting_generation_mode( + init_img_partial_transparency, init_mask_has_mask + ), + ) + + print( + "FULLY TRANSPARENT IMAGE WITH MASK, expect txt2img, got ", + get_outpainting_generation_mode(init_img_full_transparency, init_mask_has_mask), + ) + + +if __name__ == "__main__": + main() diff --git a/backend/modules/test_images/init-img_full_transparency.png b/backend/modules/test_images/init-img_full_transparency.png new file mode 100644 index 0000000000000000000000000000000000000000..6cdeada60955bcd356482c98718e03b05a28741a GIT binary patch literal 2731 zcmeHIZBHCk6dpicN(&mR6}OR02AedIo!QwHaEF~Du$0}DrM$C{P#Jb-cZc1b8E1wv zOZq{fS}BQw#+2d~5UFi_K`>B>s0d$>TJ=k7T0+3Y29?@aktVg;=$%>0i-7(BnPf8e z-sd^zp7We@?=%OH5iN3cf`iUEOtVsw zs)V8oQNYNw&u(V?G%EsiNhAf={{yYq49(_zoKOtfiY5_UHBz)AtbWQ(morYuv*K+9 z$fH^JIz)-iSErP>lx09Zp%7Ff`wB)PX?kqcMim=E%e5fX_-vdLglAC0TY;?E*#!dU zVtfD-i*mDIYfg45ZcI(p>e0{+pl}4RWn2L>B>|RR2l^AowYszt+&~zNgdyz-94B-- z)w9Y5=fO!y)PM1nu7*v(!e%2Zj3{wJKwS#8dNKWMXcn6K7`4Y?SgkZcITVpdgcmqx zor89&n*(>D{5d^wq?znIb*k-( zcIJirn2bZgJpB1rsHlY31NM&%mag~CzB>ENg)Uc)@bJmfSWoh6kLSdHbT)7<@kILr zB${L!`}wcg&*q!o924qB9+~gl@%{VJn)BVmOhVVO7Yj{|9l66_lr5CUS6{1I{Ob7J zRP+Q9tSTG45+CHAo@mls?%8v0|8$4t^XuE5%DYCF{Nw5mw-d*`3#H}#BhjA< zGXuBdSd06oOI1x?@XOf7TPj2d+P+hH!=R2}0{F$;Z#8F@$iW+9co?9Jci%ebkLJ3; jaO>GpU`v7jnF8OXh2Mn2uDXAHNlDzAlW*?Js&4!n5bH>- literal 0 HcmV?d00001 diff --git a/backend/modules/test_images/init-img_opaque.png b/backend/modules/test_images/init-img_opaque.png new file mode 100644 index 0000000000000000000000000000000000000000..a45aec75ed4b2b500385b0c40e5c2bbc720352e2 GIT binary patch literal 299473 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

-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 z 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¸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%0Dw&Wm=Q`SawpHl)?d#b$`6ov= zSAGHLo>v4=T>LPXAHCOx=39wudkR^n*lCSPtsZ;+#%c_4F@z&Bkp%!1-IY z%ZOlw8E(H@(a6Z*@KnVJ5=?rIya30Dlp`=kcJg%>k-;RLMnyyy1u;4uHe@d-v4Pt~ z;4DP9Cx}xL4Imf8-ACZM6W5^^(HYKteFn`KS17C?(;`LW>{MX1BW#oFV0R|~E=m(^ zB9z!cR9$M_%)I-PfdDk+;0RXh(z^AsODD>a3@15<3+>Kp>SxKn8 zUP)LV2#>uECs_`b8#Ul`2JFI4Fm6CI05$FC&7n`~&e%;W$Z3m zkw`J}vXg9gEssxTe6m09#)h;2wC8L`xDtWO5PA0j1*9O!8f_44Cj}KJ+fN~C(o=)x zL1KY>>k0HR##G^J4$A21^|lE}(HOicC#U%d2povPO9mLfNT>ILbliH^_AyGe3OlIu z!8;h5v{7Qu%EposumrPn&$M%ohWJIdy*4UYDQvZW;;>ZagHlswPwRO^b+c82?*|`` z#ZT#zt&lTCeZ(`TAN_d^j9|p7ZX9f7p^!nd(9>Ee)M44qX&ehF^MyT6OQ9gk-eX5IGX!v#5$k^9-Fg> zzu}%MWE=>XRIFpcB@IUFz6?R%nWs4P!?k`6(&D^N+dG+M*pXeXC@wfq&;*;~8CO;? z=E98k_>Jj7gP9Z?W5}5(*?GGJ9|R zz*G7FB|U@`I0(;zX{ibzV)6Y2wpXvb4DW&m3@w&yv7K$|W4}eh&UkHk>_rN*rO2^? zi0j%OHF)B0xiaKA^Br{0kKx7{j4|K-j?eMWBL18nAI$NYnf8wU4t(5=J_{oCeSt&I z$>>s0{6Ym zhzNS@spsFKB94@|vC8ma(b$Ef9l^!kDnQO2!X>8Dg{jj`E*QN5%&!VC`baEfyA{zA zpV!OaLP6V#!I_&+;WsO3r^7$(&yAJiN=))FgCkI@d`fA(ONw&B+Me#X{hdV*5iUW4 zpvW?6hGx%u3h@kT`_P`0O`w%$K3w-Cgpm z--82GZo&wNiXQZKd+h9j#1=#|i--^SwHN=%Sm6*up9~z3yFNl>WT|BpS*!W@_>ReH;dWmJCWyY$o<>e)GkDG0hwpJ-OC~-*;`bp0e0UOis;?Eof;5p0+I{i z5N-s)IM;y<_fLy-yrl)wqae?z9wwF7_Lb}2z1~s#KvRZAqdt2l_MUH2-e8TF=bcMl zr&vmx{&sULRiT#k<*YhG z-S$8|bwB$4HLzd}ckJoLE5LK>q|I~Y%|LUHeZp1ZV6ry1wF4L$?*1*m6eJjGD4(;B%T zyU)+}(IZvynLa{E)zF#GQuOtFQh447+m~-6V}! zJN_`Y1A}L^bo;Z<1znm?uUVYhK7$f=Lq5c( z^r!f-R;W*;vrsfeLSK)!KcbGh&f|!EK8j-5zvnBW1J$ zXIi(I%^ezd&p!rwj`2-jI`f?@EA%nv%=bHId@LNCuYb(!ne)Hh$KAl0HrzAt^qj>6 z(^$weZB1DnRwoSfY97{0vDWD^NDgFvkevyy7bYX~;;OcEXAZZ8xlE4>Y%<;Tz!AbS zr5~{iJ#2fri2wG3GSNL-JIj>j!uU&A#NeS!Wf+q{Ca zn~PSXB4&GOQqryZudsJ6aD8i8Czci22F#flS1v2IHT7gwLW(k;4Tcppf@a3?m`QCV1iSxD@u*lNb95ARyAJrfE5Ah(oyLVOZZCt@w{(KWX$v3NSh*+7PNqXkO z5{S3+)`VajR^bdV__D_Sb-U``gS9@)tMfVYHRjCE_?Xtrcg`2dl0JRf=lFZv12=Ha z7wqqxvA=!5sHA2x)wQ#mGnj67daxJ|Gq!x+3rDXx0ga{o!Mz3c18`FBdsmrkGlH@ zK(yyW-*kmd=61*U^Hq-9?$|oo# z@A@_!+mK|#dM#iU))K`G<4v(F&6$Ucr(6N^^DoJEKh%TDB9KQ5n4d&a`Qy zRA}*es?a~p_8eg@J9g7B27ElcyPv`yx0KXQdv8@v!I72l|Ll{(AT+`~g3CW5Kk^dgY7j(i51Ne}N0$L#eIn@9iZAqdl{! zWcKTl+x*|u0&j^u8v;BXgKEQwO`BugGw7Z%j_twu`W!THzUMm#6Y6+%fBPI9`+KnN zKUu=r>#WzaOQWaZ)^ISKo#Ia>cpX>*?q50=SjVDOJ7XarEef=ue6L_iMXrB$9?wou z{Z%P$90w*HsByW)B!a{R6v1|C=?lOBA`X;$`ce~4u?})!^p#(|1j|B+i5jkaYTgJ% zd!YvB4K?>oG9vD97eSNocR9a7e6YoQx@{wiJvLx%FLf(PVBLk7UTGne``1`o5JWO? zBj#12+8vlCvZ0|d^JM0RLR+K#FPF3*`S7gaGEUQ6V+DsBIyxZsxwE>m*29Qk04Nmk67iRi+CC`=;8Q4&x3eJHms2< zqqXsvx;N*ND1UVUztG-NP?z9-6;!xAb3#u!?;RFD04;dxc}~x_@lBR}@D1n#G@F{ONGkwKhdd;nC_XWmY;-yHWS=|F>B03X z$$^OO6B^U)J4$3D(_YKv9wclr`=i4RWOv2aI3c65r#Bm_>{;g>S#;dlvUlYv@S%zo zk#9Zv6Pma5NDuLeBY+58+s-}V78Hfg#_I*W)8E~{Ioc}U;%>`Ekh@eNf#78r69e8t zX|h?%dzrrT?5x4f(&qo#W(J}WG?MKllQ4^EJ*Jb z&v&mqQn02?pX;VXhsYh^>;~;!2@1S7ZW9`@bu_NI!q&~aeS0v`ox=SEgx(+KRmCC9 z2JQt)y}kw3{;>U}n?ch=uOXDTcJ*JMP509(e+KU#|5v4UPa2njwrQMVRxRvJi=HBw z;~lzGsq@`e0vkcL>1-VYq#fr(fSPRrqFA;T2^!iP zU@lCdA6Bs%6b~VlX1eekmRQ1sL1G)$x}>^hnV~?gS1g=m1hE@cudjZA^muW>{lJ-f@ew!k+B{U|muo_tMm$_FQs+ zEJsZ0tQ9B5-*|HCA9qsO*uuBnarXB)XtR3TaXenDZkGX`M^X2eUgFAW&Wv!|wa%}{r{Li&0wOx_a`p4%4Y|C6PgFjCLybVY0muIYqX>af%;rXNm__d(9 zb`BRN@s9ic>VLegz_#Y8^b4p3$x}j_fZN4IFsxwf+3%5Kz|Zlyg5`|s6i|Z#$+prl zSxvqxi}tSAXl?Qa$Yog;lG!xC6oa-NvUI6!dX=2Nac46jt5rQEjh52RM5y|8iW3bHbT!T~~@>DxRvj!50 z>M4&E25|GKX|qW)o*sI1G6qcosKEhTZ~?syj?tw4ovC@i#sLpiRkk;lpk)4~kufh&)5tFbfu#WMNAj6L4aX3Sj z?I9KKf6v33$A>(99z75>e5$IM$w#wPMUyVE9+a{R7Ni7}U3x!_mBAkFJ9ky}%;gP# zQOoZ6e4co$Y>H#H-5@GqS`AidR`UEAe;@ssX)MX6!Xtite!d@8tJ42W?@q8$rk%`F z2JPdW(sR^5xYh(Wk>`lcAS-VkYcl1dT~{eU<^xop!$EhSk$b0nv#?^}nn}cFkH4Nw zNwyJ!)!PYj2H)%(3D@rWIlZ%$J^bk+tyEW3;cVza~o%al~me^C;j(gS>? z0!#d}T{k|Az8VlJ2F*_Oxk0XO#4Jjiy#>v?RfpZl*i0?MR|&8sOaQOU=A?-6IX@Ga zZ2Hi1ymGwh_V>#(^Tn$3zWE0~-|rV~ce78UIZnM#eaF{+2#vhob=##muVDKZAC43v;JezWCS7jx= z)zcMJTRgPR-~oW9;)xM~0Jh6T!ximw#+H}WPxYUf3=`1MC;;@lM8!y^{q5X zH`7EBMAP_$-GFN_7rygez1u#lqXrLQ@&nC~WTR&U@Mu1x*nyVR?3t;!xV!(%M_~6* zDh%-hKIKP~;miV`p)@Fd*abXRYa|pwW2|A!qFDgD5A-hM!do$@^gV~$h@n)SK~{#1 z{m;0CWa)~>4yl8NXjcM#IMXM?Txzp1@E0z)o!yDg%lY8#wUO{_=Lj-7UR>1DO z3OKA=_~+5A<{lSbRknCB zb9#QovZ?#$9>HCCm*Xa23Eq8L$ge8$(v1CI)bW>E@EtR+Wxtv0vc&-I@rFhBtK|fY z`A*pS_^s`)Lfp-P7njPm^c%9%66QGYzVLL+3xWl>y<&4;gNyv0W!Qy?dGp;?H*kTV zy@-J*Y<7g1`tlQr6er%jY5#0+SE%luGf9Z-z_=g2Cm zIQB6qsolk=Fg+Tu_}Q4?434F1P4X7`+(fk}XBIZx7InGOmr&WZ6Yo3)G1HFk_`RS) zP!L8MQ0PN}CE=KIcP)Vyf^2LWUG&OnwQp%I#+}C|?^Aq_(w6KO6M6c(BA{-#{qMLB zdK5c>HhVIxyMv?~C7eHub1S+rzlep)7DhjwUUN`-;D(?+ev;l1Z{#9LKjsI5DL#qy zk61;KpVA-ULlsErA&YC66pSaxw}kD{y#q#h`f2AQYPmeV(@?+i<#f1&x9q(~H11#< zm+!627-p}{8M@K559ah44&3AKV5YxDANO$1oZ~h1^c>9j66^74d@sv8nI|xfIh>4+ zdP8!e=hadN*1PP}^4+(h7YPpm`Sn0q_nT~}$pJ0rk-b-wuo?gH`_qDAUhd$YVq6T~ zZvsZTD*+bNUOIG8Hz@HMFGjc7-rMt|@`I`o|I#|%ghB*XFIAAtcEHjD)ce!*-zIdaRr~kebk(k+a zc!=tAft0iw0lBnHa>gC+tGx4Oy8by^3FzYWd3QyO{T&x2j)(0LVqb(yXlTNMN4YNr z1>)}m*cU+(zGTK`H`H%J4 zSzqc8|6iL>m7X|9Z8>FAh;=!yiZd4{6IW!~uC$JX4S?D#w)x(7jvqz?>VjqH7EUwgVs}p+{uJYG6EN*#k zPC1I5MEx05AgM6Mx^w2MI?E;vBZ6BPU=uZd&;;EX%*#f_Z7VEb5-({Q!N__&dDdyBsFzS#q=cv38Lo=O%JCix4+WE zDj*{IFlnF9$76U#I#5|nJba3eP*%y$zw{F$p00;QKVYT$7!Vm1N?t~Qlq>|vdzx@F z`*l?WdLTSrBAmpNwa^aLFwru7$p^Nm7Qw0E=scuY-Qk2e)iBwlDxE3mk2_|orw1yN zecQH3w8nlwisupsIgJ#a)9#MpK4x%cPMj*uGd{y(FRDHq;4HbMbMhD1W8-{o|quc#6CqCKT z`)Cn!On7EyS4gh}cYuk7cK$gK^gkW(D(9Rc#nqYb3BF0b(MN-dL&xq8z)$KK)o#90{}d3%eyDWO<{XVA5n z0=H(#9!4#|z{Kk{bzq)A)junc;5%t5Yn|jVJo8&nS~zrH(f#@^9Sgpjj$f+CkB<{3}A=#w^%MJ>PV&; zSuDm9r`MBVBAx5K@=UTLeC8f(EX?%V5^RLPo$~GZ*s*&s<@yU~TG{75};Pkr=&XDmVwpUh{GD*R_`s(KRIGD2|gi!ws= z`)yKL<`>?@lXw!ltjAG#@u-ab=L zDEP2FSlB8d7#CxS;aVc~Pm)AW8)LRT?XRykKLI^<4krXkTp!%yZtM`<7n5JVPcajC zfqDX!%}r45+<-;xxl`U;^h2@sxE*{hv^K0G+7bc6Vm`U^btmgg%az80E6mHivjENh z?`pah|I&TFE08Yd{v~ScteqDwO2|~|qBxSXlBB~8tYc9a<$S<9K%#d} zGVkredH8N3!L*|8;a6%+5WGAfH_F_bPJ)ZB0><4{(h%@|- z+w|y|KjHXs;fZj(HjHMZij|w$(9HGQ%_K{|Y6xh`O5}Mg5@kK0bmKlz(uXXNM2R0R zJjnY1D^Zy{<{mPVhz{%~-OA37JykE9xXtX=(h9ttC-$XzXRt9z94rc zcAmsOV!^}p$WDPP$I){EqeQd7^d+$o?~?`geBPnZ#L0Wxa0|bT&D_id zGoteyL0Gyb=>Jyw%pzC-GMkxo#5*qEEiW`%2_h;pP-;;#MyJtiqDKqBULdAZnO;&M4~OZb?_69nZM zOaXVGE&betRxK*&Asch*`D3%panaq6;3GDhjj^Z+ zqt!c0GGWbjV9?72t_pk`W6$$F(*syvyNCadrw!|X-xdGt+?I)s0~BKfqIkUxIA+w2 zHWbZ#TPA0s)}IQwCHWx%KIQ{R`eTZE3XdYUirMFo+Gms-ux?|ye|+U1NfLRIJB|@u zaO#1rKe&JQzGA;chG#vK@q$N~!M{C=>Hrz;H3F*z+i{Oi6OHrjZy@``it(It2D8q+ zp?5oN(u${Iv>IG&3E6!qZv})~kNOyf7K2k zgsO;hSn~SB8*(ZcLN_>s6nvKs-G-VkJ0iK`Z2#B23kK?&5^XtpnUEWk%HGSk{>p{8 z_z(UnD(=rrFv)gh-AAhZEPe|azmLs;BULygcg)3%anJOi+~0)lA7d{^6pHY%AD3@;JE7Mv8g_ox>?X7tcjI?f>XgfLn7 zd-s(q>E`xQSZt|*GKP2e&izj?qRo<2(9s1um$Cexm38@E44BZawuM2VJ?0R-bc=+j z`kyZ+`Yb>TJu0!z*gmB%^oP)lDvS?OcsVh7OgNV5 zygMmwYq}U^Ox9ovIPZl4C1u!;Eafdjz%i>JZxzGx2wB{i6wGp8jTx~8`Ia#>wtXE7 ze0n&;V;u9GX$q=td{@7Z-s>NzdRqZ!C~P>vA)&@(f$t3D=;k>j;_AaJZkC@vLjw<> z;)nVJiV*c7io3H|;DdNf*;FlUw)54?^=$zLz);B-CkeFq;+>?7bA!gp_C}`@9c(WF zo4bC-Zk%z?91uO z!Yk?Vp4s37Z#1Ms0|0=l5v<|`e{fMLh|jLzuwuOh)Qav%M2x>4YSTk<9>SK@TtPaR zVJ0H(p}Tu>ZGtjnNpNPk(wqG31p{xMFaQcfmVzWPtYkR8x0?mx<95SfV$G%vWTI98 z#;&Kv@eT+=lZHJpJQYcn86nk%?M(t)Y=%TRJH+mbBp0d%3O=3GMpv5H?FdctHDU%N zrqD`Orn_7`Da>ab3ue+;0_r*UV;TU)WOQ|lz>b5J-L@~g|3LXp*7!GH<}i#$xQvBy zZHZmtOoj(HpnIExJJ=**cJlQC7614Dg>%&5m_ zd@}hkZ2Q*!$STH(f3u@pWKRx>huodO426+)J~uqoWC0?pT=AdFqXa~*ryD`C$j=tO z;v`jU@wRaWJLj-vvR?82c8@LA1v@sD$6(Uaddp^h7vsMYd%#|lf8f5gyvGNaGX`ed zjh?grTBA=NGw$2xL>TH&y8e3B>}!6vsLeHRSW1iw-==T*jr#XWyn_k9fu4&9-GSb} zdf_|ni>v9pC1>ojW02(gW42L94&`8nAa|8b;6rH5T|gs&2997{3(Buf!~l`xaYcD` z;f2u4wVIm^Ojo?OB&n2P_Du#b^jzxr$szRu>FmwdH@ja(U?C~r;uMzzc%SRl_%FVs zd#va;%*D-gKWTpR{IYphHiW?D{(WJ7|7`Ev&Fw-0rakFlfyJZa#M>q{T9;}Jo_Kfx zpvR~rCkiX%&hxQK-o35+?DIC>-Y{%Ahmzd(vq@8@!-Fq?ms_)=GNWC6Fey`qHrLb2QV`Hj3Vrob091i*DX`n?I-*@C?%$)5a|4=Y4dQ~kjx!4Q96xg6QRh#q{|_uLl)jqXvF>llm>7enp=9yhoY)y~Wp3?g)_Ryq;!bnHoFq zI`(wvnV$?e+tWU#=k7snOuJ2YceMXA>!G?VuA}pbFKVDz?2_?-;@d%az3qQlip20V zD}?bklC$Uyc9SfZ3E3paOYJUL13bxTsoh@=NHa)AWkI^S;TwmMoe2xk1~tq@i<*W? zEuZ69`(d@|%ZpaSb4N3Vmy6!4LmGIVrC_ZcP)S^WBW4zekG)2uSVlRBN2#{SCH8_R zc+P0GlAIa(F2P%Lm3;H%1(;&E}Mt(0z$+RSUfsL4dWeSjs?ZS-R9dKI->;|4_ zZ&LRxM;m;aDMhY?!XdpA-+7xny`ec4qOa4L$<(*MP|=+uz<$zMyEp$$KPnxo4RG6V z_(ec3*1tJkxb?$@bm!Jha|H$OIm?J?5@GK6p6lTR5p{!{Xw37aro8SIqU7l!iO%*} zlIMJ-iayyxxpA>6KF_G92M0#h(HPJs_}jjN1`Y_a=;x;~;Av0n8sP&DWw0$n zC-f+Ow|C_N#v0eN-Y$3gbcOjwT}#eqRi3I*$(40oz*Ct9P^{m`c>d<7j$w#W_5)d4 zcixz2Vuw$FU`=mMM2K=2z|4{E&@N-}GUoKEnI=1RXHwB0qsKO;Jv|+Vyq+F;?CEUs z8r$vemG)#Q&J5g`Xxg$v;m+)(l}j4nFKz`;)@%_Y+%i3E2`)O1OYtGXmG?IAwu-n= z{%*VsTC1Ss8T*MYK4r$@KHSiss54eB*6OtPQ7cU4Ex6!xd)R(v8?|_FZc|cz_-k#OmHpWx#8b!)k;eCb1&~p?*hUlecqa0rFVzV``#hiJ=!WulHIz|Li=iN z1+fw5HzD8V<~{}EcldSb_!OLT6Y&0H?Kl8l4wfPUXaK>3+Y9dxxvT8+t#flAOUB44ZuypjRp4u z>(OMik%1r6O5g&u98bPW%vos9?~LO7OsO+>c1Q*c4punR+|EWU%iyEli@-Kv;~nCRot=z^iSCd#Jc}d&-c|Hb$7pYeV4=#8tuz5v zL_QjpQH4Slw&;VV>P|kkSs9VZ0pKR@upD_W+$tyk!ob=Q-{hnrYXS!@<=bZWoU=zK z$|Q7VawltyHxqpOfbBU=1nMzt_jgWnvh{l=}qV$8-70$0t+doNd$bN~6C{spnt&ENUrGSeUyu9gO7EFF_KerL)qy=ZF( z!~$mIrVjj$Fs0y3h;@=lE?%ZTZf$LVI)kEVWfZWuuW`qih}wTSFINgd@}lPJm58n2 za7(~}z1w=ExwF}C^fwl)Pl%}@=xYzvz-8Z}wSDJd?|Tv68Y4Fmmqgk$+~Z%WN*W6VLI%j_2JtJERPQk=abzg-JUy<0}ay+|Au%o@lX}q%Hb4axd?$-&rNb`O)=%WcsW)HyQw%qRhzS6uK7=T zwH+OK*`C1yB`?ge*@pW8E|RoV@LRj`UGum_RNh}25#FW`_^qdC&SWLloh)z2PRX$N2G7Fwl=I&4aCZm?YdF>bsr1o}0WueU{tEY)9oIVJ;mkMA zb?F<%bN45A_N0v)Mtt0En4h>EZH1Tq7i60w0N(m3g>%YtTqWpV5g*Sgj<*Kg z(2uQlmT1erIUrDT>p2icA@b*o+Y)e!zDph;40c*k*IulkXzS=0DAyNT*((0t)47OK z%|c1lBJWC4f|=nU{49ho>~Q5y*chwxvQ@kKA{~=qE@3SUNACsgsH7rg12g`E+K@YAv^}=gqLwvB_UZFw)?!HyWVnImzA;fFE z?+Y0{wx%3hW(l7dGbk30#dV^>s7u&AgU3XlK7; zAai6=K0Uag*!}>a8;j0(iGU))@fIQBVOII6;L2#^g&w01N7`57kXJ@6UPvdY@wclE|r)X>wfK;OC0CVSGYKUnaJUdC;K@A^5jL|jZxk< z@1k7fm7CCdI42_ZU*=;iNx2JVK-|Zp`BhpcAf)-qZ*BZ?2m$mRee(_b7SLMpyXG%& z0y`YQrJb&y9`nAUY0J+ZG76GC!H{NLg8vFdUQ|wt2wmjEv0nJ-hBDlW_oiVWXvk|p zx2Nr|*_m9S#1%E)Alhkh|9kjk=yDG z?(L{BKC;QDS;j7PSs@SHLjzx< z!JoJ}>@w@D?#gGmEv^eFT86|Fcp@L@As@0x)l`0Q$8A`P9p0`}BdHb%oJ-?K9;0F< znZkFx(_e{b1VOUbS=+p1uP0Lpos}#NV9@vxfN8_W-OLc3v-O}S;Qqvopgk~7_h_LX zFCmQ4jVPF`roBOJ6QTxi+@=ENWfT}-{lN9!z@~>os!*A z*Oh4wmUPyLSthWR-o}9ybTTKw7v)%FcgxCr#f|!}04Xan-qbkASi^0bl1v&@QHFm- zO})2kBMiA_GocwpcFgY+aD6uzQ}H}A7tJW|VBoy*VFMFTGTsj%MuK|L;4$J z@25^MpNW2E6WlF|x0xgER7l^d9d;0yAchJZ|z{7;xzegg1a`%`I`U5aUw2FXsiPE%H_- zZ;pJq{M~<(N+sw(BKXZWUKlTjdpWvHf{65PbeRDjljbg;*|q^S{JPW5KG+nIiDC%F zah&}WJ7&tPU8e@x-6QEUTXe-qQJK=&$7fT8-|<@fmAqbrEWTwir9c(iy&f@~KtWbz z)x_zqC%%JGi{de!Z=?6VXxa@l`OT(ZvyEfM(2ZO4lHT2~!{=GY)Q9!h4Ae8Ks*fy6 z@bh^-vpqBv*GCX|ZdVvelH2GQtc<|b(5wRH>y{+92v2RnN4pJ9qk;P=VX*B^IUkFC z_8I03^zj%6obkkkIcFi!KQjT{F}A=t$Ha7x!0hAUIM9D4)AGGmJV6JDNM5^#K6f=h zN{ZT4Z8YjvUp}ko9=!b6t&uiKVCDEjuz3CbvXtCL1?M;6r(@uiw$qiCbmO3&s~8lh zPPy-L<_30nk)+yKGc}<&bTwQ11-aiTk}s1nDs}ax)iw-*&n>nEcowbLQd0@BzRJqg zZ8cmTqI3znT`O+0IA|^0pAS;l$)t20Lk^u9B+pJ4y-J!AyE_%}1hX!ZD}@X=U_ena zWH*Us<5|3nG69u6nl*Pwk*V~4cP-?ezOG@}trqA^Coi0z2clF_mkcLiW8RJooz4E~HRdffJHo8#oLW0huLF(wc%J zy#l|qp*QB+s9Yv9<{}Xz0&DKPne)x1xulF+PBxyT+N?O&1VZX?$q1pF!m3JIix63CmL?XAXsMo$IN3ZDH@n#F8Q;@$~$V8pHI& zQjOI<5W2tQcn;M-(HMNSn3rf+^Yqeq?ifPQf%|_f43<0V6i4CeZvC323PC$rw)8wi ziFG%2MdYJy3s0iTTTpo2)NjX%Tc>gjShhr1^(x~?f^jwu<@l#s&wGN$?uZdmY}xKP z`5ue%&&g0rkL^f$a(PP4x9m zHEI|qXTK_owMp~M+xgO7z5nI7uuD$3Kaom2xU^pq&8=wW&L-?b1T!Z5o_G+)_{|4% z{gts10Cxz2kxBBJ|Bx_es24%O?M94@n}rI#1@A&k-e;bsV}E-jTZ`Z)vTrFM#lHG} zee5O4k5N$PR67^Zz?dYR`K8=i8Z#br*)Fyc?r?#mIZC{W<_-K%2imnE1t4dH>J=03ZNKL_t(% zw+~#Gk!ZJEEZarQTnRCVa1(heysbul$PR&+Z`DuJc(AQ2jNVk>mljST;oBj~_gL>g zPI+%%Q(<4~_#O_7J<88d8y16#Y-{caENo!}Wv9;o+$mJnH6}sS0dmQWr3!?mlwEnY z*Xj+H_yEo2P6GYT^4Yha+J=bSpoLk`jn~=Um8Mw8&OTJ}^kE#z`;d_%oY0L!!2SFi zsuXcMhmAvijWdzg8H4Q+EZJ?0D%Nskjvi!}OVA$F9o)@OMRGue0o8UkfobjQ!TIjM z2+ezO;&gd5Gh?u&A@^>dgc!105E~GQ?o!fGH{cR?C zo5Do-*T*WwD|hUZi?7tynE5XALR^8n^^5*5q45`zdD-Bke!CXQWn}6b;}_WRYjw29 ztZ}Je=(d!26`HsAkC9l2&>OZdtg@40OBB2s5565tIChG?*CbeN&Tj^&^xec5lpzwp z?2y_I}V+Xw~zmQxLHg&e;tE&{w`PR2K?WKQ1_*IGxG90Pwwh( zVRJJDxp(wM1aB7L0*3k1cIpAYe_m$QmP+Pr-*YAmS77E$?M-ZKHI(UsJg!^43j{Un zk=Dn_kJgy+Aq8nHxFiR`2AUwYs!niFX3{f};0;Y_g~LZKI*|J_b_s10N>VCm+zu$QG&10Pzt+7v35qV8=SX_#z(Rwyek16uQi|-O2qqwQ-wlCc0 z94u%zSm5tRy_okpD6O=^?JpNBowrSZ+XUKkEvKDguiI#N#s_rU?IuI@W?ju-*jPpX zq|%rf%)!~OnUa{jRAroAaK8XoLJ(m2NhW@i1MrrCsWi6S<1KmvpuE>8q^mjq^pQs8ZL0_AZR z1SCf5CaH;&E;8Taun_(+8Rh)$(pfdizc4ldM zhD6nEI|I~l)HLvTy5Q^)qO+FUeg~`bwOxA)ts9n=fO!j-1|TsRB?7n{S3^pdvx?n) z@klsR1m&Z*#RUw}J-#XGcNQeCj2kTSF>bMpU%FuLX@-RI#AGZz=H@slIXx|$sy_q- z<0+DVvNZvgK5|fub+gWpi*rdsz|mx)lf;7hu$evIS?&uQa~o#PT0 zWfSHM0Spmit@dQ}6)`8hnjeq1HlMJ*2_#+O(jH_O)5?5~9msfwWDOt?;_@X;{M9G5 zHGhf-!?!n>jD%Y;CfAzQ-{7I)J2)RBR%QQ_FgcZqrq!?mFK(IzG$rzGMUOfYe9pw0 z%=9eGW_$nagI66yp_Pv7zHSSI#KE<3*6gUGAF6wEauZPnHE>r~{OG3?Td9B9u^!xl zqau=4zbUc*r%h!`T6Z|NM`Z*pr!zK`j1AYa5zw-XS>pt`0E6-L$TmA>E90 z;4dTT)(GN{24Q;ZJb9hqcuo`qI0N>1k-mC&BR8=@R+F<)ydtrQ%7C%6%39lGf#RRk z%0D-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


sC|y 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
#I;J5E(+F$+>!{ml2S=W%!IA@Ig*5 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 z%0D6Wfv5%+QN3sJLaSQ=ejqp=-BX)(7*g>oCZ}4p9=%OTmi*{-z1HY$?fKkFpA>6( zrNJ7l=X~-z&Y1()@H7JEFx>aV#IT&)d$!fD#e|*aL1mg-PrioEZ(U zYeZ9^g)jgHuxd;LP?9GLa6zWxbAahhsY%;aqwZm zdH+q}!06R-hxx`vHAcz0*{x%O9b;QYmSSf>*wLPr2`~Owu*+xQ=4Nik7C;Q zay;AdxZ~~N{Vy~Fz$jFcF63o1#7~_N@kCOCdFJ;gDl6DS?E%M{cYe3SIFi7N@8#7Q z;Le6PfNjh3G%^)}aF60BVN~is{3{;!PIISrh*|9euL{=-zLvEeN9Oo=UTwiF&r{xi zC^J3F({S%}IS#lB_8+um6(avk17sAUW+63IG}-0D-%<{r#(Z)^jCus85*H=rO97TK zBSRq0vj|$zkbB^a4q4#rC}^ajPkounu^R&iDhTJ2Ca1IIXB4N+@$8TrcOMPkv_=9k z=&EKql09o?Y+h>~YxFHSJ_{?p-O0bp$Xi>`k@2I03^cN8c6 zUXnHjL>^(zun-K9|K~ZvHVt-J{I-~#Z@}Mx{ds_U0)Ji@zb^QtibHyG5htk={jy@4 z=>PzjR2zmouiDw~{Bp;BCj55zGZ~v)tOEdi4;a0fhxcw+TI&&_kG8)OKr#?Zix8

E-a8lN(0J=BqCWu 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 literal 0 HcmV?d00001 diff --git a/backend/modules/test_images/init-mask_no_mask.png b/backend/modules/test_images/init-mask_no_mask.png new file mode 100644 index 0000000000000000000000000000000000000000..2aecd3ea7db2c6adc472e8a8483a8ee6025d89a2 GIT binary patch literal 3513 zcmeHK?@tqF9Dk4jibBlX)YWKi$CjAP-t}66_3X*8McPOi1(aff<7l6@N87vG-Cd$RC)(3-6nBNqbNZJcRMREs~|xvpU5W+`1)+jB6)pu zrETMsFhY!*-RRYq|vBH480uV6*j8pUqH!s(>#oU8~^OxsG9dKG*zxk@fWoL1u)re&IDJ!+5`T$BWF zlLvaW!;xGPl?9&?VI^4XM@eSzVxNyg;f!GwYV~3iK^chr*%pxiL~0Me8#(0}sdn8x z*DT~5=PerHzBWa6$vxEmXpWH6g9I(6M-k-F{E^V0@l1?g0wAr0Lur|l4ggl~Yufk4 zrVYi9?Jm0M&}C+1oNGI?MaN)`OOEZzc(ft2HhgC+ucCY8gI$T7;mi!z+uK@yU)Z=J zk=xQazY`{i#wuxDO?uv~MgFe}dk)D5&FSBXTL*qTH`z8YmS`Kj5pTV+Zbipg*YoRE z(eLizCMz3rg{CYBY{`iHimyf%mWv+AaUyq6P`6t>x)sMV)taDS} zi9X&*tlkkEKWpqc7+-Vyz`)jLucZfD&zOE|_4K$M+!Jif+*L+@^yf(bjy+7r;lule z^jBXkpI@{sUPit02AjG3t(f~0ll{ntC-;xOaQTR@M0)(t=Ip?lH=ioW{rF_;)T#pq z7c)ej^Wx8cjeb79=bejEQ}?p*jzvG5&eEMfdVyPhWcO<>OG|s{g-cs*)#TP+tGn~% z-m&4VemY*aB{7s67oO|isT=Hk`qajec6;xQ1#3%>-qp1)z0Caa{q>1eeZgCsYtD3M zeI{K!JCVcN{XczMw=;-784E;vtqj1zCF(B?w8xhNkhRibE3S^lZw^vv09({+=a9419C@d^#9n0dQr4#W3|qg& { const { shouldShowGalleryButton, shouldShowOptionsPanelButton } = useAppSelector(appSelector); - useEffect(() => { - dispatch(requestSystemConfig()); - }, [dispatch]); - return (

diff --git a/frontend/src/app/constants.ts b/frontend/src/app/constants.ts index bd457dc7fb..78511c10d7 100644 --- a/frontend/src/app/constants.ts +++ b/frontend/src/app/constants.ts @@ -1,6 +1,6 @@ // TODO: use Enums? -import { InProgressImageType } from '../features/system/systemSlice'; +import { InProgressImageType } from 'features/system/systemSlice'; // Valid samplers export const SAMPLERS: Array = [ diff --git a/frontend/src/app/invokeai.d.ts b/frontend/src/app/invokeai.d.ts index 0a263e2799..3407f68455 100644 --- a/frontend/src/app/invokeai.d.ts +++ b/frontend/src/app/invokeai.d.ts @@ -12,7 +12,9 @@ * 'gfpgan'. */ -import { Category as GalleryCategory } from '../features/gallery/gallerySlice'; +import { Category as GalleryCategory } from 'features/gallery/gallerySlice'; +import { InvokeTabName } from 'features/tabs/InvokeTabs'; +import { IRect } from 'konva/lib/types'; /** * TODO: @@ -115,8 +117,8 @@ export declare type Image = { metadata?: Metadata; width: number; height: number; - category: GalleryCategory; - isBase64: boolean; + category: GalleryCategory; + isBase64: boolean; }; // GalleryImages is an array of Image. @@ -171,10 +173,13 @@ export declare type SystemStatusResponse = SystemStatus; export declare type SystemConfigResponse = SystemConfig; -export declare type ImageResultResponse = Omit; +export declare type ImageResultResponse = Omit & { + boundingBox?: IRect; + generationMode: InvokeTabName; +}; export declare type ImageUploadResponse = Omit & { - destination: 'img2img' | 'inpainting'; + destination: 'img2img' | 'inpainting' | 'outpainting' | 'outpainting_merge'; }; export declare type ErrorResponse = { @@ -198,9 +203,17 @@ export declare type ImageUrlResponse = { url: string; }; -export declare type ImageUploadDestination = 'img2img' | 'inpainting'; +export declare type ImageUploadDestination = + | 'img2img' + | 'inpainting' + | 'outpainting_merge'; export declare type UploadImagePayload = { file: File; destination?: ImageUploadDestination; }; + +export declare type UploadOutpaintingMergeImagePayload = { + dataURL: string; + name: string; +}; diff --git a/frontend/src/app/selectors/readinessSelector.ts b/frontend/src/app/selectors/readinessSelector.ts index 702f45c473..559c71b614 100644 --- a/frontend/src/app/selectors/readinessSelector.ts +++ b/frontend/src/app/selectors/readinessSelector.ts @@ -1,39 +1,35 @@ import { createSelector } from '@reduxjs/toolkit'; import _ from 'lodash'; -import { RootState } from '../store'; -import { activeTabNameSelector } from '../../features/options/optionsSelectors'; -import { OptionsState } from '../../features/options/optionsSlice'; - -import { SystemState } from '../../features/system/systemSlice'; -import { InpaintingState } from '../../features/tabs/Inpainting/inpaintingSlice'; -import { validateSeedWeights } from '../../common/util/seedWeightPairs'; +import { RootState } from 'app/store'; +import { activeTabNameSelector } from 'features/options/optionsSelectors'; +import { OptionsState } from 'features/options/optionsSlice'; +import { SystemState } from 'features/system/systemSlice'; +import { baseCanvasImageSelector } from 'features/canvas/canvasSlice'; +import { validateSeedWeights } from 'common/util/seedWeightPairs'; export const readinessSelector = createSelector( [ (state: RootState) => state.options, (state: RootState) => state.system, - (state: RootState) => state.inpainting, + baseCanvasImageSelector, activeTabNameSelector, ], ( options: OptionsState, system: SystemState, - inpainting: InpaintingState, + baseCanvasImage, activeTabName ) => { const { prompt, shouldGenerateVariations, seedWeights, - // maskPath, initialImage, seed, } = options; const { isProcessing, isConnected } = system; - const { imageToInpaint } = inpainting; - let isReady = true; const reasonsWhyNotReady: string[] = []; @@ -48,20 +44,11 @@ export const readinessSelector = createSelector( reasonsWhyNotReady.push('No initial image selected'); } - if (activeTabName === 'inpainting' && !imageToInpaint) { + if (activeTabName === 'inpainting' && !baseCanvasImage) { isReady = false; reasonsWhyNotReady.push('No inpainting image selected'); } - // // We don't use mask paths now. - // // Cannot generate with a mask without img2img - // if (maskPath && !initialImage) { - // isReady = false; - // reasonsWhyNotReady.push( - // 'On ImageToImage tab, but no mask is provided.' - // ); - // } - // TODO: job queue // Cannot generate if already processing an image if (isProcessing) { diff --git a/frontend/src/app/socketio/actions.ts b/frontend/src/app/socketio/actions.ts index 05e0eb92b8..faad169b07 100644 --- a/frontend/src/app/socketio/actions.ts +++ b/frontend/src/app/socketio/actions.ts @@ -1,7 +1,7 @@ import { createAction } from '@reduxjs/toolkit'; -import { GalleryCategory } from '../../features/gallery/gallerySlice'; -import { InvokeTabName } from '../../features/tabs/InvokeTabs'; -import * as InvokeAI from '../invokeai'; +import { GalleryCategory } from 'features/gallery/gallerySlice'; +import { InvokeTabName } from 'features/tabs/InvokeTabs'; +import * as InvokeAI from 'app/invokeai'; /** diff --git a/frontend/src/app/socketio/emitters.ts b/frontend/src/app/socketio/emitters.ts index 3f1740b027..803b81ca03 100644 --- a/frontend/src/app/socketio/emitters.ts +++ b/frontend/src/app/socketio/emitters.ts @@ -4,23 +4,24 @@ import { Socket } from 'socket.io-client'; import { frontendToBackendParameters, FrontendToBackendParametersConfig, -} from '../../common/util/parameterTranslation'; +} from 'common/util/parameterTranslation'; import { GalleryCategory, GalleryState, removeImage, -} from '../../features/gallery/gallerySlice'; -import { OptionsState } from '../../features/options/optionsSlice'; +} from 'features/gallery/gallerySlice'; +import { OptionsState } from 'features/options/optionsSlice'; import { addLogEntry, errorOccurred, modelChangeRequested, setIsProcessing, -} from '../../features/system/systemSlice'; -import { inpaintingImageElementRef } from '../../features/tabs/Inpainting/InpaintingCanvas'; -import { InvokeTabName } from '../../features/tabs/InvokeTabs'; -import * as InvokeAI from '../invokeai'; -import { RootState } from '../store'; +} from 'features/system/systemSlice'; +import { inpaintingImageElementRef } from 'features/canvas/IAICanvas'; +import { InvokeTabName } from 'features/tabs/InvokeTabs'; +import * as InvokeAI from 'app/invokeai'; +import { RootState } from 'app/store'; +import { baseCanvasImageSelector } from 'features/canvas/canvasSlice'; /** * Returns an object containing all functions which use `socketio.emit()`. @@ -42,7 +43,7 @@ const makeSocketIOEmitters = ( const { options: optionsState, system: systemState, - inpainting: inpaintingState, + canvas: canvasState, gallery: galleryState, } = state; @@ -50,15 +51,15 @@ const makeSocketIOEmitters = ( { generationMode, optionsState, - inpaintingState, + canvasState, systemState, }; - if (generationMode === 'inpainting') { - if ( - !inpaintingImageElementRef.current || - !inpaintingState.imageToInpaint?.url - ) { + if (['inpainting', 'outpainting'].includes(generationMode)) { + const baseCanvasImage = baseCanvasImageSelector(getState()); + const imageUrl = baseCanvasImage?.url; + + if (!inpaintingImageElementRef.current || !imageUrl) { dispatch( addLogEntry({ timestamp: dateFormat(new Date(), 'isoDateTime'), @@ -70,11 +71,10 @@ const makeSocketIOEmitters = ( return; } - frontendToBackendParametersConfig.imageToProcessUrl = - inpaintingState.imageToInpaint.url; + frontendToBackendParametersConfig.imageToProcessUrl = imageUrl; - frontendToBackendParametersConfig.maskImageElement = - inpaintingImageElementRef.current; + // frontendToBackendParametersConfig.maskImageElement = + // inpaintingImageElementRef.current; } else if (!['txt2img', 'img2img'].includes(generationMode)) { if (!galleryState.currentImage?.url) return; @@ -96,7 +96,12 @@ const makeSocketIOEmitters = ( // TODO: handle maintaining masks for reproducibility in future if (generationParameters.init_mask) { generationParameters.init_mask = generationParameters.init_mask - .substr(0, 20) + .substr(0, 64) + .concat('...'); + } + if (generationParameters.init_img) { + generationParameters.init_img = generationParameters.init_img + .substr(0, 64) .concat('...'); } diff --git a/frontend/src/app/socketio/listeners.ts b/frontend/src/app/socketio/listeners.ts index e27d79f55c..84dab263c2 100644 --- a/frontend/src/app/socketio/listeners.ts +++ b/frontend/src/app/socketio/listeners.ts @@ -2,7 +2,7 @@ import { AnyAction, MiddlewareAPI, Dispatch } from '@reduxjs/toolkit'; import { v4 as uuidv4 } from 'uuid'; import dateFormat from 'dateformat'; -import * as InvokeAI from '../invokeai'; +import * as InvokeAI from 'app/invokeai'; import { addLogEntry, @@ -15,7 +15,7 @@ import { errorOccurred, setModelList, setIsCancelable, -} from '../../features/system/systemSlice'; +} from 'features/system/systemSlice'; import { addGalleryImages, @@ -25,19 +25,21 @@ import { removeImage, setCurrentImage, setIntermediateImage, -} from '../../features/gallery/gallerySlice'; +} from 'features/gallery/gallerySlice'; import { clearInitialImage, setInitialImage, setMaskPath, -} from '../../features/options/optionsSlice'; -import { requestImages, requestNewImages } from './actions'; +} from 'features/options/optionsSlice'; +import { requestImages, requestNewImages, requestSystemConfig } from './actions'; import { + addImageToOutpaintingSesion, clearImageToInpaint, setImageToInpaint, -} from '../../features/tabs/Inpainting/inpaintingSlice'; -import { tabMap } from '../../features/tabs/InvokeTabs'; + setImageToOutpaint, +} from 'features/canvas/canvasSlice'; +import { tabMap } from 'features/tabs/InvokeTabs'; /** * Returns an object containing listener callbacks for socketio events. @@ -56,6 +58,7 @@ const makeSocketIOListeners = ( try { dispatch(setIsConnected(true)); dispatch(setCurrentStatus('Connected')); + dispatch(requestSystemConfig()); const gallery: GalleryState = getState().gallery; if (gallery.categories.user.latest_mtime) { @@ -111,6 +114,16 @@ const makeSocketIOListeners = ( }) ); + if (data.generationMode === 'outpainting' && data.boundingBox) { + const { boundingBox } = data; + dispatch( + addImageToOutpaintingSesion({ + image: newImage, + boundingBox, + }) + ); + } + if (shouldLoopback) { const activeTabName = tabMap[activeTab]; switch (activeTabName) { @@ -299,15 +312,15 @@ const makeSocketIOListeners = ( // remove references to image in options const { initialImage, maskPath } = getState().options; - const { imageToInpaint } = getState().inpainting; + const { inpainting, outpainting } = getState().canvas; if (initialImage?.url === url || initialImage === url) { dispatch(clearInitialImage()); } - if (imageToInpaint?.url === url) { - dispatch(clearImageToInpaint()); - } + // if (imageToInpaint?.url === url) { + // dispatch(clearImageToInpaint()); + // } if (maskPath === url) { dispatch(setMaskPath('')); diff --git a/frontend/src/app/socketio/middleware.ts b/frontend/src/app/socketio/middleware.ts index 854e245c4f..3f4fd1d06c 100644 --- a/frontend/src/app/socketio/middleware.ts +++ b/frontend/src/app/socketio/middleware.ts @@ -4,7 +4,7 @@ import { io } from 'socket.io-client'; import makeSocketIOListeners from './listeners'; import makeSocketIOEmitters from './emitters'; -import * as InvokeAI from '../invokeai'; +import * as InvokeAI from 'app/invokeai'; /** * Creates a socketio middleware to handle communication with server. @@ -104,12 +104,9 @@ export const socketioMiddleware = () => { onImageDeleted(data); }); - socketio.on( - 'imageUploaded', - (data: InvokeAI.ImageUploadResponse) => { - onImageUploaded(data); - } - ); + socketio.on('imageUploaded', (data: InvokeAI.ImageUploadResponse) => { + onImageUploaded(data); + }); socketio.on('maskImageUploaded', (data: InvokeAI.ImageUrlResponse) => { onMaskImageUploaded(data); diff --git a/frontend/src/app/store.ts b/frontend/src/app/store.ts index 76ccc09bfe..f2b5b8e636 100644 --- a/frontend/src/app/store.ts +++ b/frontend/src/app/store.ts @@ -5,16 +5,14 @@ import type { TypedUseSelectorHook } from 'react-redux'; import { persistReducer } from 'redux-persist'; import storage from 'redux-persist/lib/storage'; // defaults to localStorage for web -import optionsReducer, { OptionsState } from '../features/options/optionsSlice'; -import galleryReducer, { GalleryState } from '../features/gallery/gallerySlice'; -import inpaintingReducer, { - InpaintingState, -} from '../features/tabs/Inpainting/inpaintingSlice'; +import { getPersistConfig } from 'redux-deep-persist'; + +import optionsReducer from 'features/options/optionsSlice'; +import galleryReducer from 'features/gallery/gallerySlice'; +import systemReducer from 'features/system/systemSlice'; +import canvasReducer from 'features/canvas/canvasSlice'; -import systemReducer, { SystemState } from '../features/system/systemSlice'; import { socketioMiddleware } from './socketio/middleware'; -import autoMergeLevel2 from 'redux-persist/es/stateReconciler/autoMergeLevel2'; -import { PersistPartial } from 'redux-persist/es/persistReducer'; /** * redux-persist provides an easy and reliable way to persist state across reloads. @@ -28,87 +26,82 @@ import { PersistPartial } from 'redux-persist/es/persistReducer'; * These can be blacklisted in redux-persist. * * The necesssary nested persistors with blacklists are configured below. - * - * TODO: Do we blacklist initialImagePath? If the image is deleted from disk we get an - * ugly 404. But if we blacklist it, then this is a valuable parameter that is lost - * on reload. Need to figure out a good way to handle this. */ -const rootPersistConfig = { - key: 'root', - storage, - stateReconciler: autoMergeLevel2, - blacklist: ['gallery', 'system', 'inpainting'], -}; +const genericCanvasBlacklist = [ + 'pastObjects', + 'futureObjects', + 'stageScale', + 'stageDimensions', + 'stageCoordinates', + 'cursorPosition', +]; -const systemPersistConfig = { - key: 'system', - storage, - stateReconciler: autoMergeLevel2, - blacklist: [ - 'isCancelable', - 'isConnected', - 'isProcessing', - 'currentStep', - 'socketId', - 'isESRGANAvailable', - 'isGFPGANAvailable', - 'currentStep', - 'totalSteps', - 'currentIteration', - 'totalIterations', - 'currentStatus', - ], -}; +const inpaintingCanvasBlacklist = genericCanvasBlacklist.map( + (blacklistItem) => `canvas.inpainting.${blacklistItem}` +); -const galleryPersistConfig = { - key: 'gallery', - storage, - stateReconciler: autoMergeLevel2, - whitelist: [ - 'galleryWidth', - 'shouldPinGallery', - 'shouldShowGallery', - 'galleryScrollPosition', - 'galleryImageMinimumWidth', - 'galleryImageObjectFit', - ], -}; +const outpaintingCanvasBlacklist = genericCanvasBlacklist.map( + (blacklistItem) => `canvas.outpainting.${blacklistItem}` +); -const inpaintingPersistConfig = { - key: 'inpainting', - storage, - stateReconciler: autoMergeLevel2, - blacklist: ['pastLines', 'futuresLines', 'cursorPosition'], -}; +const systemBlacklist = [ + 'currentIteration', + 'currentStatus', + 'currentStep', + 'isCancelable', + 'isConnected', + 'isESRGANAvailable', + 'isGFPGANAvailable', + 'isProcessing', + 'socketId', + 'totalIterations', + 'totalSteps', +].map((blacklistItem) => `system.${blacklistItem}`); -const reducers = combineReducers({ +const galleryBlacklist = [ + 'categories', + 'currentCategory', + 'currentImage', + 'currentImageUuid', + 'shouldAutoSwitchToNewImages', + 'shouldHoldGalleryOpen', + 'intermediateImage', +].map((blacklistItem) => `gallery.${blacklistItem}`); + +const rootReducer = combineReducers({ options: optionsReducer, - gallery: persistReducer(galleryPersistConfig, galleryReducer), - system: persistReducer(systemPersistConfig, systemReducer), - inpainting: persistReducer( - inpaintingPersistConfig, - inpaintingReducer - ), + gallery: galleryReducer, + system: systemReducer, + canvas: canvasReducer, }); -const persistedReducer = persistReducer<{ - options: OptionsState; - gallery: GalleryState & PersistPartial; - system: SystemState & PersistPartial; - inpainting: InpaintingState & PersistPartial; -}>(rootPersistConfig, reducers); +const rootPersistConfig = getPersistConfig({ + key: 'root', + storage, + rootReducer, + blacklist: [ + ...inpaintingCanvasBlacklist, + ...outpaintingCanvasBlacklist, + ...systemBlacklist, + ...galleryBlacklist, + ], + throttle: 500, +}); + +const persistedReducer = persistReducer(rootPersistConfig, rootReducer); // Continue with store setup export const store = configureStore({ reducer: persistedReducer, middleware: (getDefaultMiddleware) => getDefaultMiddleware({ - // redux-persist sometimes needs to temporarily put a function in redux state, need to disable this check + immutableCheck: false, serializableCheck: false, }).concat(socketioMiddleware()), }); +export type AppGetState = typeof store.getState; export type RootState = ReturnType; export type AppDispatch = typeof store.dispatch; diff --git a/frontend/src/common/components/GuideIcon.tsx b/frontend/src/common/components/GuideIcon.tsx index 2f4312ae76..e3e32ea32e 100644 --- a/frontend/src/common/components/GuideIcon.tsx +++ b/frontend/src/common/components/GuideIcon.tsx @@ -1,7 +1,7 @@ import { Box, forwardRef, Icon } from '@chakra-ui/react'; import { IconType } from 'react-icons'; import { MdHelp } from 'react-icons/md'; -import { Feature } from '../../app/features'; +import { Feature } from 'app/features'; import GuidePopover from './GuidePopover'; type GuideIconProps = { diff --git a/frontend/src/common/components/GuidePopover.scss b/frontend/src/common/components/GuidePopover.scss index faa31212bb..58434270b2 100644 --- a/frontend/src/common/components/GuidePopover.scss +++ b/frontend/src/common/components/GuidePopover.scss @@ -1,11 +1,11 @@ .guide-popover-arrow { - background-color: var(--tab-panel-bg) !important; - box-shadow: none !important; + background-color: var(--tab-panel-bg); + box-shadow: none; } .guide-popover-content { - background-color: var(--background-color-secondary) !important; - border: none !important; + background-color: var(--background-color-secondary); + border: none; } .guide-popover-guide-content { diff --git a/frontend/src/common/components/GuidePopover.tsx b/frontend/src/common/components/GuidePopover.tsx index b5893629c0..2fd6d082d0 100644 --- a/frontend/src/common/components/GuidePopover.tsx +++ b/frontend/src/common/components/GuidePopover.tsx @@ -5,12 +5,12 @@ import { PopoverTrigger, Box, } from '@chakra-ui/react'; -import { SystemState } from '../../features/system/systemSlice'; -import { useAppSelector } from '../../app/store'; -import { RootState } from '../../app/store'; +import { SystemState } from 'features/system/systemSlice'; +import { useAppSelector } from 'app/store'; +import { RootState } from 'app/store'; import { createSelector } from '@reduxjs/toolkit'; import { ReactElement } from 'react'; -import { Feature, FEATURES } from '../../app/features'; +import { Feature, FEATURES } from 'app/features'; type GuideProps = { children: ReactElement; diff --git a/frontend/src/common/components/IAIButton.scss b/frontend/src/common/components/IAIButton.scss index 1ac41cf0d7..90489a3bda 100644 --- a/frontend/src/common/components/IAIButton.scss +++ b/frontend/src/common/components/IAIButton.scss @@ -1,3 +1,8 @@ .invokeai__button { - justify-content: space-between; + background-color: var(--btn-base-color); + place-content: center; + + &:hover { + background-color: var(--btn-base-color-hover); + } } diff --git a/frontend/src/common/components/IAICheckbox.scss b/frontend/src/common/components/IAICheckbox.scss index c0118e25e1..3b79c8f4db 100644 --- a/frontend/src/common/components/IAICheckbox.scss +++ b/frontend/src/common/components/IAICheckbox.scss @@ -15,7 +15,7 @@ svg { width: 0.6rem; height: 0.6rem; - stroke-width: 3px !important; + stroke-width: 3px; } &[data-checked] { diff --git a/frontend/src/common/components/IAIIconButton.scss b/frontend/src/common/components/IAIIconButton.scss index 7bed75c3fc..d55e5de4c5 100644 --- a/frontend/src/common/components/IAIIconButton.scss +++ b/frontend/src/common/components/IAIIconButton.scss @@ -1,11 +1,11 @@ @use '../../styles/Mixins/' as *; .invokeai__icon-button { - background-color: var(--btn-grey); + background: var(--btn-base-color); cursor: pointer; &:hover { - background-color: var(--btn-grey-hover); + background-color: var(--btn-base-color-hover); } &[data-selected='true'] { @@ -20,16 +20,39 @@ } &[data-variant='link'] { - background: none !important; + background: none; &:hover { - background: none !important; + background: none; } } - &[data-selected='true'] { - border-color: var(--accent-color); + // Check Box Style + &[data-as-checkbox='true'] { + background-color: var(--btn-base-color); + border: 3px solid var(--btn-base-color); + + svg { + fill: var(--text-color); + } + &:hover { - border-color: var(--accent-color-hover); + background-color: var(--btn-base-color); + border-color: var(--btn-checkbox-border-hover); + svg { + fill: var(--text-color); + } + } + + &[data-selected='true'] { + border-color: var(--accent-color); + svg { + fill: var(--accent-color-hover); + } + &:hover { + svg { + fill: var(--accent-color-hover); + } + } } } @@ -38,28 +61,12 @@ animation-duration: 1s; animation-timing-function: ease-in-out; animation-iteration-count: infinite; + &:hover { animation: none; background-color: var(--accent-color-hover); } } - - &[data-as-checkbox='true'] { - background-color: var(--btn-grey); - border: 3px solid var(--btn-grey); - - svg { - fill: var(--text-color); - } - - &:hover { - background-color: var(--btn-grey); - border-color: var(--btn-checkbox-border-hover); - svg { - fill: var(--text-color); - } - } - } } @keyframes pulseColor { diff --git a/frontend/src/common/components/IAIIconButton.tsx b/frontend/src/common/components/IAIIconButton.tsx index 3cc76c09f0..239e1f5372 100644 --- a/frontend/src/common/components/IAIIconButton.tsx +++ b/frontend/src/common/components/IAIIconButton.tsx @@ -25,13 +25,23 @@ const IAIIconButton = forwardRef((props: IAIIconButtonProps, forwardedRef) => { } = props; return ( - + diff --git a/frontend/src/common/components/IAINumberInput.scss b/frontend/src/common/components/IAINumberInput.scss index c7de72dd9a..5012828311 100644 --- a/frontend/src/common/components/IAINumberInput.scss +++ b/frontend/src/common/components/IAINumberInput.scss @@ -1,16 +1,14 @@ .invokeai__number-input-form-control { - display: grid; - grid-template-columns: max-content auto; + display: flex; align-items: center; + column-gap: 1rem; .invokeai__number-input-form-label { color: var(--text-color-secondary); margin-right: 0; font-size: 1rem; margin-bottom: 0; - flex-grow: 2; white-space: nowrap; - padding-right: 1rem; &[data-focus] + .invokeai__number-input-root { outline: none; @@ -33,7 +31,7 @@ align-items: center; background-color: var(--background-color-secondary); border: 2px solid var(--border-color); - border-radius: 0.2rem; + border-radius: 0.3rem; } .invokeai__number-input-field { @@ -41,10 +39,8 @@ font-weight: bold; width: 100%; height: auto; - padding: 0; font-size: 0.9rem; - padding-left: 0.5rem; - padding-right: 0.5rem; + padding: 0 0.5rem; &:focus { outline: none; diff --git a/frontend/src/common/components/IAINumberInput.tsx b/frontend/src/common/components/IAINumberInput.tsx index b538092909..9d6e6969a0 100644 --- a/frontend/src/common/components/IAINumberInput.tsx +++ b/frontend/src/common/components/IAINumberInput.tsx @@ -21,6 +21,7 @@ const numberStringRegex = /^-?(0\.)?\.?$/; interface Props extends Omit { styleClass?: string; label?: string; + labelFontSize?: string | number; width?: string | number; showStepper?: boolean; value: number; @@ -43,6 +44,7 @@ interface Props extends Omit { const IAINumberInput = (props: Props) => { const { label, + labelFontSize = '1rem', styleClass, isDisabled = false, showStepper = true, @@ -127,6 +129,7 @@ const IAINumberInput = (props: Props) => { {label} diff --git a/frontend/src/common/components/IAIPopover.scss b/frontend/src/common/components/IAIPopover.scss index 73fab8cfb5..ab2ac26b3a 100644 --- a/frontend/src/common/components/IAIPopover.scss +++ b/frontend/src/common/components/IAIPopover.scss @@ -1,10 +1,10 @@ .invokeai__popover-content { min-width: unset; - width: unset !important; + width: unset; padding: 1rem; - border-radius: 0.5rem !important; - background-color: var(--background-color) !important; - border: 2px solid var(--border-color) !important; + border-radius: 0.5rem; + background-color: var(--background-color); + border: 2px solid var(--border-color); .invokeai__popover-arrow { background-color: var(--background-color) !important; diff --git a/frontend/src/common/components/IAIPopover.tsx b/frontend/src/common/components/IAIPopover.tsx index ff18d96ddd..74bf1644a4 100644 --- a/frontend/src/common/components/IAIPopover.tsx +++ b/frontend/src/common/components/IAIPopover.tsx @@ -29,7 +29,7 @@ const IAIPopover = (props: IAIPopoverProps) => { {triggerComponent} - {hasArrow && } + {hasArrow && } {children} diff --git a/frontend/src/common/components/IAISelect.scss b/frontend/src/common/components/IAISelect.scss index d0b9e54037..83df2d41bf 100644 --- a/frontend/src/common/components/IAISelect.scss +++ b/frontend/src/common/components/IAISelect.scss @@ -27,5 +27,6 @@ .invokeai__select-option { background-color: var(--background-color-secondary); + color: var(--text-color-secondary); } } diff --git a/frontend/src/common/components/IAISelect.tsx b/frontend/src/common/components/IAISelect.tsx index cfec3ff18d..138ba2da30 100644 --- a/frontend/src/common/components/IAISelect.tsx +++ b/frontend/src/common/components/IAISelect.tsx @@ -2,7 +2,7 @@ import { FormControl, FormLabel, Select, SelectProps } from '@chakra-ui/react'; import { MouseEvent } from 'react'; type IAISelectProps = SelectProps & { - label: string; + label?: string; styleClass?: string; validValues: | Array @@ -32,15 +32,18 @@ const IAISelect = (props: IAISelectProps) => { e.nativeEvent.cancelBubble = true; }} > - - {label} - + {label && ( + + {label} + + )} + {children} {isDragActive && isHandlingUpload && ( diff --git a/frontend/src/common/components/ImageUploaderButton.tsx b/frontend/src/common/components/ImageUploaderButton.tsx index 373ab7ad21..c11428cec7 100644 --- a/frontend/src/common/components/ImageUploaderButton.tsx +++ b/frontend/src/common/components/ImageUploaderButton.tsx @@ -1,7 +1,7 @@ import { Heading } from '@chakra-ui/react'; import { useContext } from 'react'; import { FaUpload } from 'react-icons/fa'; -import { ImageUploaderTriggerContext } from '../../app/contexts/ImageUploaderTriggerContext'; +import { ImageUploaderTriggerContext } from 'app/contexts/ImageUploaderTriggerContext'; type ImageUploaderButtonProps = { styleClass?: string; diff --git a/frontend/src/common/components/ImageUploaderIconButton.tsx b/frontend/src/common/components/ImageUploaderIconButton.tsx index 214e7b7b7c..b35b32afce 100644 --- a/frontend/src/common/components/ImageUploaderIconButton.tsx +++ b/frontend/src/common/components/ImageUploaderIconButton.tsx @@ -1,6 +1,6 @@ import { useContext } from 'react'; import { FaUpload } from 'react-icons/fa'; -import { ImageUploaderTriggerContext } from '../../app/contexts/ImageUploaderTriggerContext'; +import { ImageUploaderTriggerContext } from 'app/contexts/ImageUploaderTriggerContext'; import IAIIconButton from './IAIIconButton'; const ImageUploaderIconButton = () => { diff --git a/frontend/src/common/components/WorkInProgress/ImageToImageWIP.tsx b/frontend/src/common/components/WorkInProgress/ImageToImageWIP.tsx index 20686087a0..0867232c31 100644 --- a/frontend/src/common/components/WorkInProgress/ImageToImageWIP.tsx +++ b/frontend/src/common/components/WorkInProgress/ImageToImageWIP.tsx @@ -1,5 +1,5 @@ import React from 'react'; -import Img2ImgPlaceHolder from '../../../assets/images/image2img.png'; +import Img2ImgPlaceHolder from 'assets/images/image2img.png'; export const ImageToImageWIP = () => { return ( diff --git a/frontend/src/common/util/openBase64ImageInTab.ts b/frontend/src/common/util/openBase64ImageInTab.ts new file mode 100644 index 0000000000..0e18ccb45f --- /dev/null +++ b/frontend/src/common/util/openBase64ImageInTab.ts @@ -0,0 +1,21 @@ +type Base64AndCaption = { + base64: string; + caption: string; +}; + +const openBase64ImageInTab = (images: Base64AndCaption[]) => { + const w = window.open(''); + if (!w) return; + + images.forEach((i) => { + const image = new Image(); + image.src = i.base64; + + w.document.write(i.caption); + w.document.write('
'); + w.document.write(image.outerHTML); + w.document.write('

'); + }); +}; + +export default openBase64ImageInTab; diff --git a/frontend/src/common/util/parameterTranslation.ts b/frontend/src/common/util/parameterTranslation.ts index d1f52cd9ac..f73da43898 100644 --- a/frontend/src/common/util/parameterTranslation.ts +++ b/frontend/src/common/util/parameterTranslation.ts @@ -1,20 +1,21 @@ -import { NUMPY_RAND_MAX, NUMPY_RAND_MIN } from '../../app/constants'; -import { OptionsState } from '../../features/options/optionsSlice'; -import { SystemState } from '../../features/system/systemSlice'; +import { NUMPY_RAND_MAX, NUMPY_RAND_MIN } from 'app/constants'; +import { OptionsState } from 'features/options/optionsSlice'; +import { SystemState } from 'features/system/systemSlice'; import { stringToSeedWeightsArray } from './seedWeightPairs'; import randomInt from './randomInt'; -import { InvokeTabName } from '../../features/tabs/InvokeTabs'; -import { InpaintingState } from '../../features/tabs/Inpainting/inpaintingSlice'; -import generateMask from '../../features/tabs/Inpainting/util/generateMask'; +import { InvokeTabName } from 'features/tabs/InvokeTabs'; +import { CanvasState, isCanvasMaskLine } from 'features/canvas/canvasSlice'; +import generateMask from 'features/canvas/util/generateMask'; +import { canvasImageLayerRef } from 'features/canvas/IAICanvas'; +import openBase64ImageInTab from './openBase64ImageInTab'; export type FrontendToBackendParametersConfig = { generationMode: InvokeTabName; optionsState: OptionsState; - inpaintingState: InpaintingState; + canvasState: CanvasState; systemState: SystemState; imageToProcessUrl?: string; - maskImageElement?: HTMLImageElement; }; /** @@ -27,10 +28,9 @@ export const frontendToBackendParameters = ( const { generationMode, optionsState, - inpaintingState, + canvasState, systemState, imageToProcessUrl, - maskImageElement, } = config; const { @@ -62,8 +62,11 @@ export const frontendToBackendParameters = ( shouldRandomizeSeed, } = optionsState; - const { shouldDisplayInProgressType, saveIntermediatesInterval } = - systemState; + const { + shouldDisplayInProgressType, + saveIntermediatesInterval, + enableImageDebugging, + } = systemState; const generationParameters: { [k: string]: any } = { prompt, @@ -80,6 +83,8 @@ export const frontendToBackendParameters = ( progress_images: shouldDisplayInProgressType === 'full-res', progress_latents: shouldDisplayInProgressType === 'latents', save_intermediates: saveIntermediatesInterval, + generation_mode: generationMode, + init_mask: '', }; generationParameters.seed = shouldRandomizeSeed @@ -101,35 +106,36 @@ export const frontendToBackendParameters = ( } // inpainting exclusive parameters - if (generationMode === 'inpainting' && maskImageElement) { + if ( + ['inpainting', 'outpainting'].includes(generationMode) && + canvasImageLayerRef.current + ) { const { - lines, - boundingBoxCoordinate, + objects, + boundingBoxCoordinates, boundingBoxDimensions, inpaintReplace, shouldUseInpaintReplace, - } = inpaintingState; + stageScale, + isMaskEnabled, + } = canvasState[canvasState.currentCanvas]; const boundingBox = { - ...boundingBoxCoordinate, + ...boundingBoxCoordinates, ...boundingBoxDimensions, }; - generationParameters.init_img = imageToProcessUrl; - generationParameters.strength = img2imgStrength; - generationParameters.fit = false; - - const { maskDataURL, isMaskEmpty } = generateMask( - maskImageElement, - lines, + const maskDataURL = generateMask( + isMaskEnabled ? objects.filter(isCanvasMaskLine) : [], boundingBox ); - generationParameters.is_mask_empty = isMaskEmpty; + generationParameters.init_mask = maskDataURL; - generationParameters.init_mask = maskDataURL.split( - 'data:image/png;base64,' - )[1]; + generationParameters.fit = false; + + generationParameters.init_img = imageToProcessUrl; + generationParameters.strength = img2imgStrength; if (shouldUseInpaintReplace) { generationParameters.inpaint_replace = inpaintReplace; @@ -137,8 +143,44 @@ export const frontendToBackendParameters = ( generationParameters.bounding_box = boundingBox; - // TODO: The server metadata generation needs to be changed to fix this. - generationParameters.progress_images = false; + if (generationMode === 'outpainting') { + const tempScale = canvasImageLayerRef.current.scale(); + + canvasImageLayerRef.current.scale({ + x: 1 / stageScale, + y: 1 / stageScale, + }); + + const absPos = canvasImageLayerRef.current.getAbsolutePosition(); + + const imageDataURL = canvasImageLayerRef.current.toDataURL({ + x: boundingBox.x + absPos.x, + y: boundingBox.y + absPos.y, + width: boundingBox.width, + height: boundingBox.height, + }); + + if (enableImageDebugging) { + openBase64ImageInTab([ + { base64: maskDataURL, caption: 'mask sent as init_mask' }, + { base64: imageDataURL, caption: 'image sent as init_img' }, + ]); + } + + canvasImageLayerRef.current.scale(tempScale); + + generationParameters.init_img = imageDataURL; + + // TODO: The server metadata generation needs to be changed to fix this. + generationParameters.progress_images = false; + + generationParameters.seam_size = 96; + generationParameters.seam_blur = 16; + generationParameters.seam_strength = 0.7; + generationParameters.seam_steps = 10; + generationParameters.tile_size = 32; + generationParameters.force_outpaint = false; + } } if (shouldGenerateVariations) { @@ -171,6 +213,10 @@ export const frontendToBackendParameters = ( } } + if (enableImageDebugging) { + generationParameters.enable_image_debugging = enableImageDebugging; + } + return { generationParameters, esrganParameters, diff --git a/frontend/src/common/util/promptToString.ts b/frontend/src/common/util/promptToString.ts index d84a24acf8..ef1e7796e6 100644 --- a/frontend/src/common/util/promptToString.ts +++ b/frontend/src/common/util/promptToString.ts @@ -1,4 +1,4 @@ -import * as InvokeAI from '../../app/invokeai'; +import * as InvokeAI from 'app/invokeai'; const promptToString = (prompt: InvokeAI.Prompt): string => { if (prompt.length === 1) { diff --git a/frontend/src/common/util/seedWeightPairs.ts b/frontend/src/common/util/seedWeightPairs.ts index 9c024e1e1a..ec64b2742d 100644 --- a/frontend/src/common/util/seedWeightPairs.ts +++ b/frontend/src/common/util/seedWeightPairs.ts @@ -1,4 +1,4 @@ -import * as InvokeAI from '../../app/invokeai'; +import * as InvokeAI from 'app/invokeai'; export const stringToSeedWeights = ( string: string diff --git a/frontend/src/features/canvas/IAICanvas.tsx b/frontend/src/features/canvas/IAICanvas.tsx new file mode 100644 index 0000000000..23ebd40925 --- /dev/null +++ b/frontend/src/features/canvas/IAICanvas.tsx @@ -0,0 +1,275 @@ +// lib +import { MutableRefObject, useEffect, useRef, useState } from 'react'; +import Konva from 'konva'; +import { Layer, Stage } from 'react-konva'; +import { Image as KonvaImage } from 'react-konva'; +import { Stage as StageType } from 'konva/lib/Stage'; + +// app +import { useAppDispatch, useAppSelector } from 'app/store'; +import { + baseCanvasImageSelector, + clearImageToInpaint, + currentCanvasSelector, + outpaintingCanvasSelector, +} from 'features/canvas/canvasSlice'; + +// component +import IAICanvasMaskLines from './IAICanvasMaskLines'; +import IAICanvasBrushPreview from './IAICanvasBrushPreview'; +import { Vector2d } from 'konva/lib/types'; +import IAICanvasBoundingBoxPreview from './IAICanvasBoundingBoxPreview'; +import { useToast } from '@chakra-ui/react'; +import useCanvasHotkeys from './hooks/useCanvasHotkeys'; +import _ from 'lodash'; +import { createSelector } from '@reduxjs/toolkit'; +import { activeTabNameSelector } from 'features/options/optionsSelectors'; +import IAICanvasMaskCompositer from './IAICanvasMaskCompositer'; +import useCanvasWheel from './hooks/useCanvasZoom'; +import useCanvasMouseDown from './hooks/useCanvasMouseDown'; +import useCanvasMouseUp from './hooks/useCanvasMouseUp'; +import useCanvasMouseMove from './hooks/useCanvasMouseMove'; +import useCanvasMouseEnter from './hooks/useCanvasMouseEnter'; +import useCanvasMouseOut from './hooks/useCanvasMouseOut'; +import useCanvasDragMove from './hooks/useCanvasDragMove'; +import IAICanvasOutpaintingObjects from './IAICanvasOutpaintingObjects'; +import IAICanvasGrid from './IAICanvasGrid'; +import IAICanvasIntermediateImage from './IAICanvasIntermediateImage'; +import IAICanvasStatusText from './IAICanvasStatusText'; + +const canvasSelector = createSelector( + [ + currentCanvasSelector, + outpaintingCanvasSelector, + baseCanvasImageSelector, + activeTabNameSelector, + ], + (currentCanvas, outpaintingCanvas, baseCanvasImage, activeTabName) => { + const { + shouldInvertMask, + isMaskEnabled, + shouldShowCheckboardTransparency, + stageScale, + shouldShowBoundingBox, + shouldLockBoundingBox, + isTransformingBoundingBox, + isMouseOverBoundingBox, + isMovingBoundingBox, + stageDimensions, + stageCoordinates, + isMoveStageKeyHeld, + tool, + isMovingStage, + } = currentCanvas; + + const { shouldShowGrid } = outpaintingCanvas; + + let stageCursor: string | undefined = ''; + + if (tool === 'move') { + if (isTransformingBoundingBox) { + stageCursor = undefined; + } else if (isMouseOverBoundingBox) { + stageCursor = 'move'; + } else { + if (isMovingStage) { + stageCursor = 'grabbing'; + } else { + stageCursor = 'grab'; + } + } + } else { + stageCursor = 'none'; + } + + return { + shouldInvertMask, + isMaskEnabled, + shouldShowCheckboardTransparency, + stageScale, + shouldShowBoundingBox, + shouldLockBoundingBox, + shouldShowGrid, + isTransformingBoundingBox, + isModifyingBoundingBox: isTransformingBoundingBox || isMovingBoundingBox, + stageCursor, + isMouseOverBoundingBox, + stageDimensions, + stageCoordinates, + isMoveStageKeyHeld, + activeTabName, + baseCanvasImage, + tool, + }; + }, + { + memoizeOptions: { + resultEqualityCheck: _.isEqual, + }, + } +); + +// Use a closure allow other components to use these things... not ideal... +export let stageRef: MutableRefObject; +export let canvasImageLayerRef: MutableRefObject; +export let inpaintingImageElementRef: MutableRefObject; + +const IAICanvas = () => { + const dispatch = useAppDispatch(); + + const { + shouldInvertMask, + isMaskEnabled, + shouldShowCheckboardTransparency, + stageScale, + shouldShowBoundingBox, + isModifyingBoundingBox, + stageCursor, + stageDimensions, + stageCoordinates, + shouldShowGrid, + activeTabName, + baseCanvasImage, + tool, + } = useAppSelector(canvasSelector); + + useCanvasHotkeys(); + + const toast = useToast(); + // set the closure'd refs + stageRef = useRef(null); + canvasImageLayerRef = useRef(null); + inpaintingImageElementRef = useRef(null); + + const lastCursorPositionRef = useRef({ x: 0, y: 0 }); + + // Use refs for values that do not affect rendering, other values in redux + const didMouseMoveRef = useRef(false); + + // Load the image into this + const [canvasBgImage, setCanvasBgImage] = useState( + null + ); + + const handleWheel = useCanvasWheel(stageRef); + const handleMouseDown = useCanvasMouseDown(stageRef); + const handleMouseUp = useCanvasMouseUp(stageRef, didMouseMoveRef); + const handleMouseMove = useCanvasMouseMove( + stageRef, + didMouseMoveRef, + lastCursorPositionRef + ); + const handleMouseEnter = useCanvasMouseEnter(stageRef); + const handleMouseOut = useCanvasMouseOut(); + const { handleDragStart, handleDragMove, handleDragEnd } = + useCanvasDragMove(); + + // Load the image and set the options panel width & height + useEffect(() => { + if (baseCanvasImage) { + const image = new Image(); + image.onload = () => { + inpaintingImageElementRef.current = image; + setCanvasBgImage(image); + }; + image.onerror = () => { + toast({ + title: 'Unable to Load Image', + description: `Image ${baseCanvasImage.url} failed to load`, + status: 'error', + isClosable: true, + }); + dispatch(clearImageToInpaint()); + }; + image.src = baseCanvasImage.url; + } else { + setCanvasBgImage(null); + } + }, [baseCanvasImage, dispatch, stageScale, toast]); + + return ( +
+
+ + + + + + + + + + + + + + + {canvasBgImage && ( + <> + + + + + )} + + + + + + + +
+
+ ); +}; + +export default IAICanvas; diff --git a/frontend/src/features/tabs/Inpainting/components/InpaintingBoundingBoxPreview.tsx b/frontend/src/features/canvas/IAICanvasBoundingBoxPreview.tsx similarity index 62% rename from frontend/src/features/tabs/Inpainting/components/InpaintingBoundingBoxPreview.tsx rename to frontend/src/features/canvas/IAICanvasBoundingBoxPreview.tsx index df0d09ed65..94ba2e72a2 100644 --- a/frontend/src/features/tabs/Inpainting/components/InpaintingBoundingBoxPreview.tsx +++ b/frontend/src/features/canvas/IAICanvasBoundingBoxPreview.tsx @@ -7,58 +7,60 @@ import { Vector2d } from 'konva/lib/types'; import _ from 'lodash'; import { useCallback, useEffect, useRef } from 'react'; import { Group, Rect, Transformer } from 'react-konva'; +import { useAppDispatch, useAppSelector } from 'app/store'; +import { roundToMultiple } from 'common/util/roundDownToMultiple'; import { - RootState, - useAppDispatch, - useAppSelector, -} from '../../../../app/store'; -import { roundToMultiple } from '../../../../common/util/roundDownToMultiple'; -import { - InpaintingState, - setBoundingBoxCoordinate, + baseCanvasImageSelector, + currentCanvasSelector, + outpaintingCanvasSelector, + setBoundingBoxCoordinates, setBoundingBoxDimensions, setIsMouseOverBoundingBox, setIsMovingBoundingBox, setIsTransformingBoundingBox, -} from '../inpaintingSlice'; -import { rgbaColorToString } from '../util/colorToString'; -import { - DASH_WIDTH, - // MARCHING_ANTS_SPEED, -} from '../util/constants'; +} from 'features/canvas/canvasSlice'; +import { GroupConfig } from 'konva/lib/Group'; +import { activeTabNameSelector } from 'features/options/optionsSelectors'; const boundingBoxPreviewSelector = createSelector( - (state: RootState) => state.inpainting, - (inpainting: InpaintingState) => { + currentCanvasSelector, + outpaintingCanvasSelector, + baseCanvasImageSelector, + activeTabNameSelector, + (currentCanvas, outpaintingCanvas, baseCanvasImage, activeTabName) => { const { - boundingBoxCoordinate, + boundingBoxCoordinates, boundingBoxDimensions, - boundingBoxPreviewFill, - canvasDimensions, + stageDimensions, stageScale, - imageToInpaint, shouldLockBoundingBox, isDrawing, isTransformingBoundingBox, isMovingBoundingBox, isMouseOverBoundingBox, - isSpacebarHeld, - } = inpainting; + shouldDarkenOutsideBoundingBox, + tool, + stageCoordinates, + } = currentCanvas; + const { shouldSnapToGrid } = outpaintingCanvas; + return { - boundingBoxCoordinate, + boundingBoxCoordinates, boundingBoxDimensions, - boundingBoxPreviewFillString: rgbaColorToString(boundingBoxPreviewFill), - canvasDimensions, - stageScale, - imageToInpaint, - dash: DASH_WIDTH / stageScale, // scale dash lengths - strokeWidth: 1 / stageScale, // scale stroke thickness - shouldLockBoundingBox, isDrawing, - isTransformingBoundingBox, isMouseOverBoundingBox, + shouldDarkenOutsideBoundingBox, isMovingBoundingBox, - isSpacebarHeld, + isTransformingBoundingBox, + shouldLockBoundingBox, + stageDimensions, + stageScale, + baseCanvasImage, + activeTabName, + shouldSnapToGrid, + tool, + stageCoordinates, + boundingBoxStrokeWidth: (isMouseOverBoundingBox ? 8 : 1) / stageScale, }; }, { @@ -68,52 +70,31 @@ const boundingBoxPreviewSelector = createSelector( } ); -/** - * Shades the area around the mask. - */ -export const InpaintingBoundingBoxPreviewOverlay = () => { - const { - boundingBoxCoordinate, - boundingBoxDimensions, - boundingBoxPreviewFillString, - canvasDimensions, - } = useAppSelector(boundingBoxPreviewSelector); +type IAICanvasBoundingBoxPreviewProps = GroupConfig; - return ( - - - - - ); -}; +const IAICanvasBoundingBoxPreview = ( + props: IAICanvasBoundingBoxPreviewProps +) => { + const { ...rest } = props; -const InpaintingBoundingBoxPreview = () => { const dispatch = useAppDispatch(); const { - boundingBoxCoordinate, + boundingBoxCoordinates, boundingBoxDimensions, - stageScale, - imageToInpaint, - shouldLockBoundingBox, isDrawing, - isTransformingBoundingBox, - isMovingBoundingBox, isMouseOverBoundingBox, - isSpacebarHeld, + shouldDarkenOutsideBoundingBox, + isMovingBoundingBox, + isTransformingBoundingBox, + shouldLockBoundingBox, + stageCoordinates, + stageDimensions, + stageScale, + baseCanvasImage, + activeTabName, + shouldSnapToGrid, + tool, + boundingBoxStrokeWidth, } = useAppSelector(boundingBoxPreviewSelector); const transformerRef = useRef(null); @@ -129,31 +110,60 @@ const InpaintingBoundingBoxPreview = () => { const handleOnDragMove = useCallback( (e: KonvaEventObject) => { + if (activeTabName === 'inpainting' || !shouldSnapToGrid) { + dispatch( + setBoundingBoxCoordinates({ + x: e.target.x(), + y: e.target.y(), + }) + ); + return; + } + + const dragX = e.target.x(); + const dragY = e.target.y(); + + const newX = roundToMultiple(dragX, 64); + const newY = roundToMultiple(dragY, 64); + + e.target.x(newX); + e.target.y(newY); + dispatch( - setBoundingBoxCoordinate({ - x: Math.floor(e.target.x()), - y: Math.floor(e.target.y()), + setBoundingBoxCoordinates({ + x: newX, + y: newY, }) ); }, - [dispatch] + [activeTabName, dispatch, shouldSnapToGrid] ); const dragBoundFunc = useCallback( (position: Vector2d) => { - if (!imageToInpaint) return boundingBoxCoordinate; + if (!baseCanvasImage) return boundingBoxCoordinates; const { x, y } = position; - const maxX = imageToInpaint.width - boundingBoxDimensions.width; - const maxY = imageToInpaint.height - boundingBoxDimensions.height; + const maxX = + stageDimensions.width - boundingBoxDimensions.width * stageScale; + const maxY = + stageDimensions.height - boundingBoxDimensions.height * stageScale; - const clampedX = Math.floor(_.clamp(x, 0, maxX * stageScale)); - const clampedY = Math.floor(_.clamp(y, 0, maxY * stageScale)); + const clampedX = Math.floor(_.clamp(x, 0, maxX)); + const clampedY = Math.floor(_.clamp(y, 0, maxY)); return { x: clampedX, y: clampedY }; }, - [boundingBoxCoordinate, boundingBoxDimensions, imageToInpaint, stageScale] + [ + baseCanvasImage, + boundingBoxCoordinates, + stageDimensions.width, + stageDimensions.height, + boundingBoxDimensions.width, + boundingBoxDimensions.height, + stageScale, + ] ); const handleOnTransform = useCallback(() => { @@ -184,7 +194,7 @@ const InpaintingBoundingBoxPreview = () => { ); dispatch( - setBoundingBoxCoordinate({ + setBoundingBoxCoordinates({ x, y, }) @@ -195,6 +205,7 @@ const InpaintingBoundingBoxPreview = () => { rect.scaleY(1); }, [dispatch]); + // OK const anchorDragBoundFunc = useCallback( ( oldPos: Vector2d, // old absolute position of anchor point @@ -253,6 +264,7 @@ const InpaintingBoundingBoxPreview = () => { [scaledStep] ); + // OK const boundBoxFunc = useCallback( (oldBoundBox: Box, newBoundBox: Box) => { /** @@ -260,12 +272,10 @@ const InpaintingBoundingBoxPreview = () => { * Unlike anchorDragBoundFunc, it does get a width and height, so * the logic to constrain the size of the bounding box is very simple. */ - if (!imageToInpaint) return oldBoundBox; - + if (!baseCanvasImage) return oldBoundBox; if ( - newBoundBox.width + newBoundBox.x > imageToInpaint.width * stageScale || - newBoundBox.height + newBoundBox.y > - imageToInpaint.height * stageScale || + newBoundBox.width + newBoundBox.x > stageDimensions.width || + newBoundBox.height + newBoundBox.y > stageDimensions.height || newBoundBox.x < 0 || newBoundBox.y < 0 ) { @@ -274,101 +284,107 @@ const InpaintingBoundingBoxPreview = () => { return newBoundBox; }, - [imageToInpaint, stageScale] + [baseCanvasImage, stageDimensions] ); - const handleStartedTransforming = (e: KonvaEventObject) => { - e.cancelBubble = true; - e.evt.stopImmediatePropagation(); - console.log("Started transform") + const handleStartedTransforming = () => { dispatch(setIsTransformingBoundingBox(true)); }; - const handleEndedTransforming = (e: KonvaEventObject) => { + const handleEndedTransforming = () => { dispatch(setIsTransformingBoundingBox(false)); dispatch(setIsMouseOverBoundingBox(false)); }; - const handleStartedMoving = (e: KonvaEventObject) => { - e.cancelBubble = true; - e.evt.stopImmediatePropagation(); + const handleStartedMoving = () => { dispatch(setIsMovingBoundingBox(true)); }; - const handleEndedModifying = (e: KonvaEventObject) => { + const handleEndedModifying = () => { dispatch(setIsTransformingBoundingBox(false)); dispatch(setIsMovingBoundingBox(false)); dispatch(setIsMouseOverBoundingBox(false)); }; - const spacebarHeldHitFunc = (context: Context, shape: Konva.Shape) => { - context.rect(0, 0, imageToInpaint?.width, imageToInpaint?.height); - context.fillShape(shape); + const handleMouseOver = () => { + dispatch(setIsMouseOverBoundingBox(true)); + }; + + const handleMouseOut = () => { + !isTransformingBoundingBox && + !isMovingBoundingBox && + dispatch(setIsMouseOverBoundingBox(false)); }; return ( - <> + + { - dispatch(setIsMouseOverBoundingBox(true)); - }} - onMouseOut={() => { - !isTransformingBoundingBox && - !isMovingBoundingBox && - dispatch(setIsMouseOverBoundingBox(false)); - }} - onMouseDown={handleStartedMoving} - onMouseUp={handleEndedModifying} + fill={'rgb(255,255,255)'} + listening={false} + visible={shouldDarkenOutsideBoundingBox} + globalCompositeOperation={'destination-out'} + /> + { - dispatch(setIsMouseOverBoundingBox(true)); - }} - onMouseOut={() => { - !isTransformingBoundingBox && - !isMovingBoundingBox && - dispatch(setIsMouseOverBoundingBox(false)); - }} + ref={transformerRef} + rotateEnabled={false} /> - + ); }; -export default InpaintingBoundingBoxPreview; +export default IAICanvasBoundingBoxPreview; diff --git a/frontend/src/features/canvas/IAICanvasBrushButtonPopover.tsx b/frontend/src/features/canvas/IAICanvasBrushButtonPopover.tsx new file mode 100644 index 0000000000..c1b77a0edb --- /dev/null +++ b/frontend/src/features/canvas/IAICanvasBrushButtonPopover.tsx @@ -0,0 +1,95 @@ +import { createSelector } from '@reduxjs/toolkit'; +import { + currentCanvasSelector, + outpaintingCanvasSelector, + setBrushColor, + setBrushSize, + setTool, +} from './canvasSlice'; +import { useAppDispatch, useAppSelector } from 'app/store'; +import { activeTabNameSelector } from 'features/options/optionsSelectors'; +import _ from 'lodash'; +import IAIIconButton from 'common/components/IAIIconButton'; +import { FaPaintBrush } from 'react-icons/fa'; +import IAIPopover from 'common/components/IAIPopover'; +import IAIColorPicker from 'common/components/IAIColorPicker'; +import IAISlider from 'common/components/IAISlider'; +import { Flex } from '@chakra-ui/react'; +import IAINumberInput from 'common/components/IAINumberInput'; + +export const selector = createSelector( + [currentCanvasSelector, outpaintingCanvasSelector, activeTabNameSelector], + (currentCanvas, outpaintingCanvas, activeTabName) => { + const { + layer, + maskColor, + brushColor, + brushSize, + eraserSize, + tool, + shouldDarkenOutsideBoundingBox, + shouldShowIntermediates, + } = currentCanvas; + + const { shouldShowGrid, shouldSnapToGrid, shouldAutoSave } = + outpaintingCanvas; + + return { + layer, + tool, + maskColor, + brushColor, + brushSize, + eraserSize, + activeTabName, + shouldShowGrid, + shouldSnapToGrid, + shouldAutoSave, + shouldDarkenOutsideBoundingBox, + shouldShowIntermediates, + }; + }, + { + memoizeOptions: { + resultEqualityCheck: _.isEqual, + }, + } +); + +const IAICanvasBrushButtonPopover = () => { + const dispatch = useAppDispatch(); + const { tool, brushColor, brushSize } = useAppSelector(selector); + + return ( + } + data-selected={tool === 'brush'} + onClick={() => dispatch(setTool('brush'))} + /> + } + > + + + dispatch(setBrushSize(newSize))} + /> + + dispatch(setBrushColor(newColor))} + /> + + + ); +}; + +export default IAICanvasBrushButtonPopover; diff --git a/frontend/src/features/canvas/IAICanvasBrushPreview.tsx b/frontend/src/features/canvas/IAICanvasBrushPreview.tsx new file mode 100644 index 0000000000..f2656f30c1 --- /dev/null +++ b/frontend/src/features/canvas/IAICanvasBrushPreview.tsx @@ -0,0 +1,121 @@ +import { createSelector } from '@reduxjs/toolkit'; +import { GroupConfig } from 'konva/lib/Group'; +import _ from 'lodash'; +import { Circle, Group } from 'react-konva'; +import { useAppSelector } from 'app/store'; +import { currentCanvasSelector } from 'features/canvas/canvasSlice'; +import { rgbaColorToString } from './util/colorToString'; + +const canvasBrushPreviewSelector = createSelector( + currentCanvasSelector, + (currentCanvas) => { + const { + cursorPosition, + stageDimensions: { width, height }, + brushSize, + eraserSize, + maskColor, + brushColor, + tool, + layer, + shouldShowBrush, + isMovingBoundingBox, + isTransformingBoundingBox, + stageScale, + } = currentCanvas; + + return { + cursorPosition, + width, + height, + radius: tool === 'brush' ? brushSize / 2 : eraserSize / 2, + brushColorString: rgbaColorToString( + layer === 'mask' ? maskColor : brushColor + ), + tool, + shouldShowBrush, + shouldDrawBrushPreview: + !( + isMovingBoundingBox || + isTransformingBoundingBox || + !cursorPosition + ) && shouldShowBrush, + strokeWidth: 1.5 / stageScale, + dotRadius: 1.5 / stageScale, + }; + }, + { + memoizeOptions: { + resultEqualityCheck: _.isEqual, + }, + } +); + +/** + * Draws a black circle around the canvas brush preview. + */ +const IAICanvasBrushPreview = (props: GroupConfig) => { + const { ...rest } = props; + const { + cursorPosition, + width, + height, + radius, + brushColorString, + tool, + shouldDrawBrushPreview, + dotRadius, + strokeWidth, + } = useAppSelector(canvasBrushPreviewSelector); + + if (!shouldDrawBrushPreview) return null; + + return ( + + + + + + + + ); +}; + +export default IAICanvasBrushPreview; diff --git a/frontend/src/features/canvas/IAICanvasControls.tsx b/frontend/src/features/canvas/IAICanvasControls.tsx new file mode 100644 index 0000000000..07e0c8d17c --- /dev/null +++ b/frontend/src/features/canvas/IAICanvasControls.tsx @@ -0,0 +1,100 @@ +import IAICanvasBrushControl from './IAICanvasControls/IAICanvasBrushControl'; +import IAICanvasEraserControl from './IAICanvasControls/IAICanvasEraserControl'; +import IAICanvasUndoControl from './IAICanvasControls/IAICanvasUndoButton'; +import IAICanvasRedoControl from './IAICanvasControls/IAICanvasRedoButton'; +import { Button, ButtonGroup } from '@chakra-ui/react'; +import IAICanvasMaskClear from './IAICanvasControls/IAICanvasMaskControls/IAICanvasMaskClear'; +import IAICanvasMaskVisibilityControl from './IAICanvasControls/IAICanvasMaskControls/IAICanvasMaskVisibilityControl'; +import IAICanvasMaskInvertControl from './IAICanvasControls/IAICanvasMaskControls/IAICanvasMaskInvertControl'; +import IAICanvasLockBoundingBoxControl from './IAICanvasControls/IAICanvasLockBoundingBoxControl'; +import IAICanvasShowHideBoundingBoxControl from './IAICanvasControls/IAICanvasShowHideBoundingBoxControl'; +import ImageUploaderIconButton from 'common/components/ImageUploaderIconButton'; +import { createSelector } from '@reduxjs/toolkit'; +import { + currentCanvasSelector, + GenericCanvasState, + outpaintingCanvasSelector, + OutpaintingCanvasState, + uploadOutpaintingMergedImage, +} from './canvasSlice'; +import { RootState, useAppDispatch, useAppSelector } from 'app/store'; +import { activeTabNameSelector } from 'features/options/optionsSelectors'; +import { OptionsState } from 'features/options/optionsSlice'; +import _ from 'lodash'; +import IAICanvasImageEraserControl from './IAICanvasControls/IAICanvasImageEraserControl'; +import { canvasImageLayerRef } from './IAICanvas'; +import { uploadImage } from 'app/socketio/actions'; +import IAIIconButton from 'common/components/IAIIconButton'; +import { FaSave } from 'react-icons/fa'; + +export const canvasControlsSelector = createSelector( + [ + outpaintingCanvasSelector, + (state: RootState) => state.options, + activeTabNameSelector, + ], + ( + outpaintingCanvas: OutpaintingCanvasState, + options: OptionsState, + activeTabName + ) => { + const { stageScale, boundingBoxCoordinates, boundingBoxDimensions } = + outpaintingCanvas; + return { + activeTabName, + stageScale, + boundingBoxCoordinates, + boundingBoxDimensions, + }; + }, + { + memoizeOptions: { + resultEqualityCheck: _.isEqual, + }, + } +); + +const IAICanvasControls = () => { + const dispatch = useAppDispatch(); + const { + activeTabName, + boundingBoxCoordinates, + boundingBoxDimensions, + stageScale, + } = useAppSelector(canvasControlsSelector); + + return ( +
+ + + + {activeTabName === 'outpainting' && } + + + + + + + + + } + onClick={() => { + dispatch(uploadOutpaintingMergedImage(canvasImageLayerRef)); + }} + fontSize={20} + /> + + + + + + + +
+ ); +}; + +export default IAICanvasControls; diff --git a/frontend/src/features/tabs/Inpainting/InpaintingControls/InpaintingBrushControl.tsx b/frontend/src/features/canvas/IAICanvasControls/IAICanvasBrushControl.tsx similarity index 60% rename from frontend/src/features/tabs/Inpainting/InpaintingControls/InpaintingBrushControl.tsx rename to frontend/src/features/canvas/IAICanvasControls/IAICanvasBrushControl.tsx index 995c6a3b1f..3d3f9ee9f1 100644 --- a/frontend/src/features/tabs/Inpainting/InpaintingControls/InpaintingBrushControl.tsx +++ b/frontend/src/features/canvas/IAICanvasControls/IAICanvasBrushControl.tsx @@ -1,37 +1,31 @@ import { createSelector } from '@reduxjs/toolkit'; -import React from 'react'; import { useHotkeys } from 'react-hotkeys-hook'; import { FaPaintBrush } from 'react-icons/fa'; -import { - RootState, - useAppDispatch, - useAppSelector, -} from '../../../../app/store'; -import IAIIconButton from '../../../../common/components/IAIIconButton'; -import IAINumberInput from '../../../../common/components/IAINumberInput'; -import IAIPopover from '../../../../common/components/IAIPopover'; -import IAISlider from '../../../../common/components/IAISlider'; -import { activeTabNameSelector } from '../../../options/optionsSelectors'; +import { useAppDispatch, useAppSelector } from 'app/store'; +import IAIIconButton from 'common/components/IAIIconButton'; +import IAINumberInput from 'common/components/IAINumberInput'; +import IAIPopover from 'common/components/IAIPopover'; +import IAISlider from 'common/components/IAISlider'; +import { activeTabNameSelector } from 'features/options/optionsSelectors'; import { - InpaintingState, + currentCanvasSelector, setBrushSize, setShouldShowBrushPreview, setTool, -} from '../inpaintingSlice'; +} from 'features/canvas/canvasSlice'; import _ from 'lodash'; -import InpaintingMaskColorPicker from './InpaintingMaskControls/InpaintingMaskColorPicker'; +import IAICanvasMaskColorPicker from './IAICanvasMaskControls/IAICanvasMaskColorPicker'; const inpaintingBrushSelector = createSelector( - [(state: RootState) => state.inpainting, activeTabNameSelector], - (inpainting: InpaintingState, activeTabName) => { - const { tool, brushSize, shouldShowMask } = inpainting; + [currentCanvasSelector, activeTabNameSelector], + (currentCanvas, activeTabName) => { + const { tool, brushSize } = currentCanvas; return { tool, brushSize, - shouldShowMask, activeTabName, }; }, @@ -42,9 +36,9 @@ const inpaintingBrushSelector = createSelector( } ); -export default function InpaintingBrushControl() { +export default function IAICanvasBrushControl() { const dispatch = useAppDispatch(); - const { tool, brushSize, shouldShowMask, activeTabName } = useAppSelector( + const { tool, brushSize, activeTabName } = useAppSelector( inpaintingBrushSelector ); @@ -63,9 +57,6 @@ export default function InpaintingBrushControl() { dispatch(setBrushSize(v)); }; - // Hotkeys - - // Decrease brush size useHotkeys( '[', (e: KeyboardEvent) => { @@ -77,9 +68,9 @@ export default function InpaintingBrushControl() { } }, { - enabled: activeTabName === 'inpainting' && shouldShowMask, + enabled: true, }, - [activeTabName, shouldShowMask, brushSize] + [activeTabName, brushSize] ); // Increase brush size @@ -90,9 +81,9 @@ export default function InpaintingBrushControl() { handleChangeBrushSize(brushSize + 5); }, { - enabled: activeTabName === 'inpainting' && shouldShowMask, + enabled: true, }, - [activeTabName, shouldShowMask, brushSize] + [activeTabName, brushSize] ); // Set tool to brush @@ -103,9 +94,9 @@ export default function InpaintingBrushControl() { handleSelectBrushTool(); }, { - enabled: activeTabName === 'inpainting' && shouldShowMask, + enabled: true, }, - [activeTabName, shouldShowMask] + [activeTabName] ); return ( @@ -120,7 +111,6 @@ export default function InpaintingBrushControl() { icon={} onClick={handleSelectBrushTool} data-selected={tool === 'brush'} - isDisabled={!shouldShowMask} /> } > @@ -131,9 +121,6 @@ export default function InpaintingBrushControl() { onChange={handleChangeBrushSize} min={1} max={200} - width="100px" - focusThumbOnChange={false} - isDisabled={!shouldShowMask} /> - +
); diff --git a/frontend/src/features/tabs/Inpainting/InpaintingControls/InpaintingClearImageControl.tsx b/frontend/src/features/canvas/IAICanvasControls/IAICanvasClearImageControl.tsx similarity index 55% rename from frontend/src/features/tabs/Inpainting/InpaintingControls/InpaintingClearImageControl.tsx rename to frontend/src/features/canvas/IAICanvasControls/IAICanvasClearImageControl.tsx index 224a87a6dc..af04cc35f7 100644 --- a/frontend/src/features/tabs/Inpainting/InpaintingControls/InpaintingClearImageControl.tsx +++ b/frontend/src/features/canvas/IAICanvasControls/IAICanvasClearImageControl.tsx @@ -1,10 +1,9 @@ -import React from 'react'; import { FaTrash } from 'react-icons/fa'; -import { useAppDispatch } from '../../../../app/store'; -import IAIIconButton from '../../../../common/components/IAIIconButton'; -import { clearImageToInpaint } from '../inpaintingSlice'; +import { useAppDispatch } from 'app/store'; +import IAIIconButton from 'common/components/IAIIconButton'; +import { clearImageToInpaint } from 'features/canvas/canvasSlice'; -export default function InpaintingClearImageControl() { +export default function IAICanvasClearImageControl() { const dispatch = useAppDispatch(); const handleClearImage = () => { diff --git a/frontend/src/features/canvas/IAICanvasControls/IAICanvasEraserControl.tsx b/frontend/src/features/canvas/IAICanvasControls/IAICanvasEraserControl.tsx new file mode 100644 index 0000000000..815709c1b4 --- /dev/null +++ b/frontend/src/features/canvas/IAICanvasControls/IAICanvasEraserControl.tsx @@ -0,0 +1,61 @@ +import { createSelector } from '@reduxjs/toolkit'; +import { useHotkeys } from 'react-hotkeys-hook'; +import { FaEraser } from 'react-icons/fa'; +import { useAppDispatch, useAppSelector } from 'app/store'; +import IAIIconButton from 'common/components/IAIIconButton'; +import { currentCanvasSelector, setTool } from 'features/canvas/canvasSlice'; + +import _ from 'lodash'; +import { activeTabNameSelector } from 'features/options/optionsSelectors'; + +const eraserSelector = createSelector( + [currentCanvasSelector, activeTabNameSelector], + (currentCanvas, activeTabName) => { + const { tool, isMaskEnabled } = currentCanvas; + + return { + tool, + isMaskEnabled, + activeTabName, + }; + }, + { + memoizeOptions: { + resultEqualityCheck: _.isEqual, + }, + } +); + +export default function IAICanvasEraserControl() { + const { tool, isMaskEnabled, activeTabName } = useAppSelector(eraserSelector); + const dispatch = useAppDispatch(); + + const handleSelectEraserTool = () => dispatch(setTool('eraser')); + + // Hotkeys + // Set tool to maskEraser + useHotkeys( + 'e', + (e: KeyboardEvent) => { + e.preventDefault(); + handleSelectEraserTool(); + }, + { + enabled: true, + }, + [activeTabName] + ); + + return ( + } + onClick={handleSelectEraserTool} + data-selected={tool === 'eraser'} + isDisabled={!isMaskEnabled} + /> + ); +} diff --git a/frontend/src/features/canvas/IAICanvasControls/IAICanvasImageEraserControl.tsx b/frontend/src/features/canvas/IAICanvasControls/IAICanvasImageEraserControl.tsx new file mode 100644 index 0000000000..b0047c6b8a --- /dev/null +++ b/frontend/src/features/canvas/IAICanvasControls/IAICanvasImageEraserControl.tsx @@ -0,0 +1,60 @@ +import { createSelector } from '@reduxjs/toolkit'; +import { useHotkeys } from 'react-hotkeys-hook'; +import { useAppDispatch, useAppSelector } from 'app/store'; +import IAIIconButton from 'common/components/IAIIconButton'; +import { currentCanvasSelector, setTool } from 'features/canvas/canvasSlice'; + +import _ from 'lodash'; +import { activeTabNameSelector } from 'features/options/optionsSelectors'; +import { BsEraser } from 'react-icons/bs'; + +const imageEraserSelector = createSelector( + [currentCanvasSelector, activeTabNameSelector], + (currentCanvas, activeTabName) => { + const { tool, isMaskEnabled } = currentCanvas; + + return { + tool, + isMaskEnabled, + activeTabName, + }; + }, + { + memoizeOptions: { + resultEqualityCheck: _.isEqual, + }, + } +); + +export default function IAICanvasImageEraserControl() { + const { tool, isMaskEnabled, activeTabName } = + useAppSelector(imageEraserSelector); + const dispatch = useAppDispatch(); + + const handleSelectEraserTool = () => dispatch(setTool('eraser')); + + // Hotkeys + useHotkeys( + 'shift+e', + (e: KeyboardEvent) => { + e.preventDefault(); + handleSelectEraserTool(); + }, + { + enabled: true, + }, + [activeTabName, isMaskEnabled] + ); + + return ( + } + fontSize={18} + onClick={handleSelectEraserTool} + data-selected={tool === 'eraser'} + isDisabled={!isMaskEnabled} + /> + ); +} diff --git a/frontend/src/features/canvas/IAICanvasControls/IAICanvasLockBoundingBoxControl.tsx b/frontend/src/features/canvas/IAICanvasControls/IAICanvasLockBoundingBoxControl.tsx new file mode 100644 index 0000000000..5779a4a627 --- /dev/null +++ b/frontend/src/features/canvas/IAICanvasControls/IAICanvasLockBoundingBoxControl.tsx @@ -0,0 +1,47 @@ +import { FaLock, FaUnlock } from 'react-icons/fa'; +import { useAppDispatch, useAppSelector } from 'app/store'; +import IAIIconButton from 'common/components/IAIIconButton'; +import { + currentCanvasSelector, + GenericCanvasState, + setShouldLockBoundingBox, +} from 'features/canvas/canvasSlice'; +import { createSelector } from '@reduxjs/toolkit'; +import _ from 'lodash'; + +const canvasLockBoundingBoxSelector = createSelector( + currentCanvasSelector, + (currentCanvas: GenericCanvasState) => { + const { shouldLockBoundingBox } = currentCanvas; + + return { + shouldLockBoundingBox, + }; + }, + { + memoizeOptions: { + resultEqualityCheck: _.isEqual, + }, + } +); + +const IAICanvasLockBoundingBoxControl = () => { + const dispatch = useAppDispatch(); + const { shouldLockBoundingBox } = useAppSelector( + canvasLockBoundingBoxSelector + ); + + return ( + : } + data-selected={shouldLockBoundingBox} + onClick={() => { + dispatch(setShouldLockBoundingBox(!shouldLockBoundingBox)); + }} + /> + ); +}; + +export default IAICanvasLockBoundingBoxControl; diff --git a/frontend/src/features/canvas/IAICanvasControls/IAICanvasMaskControl.tsx b/frontend/src/features/canvas/IAICanvasControls/IAICanvasMaskControl.tsx new file mode 100644 index 0000000000..9d863f9775 --- /dev/null +++ b/frontend/src/features/canvas/IAICanvasControls/IAICanvasMaskControl.tsx @@ -0,0 +1,38 @@ +import { useState } from 'react'; +import { FaMask } from 'react-icons/fa'; + +import IAIPopover from 'common/components/IAIPopover'; +import IAIIconButton from 'common/components/IAIIconButton'; + +import IAICanvasMaskInvertControl from './IAICanvasMaskControls/IAICanvasMaskInvertControl'; +import IAICanvasMaskVisibilityControl from './IAICanvasMaskControls/IAICanvasMaskVisibilityControl'; +import IAICanvasMaskColorPicker from './IAICanvasMaskControls/IAICanvasMaskColorPicker'; + +export default function IAICanvasMaskControl() { + const [maskOptionsOpen, setMaskOptionsOpen] = useState(false); + + return ( + <> + setMaskOptionsOpen(true)} + onClose={() => setMaskOptionsOpen(false)} + triggerComponent={ + } + cursor={'pointer'} + data-selected={maskOptionsOpen} + /> + } + > +
+ + + +
+
+ + ); +} diff --git a/frontend/src/features/canvas/IAICanvasControls/IAICanvasMaskControls/IAICanvasBrushColorPicker.tsx b/frontend/src/features/canvas/IAICanvasControls/IAICanvasMaskControls/IAICanvasBrushColorPicker.tsx new file mode 100644 index 0000000000..15e5ab07b2 --- /dev/null +++ b/frontend/src/features/canvas/IAICanvasControls/IAICanvasMaskControls/IAICanvasBrushColorPicker.tsx @@ -0,0 +1,75 @@ +import { RgbaColor } from 'react-colorful'; +import { useAppDispatch, useAppSelector } from 'app/store'; +import IAIColorPicker from 'common/components/IAIColorPicker'; +import { + currentCanvasSelector, + GenericCanvasState, + setMaskColor, +} from 'features/canvas/canvasSlice'; + +import _ from 'lodash'; +import { createSelector } from '@reduxjs/toolkit'; +import { activeTabNameSelector } from 'features/options/optionsSelectors'; +import { useHotkeys } from 'react-hotkeys-hook'; + +const selector = createSelector( + [currentCanvasSelector, activeTabNameSelector], + (currentCanvas: GenericCanvasState, activeTabName) => { + const { brushColor } = currentCanvas; + + return { + brushColor, + activeTabName, + }; + }, + { + memoizeOptions: { + resultEqualityCheck: _.isEqual, + }, + } +); + +export default function IAICanvasBrushColorPicker() { + const dispatch = useAppDispatch(); + const { brushColor, activeTabName } = useAppSelector(selector); + + const handleChangeBrushColor = (newColor: RgbaColor) => { + dispatch(setMaskColor(newColor)); + }; + + // Decrease brush opacity + useHotkeys( + 'shift+[', + (e: KeyboardEvent) => { + e.preventDefault(); + handleChangeBrushColor({ + ...brushColor, + a: Math.max(brushColor.a - 0.05, 0), + }); + }, + { + enabled: true, + }, + [activeTabName, brushColor.a] + ); + + // Increase brush opacity + useHotkeys( + 'shift+]', + (e: KeyboardEvent) => { + e.preventDefault(); + handleChangeBrushColor({ + ...brushColor, + a: Math.min(brushColor.a + 0.05, 1), + }); + }, + { + enabled: true, + }, + [activeTabName, brushColor.a] + ); + + return ( + + ); +} diff --git a/frontend/src/features/canvas/IAICanvasControls/IAICanvasMaskControls/IAICanvasMaskClear.tsx b/frontend/src/features/canvas/IAICanvasControls/IAICanvasMaskControls/IAICanvasMaskClear.tsx new file mode 100644 index 0000000000..6c0b7c0410 --- /dev/null +++ b/frontend/src/features/canvas/IAICanvasControls/IAICanvasMaskControls/IAICanvasMaskClear.tsx @@ -0,0 +1,77 @@ +import { createSelector } from '@reduxjs/toolkit'; +import { FaPlus } from 'react-icons/fa'; +import { useAppDispatch, useAppSelector } from 'app/store'; +import IAIIconButton from 'common/components/IAIIconButton'; +import { activeTabNameSelector } from 'features/options/optionsSelectors'; +import { + clearMask, + currentCanvasSelector, + InpaintingCanvasState, + isCanvasMaskLine, + OutpaintingCanvasState, +} from 'features/canvas/canvasSlice'; + +import _ from 'lodash'; +import { useHotkeys } from 'react-hotkeys-hook'; +import { useToast } from '@chakra-ui/react'; + +const canvasMaskClearSelector = createSelector( + [currentCanvasSelector, activeTabNameSelector], + (currentCanvas, activeTabName) => { + const { isMaskEnabled, objects } = currentCanvas as + | InpaintingCanvasState + | OutpaintingCanvasState; + + return { + isMaskEnabled, + activeTabName, + isMaskEmpty: objects.filter(isCanvasMaskLine).length === 0, + }; + }, + { + memoizeOptions: { + resultEqualityCheck: _.isEqual, + }, + } +); + +export default function IAICanvasMaskClear() { + const { isMaskEnabled, activeTabName, isMaskEmpty } = useAppSelector( + canvasMaskClearSelector + ); + + const dispatch = useAppDispatch(); + const toast = useToast(); + + const handleClearMask = () => { + dispatch(clearMask()); + }; + + // Clear mask + useHotkeys( + 'shift+c', + (e: KeyboardEvent) => { + e.preventDefault(); + handleClearMask(); + toast({ + title: 'Mask Cleared', + status: 'success', + duration: 2500, + isClosable: true, + }); + }, + { + enabled: !isMaskEmpty, + }, + [activeTabName, isMaskEmpty, isMaskEnabled] + ); + return ( + } + onClick={handleClearMask} + isDisabled={isMaskEmpty || !isMaskEnabled} + /> + ); +} diff --git a/frontend/src/features/tabs/Inpainting/InpaintingControls/InpaintingMaskControls/InpaintingMaskColorPicker.tsx b/frontend/src/features/canvas/IAICanvasControls/IAICanvasMaskControls/IAICanvasMaskColorPicker.tsx similarity index 51% rename from frontend/src/features/tabs/Inpainting/InpaintingControls/InpaintingMaskControls/InpaintingMaskColorPicker.tsx rename to frontend/src/features/canvas/IAICanvasControls/IAICanvasMaskControls/IAICanvasMaskColorPicker.tsx index e3f58b810d..29f63484e2 100644 --- a/frontend/src/features/tabs/Inpainting/InpaintingControls/InpaintingMaskControls/InpaintingMaskColorPicker.tsx +++ b/frontend/src/features/canvas/IAICanvasControls/IAICanvasMaskControls/IAICanvasMaskColorPicker.tsx @@ -1,27 +1,31 @@ import React from 'react'; import { RgbaColor } from 'react-colorful'; import { FaPalette } from 'react-icons/fa'; +import { useAppDispatch, useAppSelector } from 'app/store'; +import IAIColorPicker from 'common/components/IAIColorPicker'; +import IAIIconButton from 'common/components/IAIIconButton'; +import IAIPopover from 'common/components/IAIPopover'; import { - RootState, - useAppDispatch, - useAppSelector, -} from '../../../../../app/store'; -import IAIColorPicker from '../../../../../common/components/IAIColorPicker'; -import IAIIconButton from '../../../../../common/components/IAIIconButton'; -import IAIPopover from '../../../../../common/components/IAIPopover'; -import { InpaintingState, setMaskColor } from '../../inpaintingSlice'; + currentCanvasSelector, + GenericCanvasState, + setMaskColor, +} from 'features/canvas/canvasSlice'; import _ from 'lodash'; import { createSelector } from '@reduxjs/toolkit'; -import { activeTabNameSelector } from '../../../../options/optionsSelectors'; +import { activeTabNameSelector } from 'features/options/optionsSelectors'; import { useHotkeys } from 'react-hotkeys-hook'; -const inpaintingMaskColorPickerSelector = createSelector( - [(state: RootState) => state.inpainting, activeTabNameSelector], - (inpainting: InpaintingState, activeTabName) => { - const { shouldShowMask, maskColor } = inpainting; +const maskColorPickerSelector = createSelector( + [currentCanvasSelector, activeTabNameSelector], + (currentCanvas: GenericCanvasState, activeTabName) => { + const { isMaskEnabled, maskColor } = currentCanvas; - return { shouldShowMask, maskColor, activeTabName }; + return { + isMaskEnabled, + maskColor, + activeTabName, + }; }, { memoizeOptions: { @@ -30,9 +34,9 @@ const inpaintingMaskColorPickerSelector = createSelector( } ); -export default function InpaintingMaskColorPicker() { - const { shouldShowMask, maskColor, activeTabName } = useAppSelector( - inpaintingMaskColorPickerSelector +export default function IAICanvasMaskColorPicker() { + const { isMaskEnabled, maskColor, activeTabName } = useAppSelector( + maskColorPickerSelector ); const dispatch = useAppDispatch(); const handleChangeMaskColor = (newColor: RgbaColor) => { @@ -51,9 +55,9 @@ export default function InpaintingMaskColorPicker() { }); }, { - enabled: activeTabName === 'inpainting' && shouldShowMask, + enabled: true, }, - [activeTabName, shouldShowMask, maskColor.a] + [activeTabName, isMaskEnabled, maskColor.a] ); // Increase mask opacity @@ -63,13 +67,13 @@ export default function InpaintingMaskColorPicker() { e.preventDefault(); handleChangeMaskColor({ ...maskColor, - a: Math.min(maskColor.a + 0.05, 100), + a: Math.min(maskColor.a + 0.05, 1), }); }, { - enabled: activeTabName === 'inpainting' && shouldShowMask, + enabled: true, }, - [activeTabName, shouldShowMask, maskColor.a] + [activeTabName, isMaskEnabled, maskColor.a] ); return ( @@ -80,7 +84,7 @@ export default function InpaintingMaskColorPicker() { } - isDisabled={!shouldShowMask} + isDisabled={!isMaskEnabled} cursor={'pointer'} /> } diff --git a/frontend/src/features/tabs/Inpainting/InpaintingControls/InpaintingMaskControls/InpaintingMaskInvertControl.tsx b/frontend/src/features/canvas/IAICanvasControls/IAICanvasMaskControls/IAICanvasMaskInvertControl.tsx similarity index 50% rename from frontend/src/features/tabs/Inpainting/InpaintingControls/InpaintingMaskControls/InpaintingMaskInvertControl.tsx rename to frontend/src/features/canvas/IAICanvasControls/IAICanvasMaskControls/IAICanvasMaskInvertControl.tsx index 3842079c33..d9e79ef002 100644 --- a/frontend/src/features/tabs/Inpainting/InpaintingControls/InpaintingMaskControls/InpaintingMaskInvertControl.tsx +++ b/frontend/src/features/canvas/IAICanvasControls/IAICanvasMaskControls/IAICanvasMaskInvertControl.tsx @@ -1,24 +1,27 @@ import { createSelector } from '@reduxjs/toolkit'; -import React from 'react'; import { MdInvertColors, MdInvertColorsOff } from 'react-icons/md'; +import { useAppDispatch, useAppSelector } from 'app/store'; +import IAIIconButton from 'common/components/IAIIconButton'; import { - RootState, - useAppDispatch, - useAppSelector, -} from '../../../../../app/store'; -import IAIIconButton from '../../../../../common/components/IAIIconButton'; -import { InpaintingState, setShouldInvertMask } from '../../inpaintingSlice'; + currentCanvasSelector, + GenericCanvasState, + setShouldInvertMask, +} from 'features/canvas/canvasSlice'; import _ from 'lodash'; -import { activeTabNameSelector } from '../../../../options/optionsSelectors'; +import { activeTabNameSelector } from 'features/options/optionsSelectors'; import { useHotkeys } from 'react-hotkeys-hook'; -const inpaintingMaskInvertSelector = createSelector( - [(state: RootState) => state.inpainting, activeTabNameSelector], - (inpainting: InpaintingState, activeTabName) => { - const { shouldShowMask, shouldInvertMask } = inpainting; +const canvasMaskInvertSelector = createSelector( + [currentCanvasSelector, activeTabNameSelector], + (currentCanvas: GenericCanvasState, activeTabName) => { + const { isMaskEnabled, shouldInvertMask } = currentCanvas; - return { shouldInvertMask, shouldShowMask, activeTabName }; + return { + shouldInvertMask, + isMaskEnabled, + activeTabName, + }; }, { memoizeOptions: { @@ -27,9 +30,9 @@ const inpaintingMaskInvertSelector = createSelector( } ); -export default function InpaintingMaskInvertControl() { - const { shouldInvertMask, shouldShowMask, activeTabName } = useAppSelector( - inpaintingMaskInvertSelector +export default function IAICanvasMaskInvertControl() { + const { shouldInvertMask, isMaskEnabled, activeTabName } = useAppSelector( + canvasMaskInvertSelector ); const dispatch = useAppDispatch(); @@ -44,9 +47,9 @@ export default function InpaintingMaskInvertControl() { handleToggleShouldInvertMask(); }, { - enabled: activeTabName === 'inpainting' && shouldShowMask, + enabled: true, }, - [activeTabName, shouldInvertMask, shouldShowMask] + [activeTabName, shouldInvertMask, isMaskEnabled] ); return ( @@ -62,7 +65,7 @@ export default function InpaintingMaskInvertControl() { ) } onClick={handleToggleShouldInvertMask} - isDisabled={!shouldShowMask} + isDisabled={!isMaskEnabled} /> ); } diff --git a/frontend/src/features/canvas/IAICanvasControls/IAICanvasMaskControls/IAICanvasMaskVisibilityControl.tsx b/frontend/src/features/canvas/IAICanvasControls/IAICanvasMaskControls/IAICanvasMaskVisibilityControl.tsx new file mode 100644 index 0000000000..459785e5d4 --- /dev/null +++ b/frontend/src/features/canvas/IAICanvasControls/IAICanvasMaskControls/IAICanvasMaskVisibilityControl.tsx @@ -0,0 +1,60 @@ +import { useHotkeys } from 'react-hotkeys-hook'; +import { BiHide, BiShow } from 'react-icons/bi'; +import { createSelector } from 'reselect'; +import { useAppDispatch, useAppSelector } from 'app/store'; +import IAIIconButton from 'common/components/IAIIconButton'; +import { activeTabNameSelector } from 'features/options/optionsSelectors'; +import { + currentCanvasSelector, + GenericCanvasState, + setIsMaskEnabled, +} from 'features/canvas/canvasSlice'; + +import _ from 'lodash'; + +const canvasMaskVisibilitySelector = createSelector( + [currentCanvasSelector, activeTabNameSelector], + (currentCanvas: GenericCanvasState, activeTabName) => { + const { isMaskEnabled } = currentCanvas; + + return { isMaskEnabled, activeTabName }; + }, + { + memoizeOptions: { + resultEqualityCheck: _.isEqual, + }, + } +); + +export default function IAICanvasMaskVisibilityControl() { + const dispatch = useAppDispatch(); + + const { isMaskEnabled, activeTabName } = useAppSelector( + canvasMaskVisibilitySelector + ); + + const handleToggleShouldShowMask = () => + dispatch(setIsMaskEnabled(!isMaskEnabled)); + // Hotkeys + // Show/hide mask + useHotkeys( + 'h', + (e: KeyboardEvent) => { + e.preventDefault(); + handleToggleShouldShowMask(); + }, + { + enabled: activeTabName === 'inpainting' || activeTabName == 'outpainting', + }, + [activeTabName, isMaskEnabled] + ); + return ( + : } + onClick={handleToggleShouldShowMask} + /> + ); +} diff --git a/frontend/src/features/canvas/IAICanvasControls/IAICanvasRedoButton.tsx b/frontend/src/features/canvas/IAICanvasControls/IAICanvasRedoButton.tsx new file mode 100644 index 0000000000..190ebebbb7 --- /dev/null +++ b/frontend/src/features/canvas/IAICanvasControls/IAICanvasRedoButton.tsx @@ -0,0 +1,57 @@ +import { createSelector } from '@reduxjs/toolkit'; +import { useHotkeys } from 'react-hotkeys-hook'; +import { FaRedo } from 'react-icons/fa'; +import { useAppDispatch, useAppSelector } from 'app/store'; +import IAIIconButton from 'common/components/IAIIconButton'; +import { activeTabNameSelector } from 'features/options/optionsSelectors'; +import { currentCanvasSelector, redo } from 'features/canvas/canvasSlice'; + +import _ from 'lodash'; + +const canvasRedoSelector = createSelector( + [currentCanvasSelector, activeTabNameSelector], + (currentCanvas, activeTabName) => { + const { futureObjects } = currentCanvas; + + return { + canRedo: futureObjects.length > 0, + activeTabName, + }; + }, + { + memoizeOptions: { + resultEqualityCheck: _.isEqual, + }, + } +); + +export default function IAICanvasRedoButton() { + const dispatch = useAppDispatch(); + const { canRedo, activeTabName } = useAppSelector(canvasRedoSelector); + + const handleRedo = () => { + dispatch(redo()); + }; + + useHotkeys( + ['meta+shift+z', 'control+shift+z', 'control+y', 'meta+y'], + (e: KeyboardEvent) => { + e.preventDefault(); + handleRedo(); + }, + { + enabled: canRedo, + }, + [activeTabName, canRedo] + ); + + return ( + } + onClick={handleRedo} + isDisabled={!canRedo} + /> + ); +} diff --git a/frontend/src/features/canvas/IAICanvasControls/IAICanvasShowHideBoundingBoxControl.tsx b/frontend/src/features/canvas/IAICanvasControls/IAICanvasShowHideBoundingBoxControl.tsx new file mode 100644 index 0000000000..ca8f70fc4a --- /dev/null +++ b/frontend/src/features/canvas/IAICanvasControls/IAICanvasShowHideBoundingBoxControl.tsx @@ -0,0 +1,46 @@ +import { FaVectorSquare } from 'react-icons/fa'; +import { useAppDispatch, useAppSelector } from 'app/store'; +import IAIIconButton from 'common/components/IAIIconButton'; +import { + currentCanvasSelector, + GenericCanvasState, + setShouldShowBoundingBox, +} from 'features/canvas/canvasSlice'; +import { createSelector } from '@reduxjs/toolkit'; +import _ from 'lodash'; + +const canvasShowHideBoundingBoxControlSelector = createSelector( + currentCanvasSelector, + (currentCanvas: GenericCanvasState) => { + const { shouldShowBoundingBox } = currentCanvas; + + return { + shouldShowBoundingBox, + }; + }, + { + memoizeOptions: { + resultEqualityCheck: _.isEqual, + }, + } +); +const IAICanvasShowHideBoundingBoxControl = () => { + const dispatch = useAppDispatch(); + const { shouldShowBoundingBox } = useAppSelector( + canvasShowHideBoundingBoxControlSelector + ); + + return ( + } + data-alert={!shouldShowBoundingBox} + onClick={() => { + dispatch(setShouldShowBoundingBox(!shouldShowBoundingBox)); + }} + /> + ); +}; + +export default IAICanvasShowHideBoundingBoxControl; diff --git a/frontend/src/features/tabs/Inpainting/InpaintingControls/InpaintingSplitLayoutControl.tsx b/frontend/src/features/canvas/IAICanvasControls/IAICanvasSplitLayoutControl.tsx similarity index 64% rename from frontend/src/features/tabs/Inpainting/InpaintingControls/InpaintingSplitLayoutControl.tsx rename to frontend/src/features/canvas/IAICanvasControls/IAICanvasSplitLayoutControl.tsx index 3f2bcceed4..ce84c168bd 100644 --- a/frontend/src/features/tabs/Inpainting/InpaintingControls/InpaintingSplitLayoutControl.tsx +++ b/frontend/src/features/canvas/IAICanvasControls/IAICanvasSplitLayoutControl.tsx @@ -1,16 +1,11 @@ -import React from 'react'; import { useHotkeys } from 'react-hotkeys-hook'; import { VscSplitHorizontal } from 'react-icons/vsc'; -import { - RootState, - useAppDispatch, - useAppSelector, -} from '../../../../app/store'; -import IAIIconButton from '../../../../common/components/IAIIconButton'; -import { setShowDualDisplay } from '../../../options/optionsSlice'; -import { setNeedsCache } from '../inpaintingSlice'; +import { RootState, useAppDispatch, useAppSelector } from 'app/store'; +import IAIIconButton from 'common/components/IAIIconButton'; +import { setShowDualDisplay } from 'features/options/optionsSlice'; +import { setDoesCanvasNeedScaling } from 'features/canvas/canvasSlice'; -export default function InpaintingSplitLayoutControl() { +export default function IAICanvasSplitLayoutControl() { const dispatch = useAppDispatch(); const showDualDisplay = useAppSelector( (state: RootState) => state.options.showDualDisplay @@ -18,7 +13,7 @@ export default function InpaintingSplitLayoutControl() { const handleDualDisplay = () => { dispatch(setShowDualDisplay(!showDualDisplay)); - dispatch(setNeedsCache(true)); + dispatch(setDoesCanvasNeedScaling(true)); }; // Hotkeys diff --git a/frontend/src/features/canvas/IAICanvasControls/IAICanvasUndoButton.tsx b/frontend/src/features/canvas/IAICanvasControls/IAICanvasUndoButton.tsx new file mode 100644 index 0000000000..54be780dd5 --- /dev/null +++ b/frontend/src/features/canvas/IAICanvasControls/IAICanvasUndoButton.tsx @@ -0,0 +1,58 @@ +import { createSelector } from '@reduxjs/toolkit'; +import { useHotkeys } from 'react-hotkeys-hook'; +import { FaUndo } from 'react-icons/fa'; +import { useAppDispatch, useAppSelector } from 'app/store'; +import IAIIconButton from 'common/components/IAIIconButton'; +import { currentCanvasSelector, undo } from 'features/canvas/canvasSlice'; + +import _ from 'lodash'; +import { activeTabNameSelector } from 'features/options/optionsSelectors'; + +const canvasUndoSelector = createSelector( + [currentCanvasSelector, activeTabNameSelector], + (canvas, activeTabName) => { + const { pastObjects } = canvas; + + return { + canUndo: pastObjects.length > 0, + activeTabName, + }; + }, + { + memoizeOptions: { + resultEqualityCheck: _.isEqual, + }, + } +); + +export default function IAICanvasUndoButton() { + const dispatch = useAppDispatch(); + + const { canUndo, activeTabName } = useAppSelector(canvasUndoSelector); + + const handleUndo = () => { + dispatch(undo()); + }; + + useHotkeys( + ['meta+z', 'control+z'], + (e: KeyboardEvent) => { + e.preventDefault(); + handleUndo(); + }, + { + enabled: canUndo, + }, + [activeTabName, canUndo] + ); + + return ( + } + onClick={handleUndo} + isDisabled={!canUndo} + /> + ); +} diff --git a/frontend/src/features/canvas/IAICanvasEraserButtonPopover.tsx b/frontend/src/features/canvas/IAICanvasEraserButtonPopover.tsx new file mode 100644 index 0000000000..ae5ee21125 --- /dev/null +++ b/frontend/src/features/canvas/IAICanvasEraserButtonPopover.tsx @@ -0,0 +1,71 @@ +import { createSelector } from '@reduxjs/toolkit'; +import { currentCanvasSelector, setEraserSize, setTool } from './canvasSlice'; +import { useAppDispatch, useAppSelector } from 'app/store'; +import _ from 'lodash'; +import IAIIconButton from 'common/components/IAIIconButton'; +import { FaEraser } from 'react-icons/fa'; +import IAIPopover from 'common/components/IAIPopover'; +import IAISlider from 'common/components/IAISlider'; +import { Flex } from '@chakra-ui/react'; +import { useHotkeys } from 'react-hotkeys-hook'; + +export const selector = createSelector( + [currentCanvasSelector], + (currentCanvas) => { + const { eraserSize, tool } = currentCanvas; + + return { + tool, + eraserSize, + }; + }, + { + memoizeOptions: { + resultEqualityCheck: _.isEqual, + }, + } +); +const IAICanvasEraserButtonPopover = () => { + const dispatch = useAppDispatch(); + const { tool, eraserSize } = useAppSelector(selector); + + const handleSelectEraserTool = () => dispatch(setTool('eraser')); + + useHotkeys( + 'e', + (e: KeyboardEvent) => { + e.preventDefault(); + handleSelectEraserTool(); + }, + { + enabled: true, + }, + [tool] + ); + + return ( + } + data-selected={tool === 'eraser'} + onClick={() => dispatch(setTool('eraser'))} + /> + } + > + + dispatch(setEraserSize(newSize))} + /> + + + ); +}; + +export default IAICanvasEraserButtonPopover; diff --git a/frontend/src/features/canvas/IAICanvasEraserLines.tsx b/frontend/src/features/canvas/IAICanvasEraserLines.tsx new file mode 100644 index 0000000000..9513ac0fef --- /dev/null +++ b/frontend/src/features/canvas/IAICanvasEraserLines.tsx @@ -0,0 +1,49 @@ +// import { GroupConfig } from 'konva/lib/Group'; +// import { Group, Line } from 'react-konva'; +// import { RootState, useAppSelector } from 'app/store'; +// import { createSelector } from '@reduxjs/toolkit'; +// import { OutpaintingCanvasState } from './canvasSlice'; + +// export const canvasEraserLinesSelector = createSelector( +// (state: RootState) => state.canvas.outpainting, +// (outpainting: OutpaintingCanvasState) => { +// const { eraserLines } = outpainting; +// return { +// eraserLines, +// }; +// } +// ); + +// type IAICanvasEraserLinesProps = GroupConfig; + +// /** +// * Draws the lines which comprise the mask. +// * +// * Uses globalCompositeOperation to handle the brush and eraser tools. +// */ +// const IAICanvasEraserLines = (props: IAICanvasEraserLinesProps) => { +// const { ...rest } = props; +// const { eraserLines } = useAppSelector(canvasEraserLinesSelector); + +// return ( +// +// {eraserLines.map((line, i) => ( +// 0 +// strokeWidth={line.strokeWidth * 2} +// tension={0} +// lineCap="round" +// lineJoin="round" +// shadowForStrokeEnabled={false} +// listening={false} +// globalCompositeOperation={'source-over'} +// /> +// ))} +// +// ); +// }; + +// export default IAICanvasEraserLines; +export default {} \ No newline at end of file diff --git a/frontend/src/features/canvas/IAICanvasGrid.tsx b/frontend/src/features/canvas/IAICanvasGrid.tsx new file mode 100644 index 0000000000..495f22ba5b --- /dev/null +++ b/frontend/src/features/canvas/IAICanvasGrid.tsx @@ -0,0 +1,88 @@ +// Grid drawing adapted from https://longviewcoder.com/2021/12/08/konva-a-better-grid/ + +import { useColorMode } from '@chakra-ui/react'; +import _ from 'lodash'; +import { Group, Line as KonvaLine } from 'react-konva'; +import useUnscaleCanvasValue from './hooks/useUnscaleCanvasValue'; +import { stageRef } from './IAICanvas'; + +const IAICanvasGrid = () => { + const { colorMode } = useColorMode(); + const unscale = useUnscaleCanvasValue(); + + if (!stageRef.current) return null; + const gridLineColor = + colorMode === 'light' ? 'rgba(0,0,0,0.3)' : 'rgba(255,255,255,0.3)'; + + const stage = stageRef.current; + const width = stage.width(); + const height = stage.height(); + const x = stage.x(); + const y = stage.y(); + + const stageRect = { + x1: 0, + y1: 0, + x2: width, + y2: height, + offset: { + x: unscale(x), + y: unscale(y), + }, + }; + + const gridOffset = { + x: Math.ceil(unscale(x) / 64) * 64, + y: Math.ceil(unscale(y) / 64) * 64, + }; + + const gridRect = { + x1: -gridOffset.x, + y1: -gridOffset.y, + x2: unscale(width) - gridOffset.x + 64, + y2: unscale(height) - gridOffset.y + 64, + }; + + const gridFullRect = { + x1: Math.min(stageRect.x1, gridRect.x1), + y1: Math.min(stageRect.y1, gridRect.y1), + x2: Math.max(stageRect.x2, gridRect.x2), + y2: Math.max(stageRect.y2, gridRect.y2), + }; + + const fullRect = gridFullRect; + + const // find the x & y size of the grid + xSize = fullRect.x2 - fullRect.x1, + ySize = fullRect.y2 - fullRect.y1, + // compute the number of steps required on each axis. + xSteps = Math.round(xSize / 64) + 1, + ySteps = Math.round(ySize / 64) + 1; + + return ( + + {_.range(0, xSteps).map((i) => ( + + ))} + {_.range(0, ySteps).map((i) => ( + + ))} + + ); +}; + +export default IAICanvasGrid; diff --git a/frontend/src/features/canvas/IAICanvasImage.tsx b/frontend/src/features/canvas/IAICanvasImage.tsx new file mode 100644 index 0000000000..8229f8552f --- /dev/null +++ b/frontend/src/features/canvas/IAICanvasImage.tsx @@ -0,0 +1,15 @@ +import { Image } from 'react-konva'; +import useImage from 'use-image'; + +type IAICanvasImageProps = { + url: string; + x: number; + y: number; +}; +const IAICanvasImage = (props: IAICanvasImageProps) => { + const { url, x, y } = props; + const [image] = useImage(url); + return ; +}; + +export default IAICanvasImage; diff --git a/frontend/src/features/canvas/IAICanvasIntermediateImage.tsx b/frontend/src/features/canvas/IAICanvasIntermediateImage.tsx new file mode 100644 index 0000000000..5562b1e44f --- /dev/null +++ b/frontend/src/features/canvas/IAICanvasIntermediateImage.tsx @@ -0,0 +1,59 @@ +import { createSelector } from '@reduxjs/toolkit'; +import { RootState, useAppSelector } from 'app/store'; +import { GalleryState } from 'features/gallery/gallerySlice'; +import { ImageConfig } from 'konva/lib/shapes/Image'; +import _ from 'lodash'; +import { useEffect, useState } from 'react'; +import { Image as KonvaImage } from 'react-konva'; + +const selector = createSelector( + [(state: RootState) => state.gallery], + (gallery: GalleryState) => { + return gallery.intermediateImage ? gallery.intermediateImage : null; + }, + { + memoizeOptions: { + resultEqualityCheck: _.isEqual, + }, + } +); + +type Props = Omit; + +const IAICanvasIntermediateImage = (props: Props) => { + const { ...rest } = props; + const intermediateImage = useAppSelector(selector); + + const [loadedImageElement, setLoadedImageElement] = + useState(null); + + useEffect(() => { + if (!intermediateImage) return; + const tempImage = new Image(); + + tempImage.onload = () => { + setLoadedImageElement(tempImage); + }; + tempImage.src = intermediateImage.url; + }, [intermediateImage]); + + if (!intermediateImage?.boundingBox) return null; + + const { + boundingBox: { x, y, width, height }, + } = intermediateImage; + + return loadedImageElement ? ( + + ) : null; +}; + +export default IAICanvasIntermediateImage; diff --git a/frontend/src/features/canvas/IAICanvasMaskButtonPopover.tsx b/frontend/src/features/canvas/IAICanvasMaskButtonPopover.tsx new file mode 100644 index 0000000000..787e1548aa --- /dev/null +++ b/frontend/src/features/canvas/IAICanvasMaskButtonPopover.tsx @@ -0,0 +1,69 @@ +import { Button, Flex } from '@chakra-ui/react'; +import { createSelector } from '@reduxjs/toolkit'; +import { + clearMask, + currentCanvasSelector, + setIsMaskEnabled, + setLayer, + setMaskColor, +} from './canvasSlice'; +import { useAppDispatch, useAppSelector } from 'app/store'; +import _ from 'lodash'; +import IAIIconButton from 'common/components/IAIIconButton'; +import { FaMask } from 'react-icons/fa'; +import IAIPopover from 'common/components/IAIPopover'; +import IAICheckbox from 'common/components/IAICheckbox'; +import IAIColorPicker from 'common/components/IAIColorPicker'; + +export const selector = createSelector( + [currentCanvasSelector], + (currentCanvas) => { + const { maskColor, layer, isMaskEnabled } = currentCanvas; + + return { + layer, + maskColor, + isMaskEnabled, + }; + }, + { + memoizeOptions: { + resultEqualityCheck: _.isEqual, + }, + } +); +const IAICanvasMaskButtonPopover = () => { + const dispatch = useAppDispatch(); + const { layer, maskColor, isMaskEnabled } = useAppSelector(selector); + + return ( + dispatch(setLayer(layer === 'mask' ? 'base' : 'mask'))} + icon={} + /> + } + > + + + dispatch(setIsMaskEnabled(e.target.checked))} + /> + + dispatch(setMaskColor(newColor))} + /> + + + ); +}; + +export default IAICanvasMaskButtonPopover; diff --git a/frontend/src/features/canvas/IAICanvasMaskCompositer.tsx b/frontend/src/features/canvas/IAICanvasMaskCompositer.tsx new file mode 100644 index 0000000000..c3e218eff4 --- /dev/null +++ b/frontend/src/features/canvas/IAICanvasMaskCompositer.tsx @@ -0,0 +1,49 @@ +import { createSelector } from '@reduxjs/toolkit'; +import { useAppSelector } from 'app/store'; +import { RectConfig } from 'konva/lib/shapes/Rect'; +import { Rect } from 'react-konva'; +import { + currentCanvasSelector, + InpaintingCanvasState, + OutpaintingCanvasState, +} from './canvasSlice'; +import { rgbaColorToString } from './util/colorToString'; + +export const canvasMaskCompositerSelector = createSelector( + currentCanvasSelector, + (currentCanvas) => { + const { maskColor, stageCoordinates, stageDimensions, stageScale } = + currentCanvas as InpaintingCanvasState | OutpaintingCanvasState; + + return { + stageCoordinates, + stageDimensions, + stageScale, + maskColorString: rgbaColorToString(maskColor), + }; + } +); + +type IAICanvasMaskCompositerProps = RectConfig; + +const IAICanvasMaskCompositer = (props: IAICanvasMaskCompositerProps) => { + const { ...rest } = props; + + const { maskColorString, stageCoordinates, stageDimensions, stageScale } = + useAppSelector(canvasMaskCompositerSelector); + + return ( + + ); +}; + +export default IAICanvasMaskCompositer; diff --git a/frontend/src/features/canvas/IAICanvasMaskLines.tsx b/frontend/src/features/canvas/IAICanvasMaskLines.tsx new file mode 100644 index 0000000000..32c5d358da --- /dev/null +++ b/frontend/src/features/canvas/IAICanvasMaskLines.tsx @@ -0,0 +1,64 @@ +import { GroupConfig } from 'konva/lib/Group'; +import { Group, Line } from 'react-konva'; +import { useAppSelector } from 'app/store'; +import { createSelector } from '@reduxjs/toolkit'; +import { + currentCanvasSelector, + GenericCanvasState, + InpaintingCanvasState, + isCanvasMaskLine, + OutpaintingCanvasState, +} from './canvasSlice'; +import _ from 'lodash'; + +export const canvasLinesSelector = createSelector( + currentCanvasSelector, + (currentCanvas: GenericCanvasState) => { + const { objects } = currentCanvas as + | InpaintingCanvasState + | OutpaintingCanvasState; + return { + objects, + }; + }, + { + memoizeOptions: { + resultEqualityCheck: _.isEqual, + }, + } +); + +type InpaintingCanvasLinesProps = GroupConfig; + +/** + * Draws the lines which comprise the mask. + * + * Uses globalCompositeOperation to handle the brush and eraser tools. + */ +const IAICanvasLines = (props: InpaintingCanvasLinesProps) => { + const { ...rest } = props; + const { objects } = useAppSelector(canvasLinesSelector); + + return ( + + {objects.filter(isCanvasMaskLine).map((line, i) => ( + 0 + strokeWidth={line.strokeWidth * 2} + tension={0} + lineCap="round" + lineJoin="round" + shadowForStrokeEnabled={false} + listening={false} + globalCompositeOperation={ + line.tool === 'brush' ? 'source-over' : 'destination-out' + } + /> + ))} + + ); +}; + +export default IAICanvasLines; diff --git a/frontend/src/features/canvas/IAICanvasOutpaintingControls.tsx b/frontend/src/features/canvas/IAICanvasOutpaintingControls.tsx new file mode 100644 index 0000000000..c3504238d4 --- /dev/null +++ b/frontend/src/features/canvas/IAICanvasOutpaintingControls.tsx @@ -0,0 +1,112 @@ +import { ButtonGroup } from '@chakra-ui/react'; +import { createSelector } from '@reduxjs/toolkit'; +import { + currentCanvasSelector, + resetCanvas, + setTool, + uploadOutpaintingMergedImage, +} from './canvasSlice'; +import { useAppDispatch, useAppSelector } from 'app/store'; +import _ from 'lodash'; +import { canvasImageLayerRef } from './IAICanvas'; +import IAIIconButton from 'common/components/IAIIconButton'; +import { + FaArrowsAlt, + FaCopy, + FaDownload, + FaLayerGroup, + FaSave, + FaTrash, + FaUpload, +} from 'react-icons/fa'; +import IAICanvasUndoButton from './IAICanvasControls/IAICanvasUndoButton'; +import IAICanvasRedoButton from './IAICanvasControls/IAICanvasRedoButton'; +import IAICanvasSettingsButtonPopover from './IAICanvasSettingsButtonPopover'; +import IAICanvasEraserButtonPopover from './IAICanvasEraserButtonPopover'; +import IAICanvasBrushButtonPopover from './IAICanvasBrushButtonPopover'; +import IAICanvasMaskButtonPopover from './IAICanvasMaskButtonPopover'; + +export const canvasControlsSelector = createSelector( + [currentCanvasSelector], + (currentCanvas) => { + const { tool } = currentCanvas; + + return { + tool, + }; + }, + { + memoizeOptions: { + resultEqualityCheck: _.isEqual, + }, + } +); + +const IAICanvasOutpaintingControls = () => { + const dispatch = useAppDispatch(); + const { tool } = useAppSelector(canvasControlsSelector); + + return ( +
+ + + + + } + data-selected={tool === 'move'} + onClick={() => dispatch(setTool('move'))} + /> + + + } + onClick={() => { + dispatch(uploadOutpaintingMergedImage(canvasImageLayerRef)); + }} + /> + } + /> + } + /> + } + /> + + + + + + + + + + } + /> + } + onClick={() => dispatch(resetCanvas())} + /> + +
+ ); +}; + +export default IAICanvasOutpaintingControls; diff --git a/frontend/src/features/canvas/IAICanvasOutpaintingObjects.tsx b/frontend/src/features/canvas/IAICanvasOutpaintingObjects.tsx new file mode 100644 index 0000000000..eba52769f3 --- /dev/null +++ b/frontend/src/features/canvas/IAICanvasOutpaintingObjects.tsx @@ -0,0 +1,65 @@ +import { createSelector } from '@reduxjs/toolkit'; +import { RootState, useAppSelector } from 'app/store'; +import _ from 'lodash'; +import { Group, Line } from 'react-konva'; +import { + CanvasState, + isCanvasBaseImage, + isCanvasBaseLine, +} from './canvasSlice'; +import IAICanvasImage from './IAICanvasImage'; +import { rgbaColorToString } from './util/colorToString'; + +const selector = createSelector( + [(state: RootState) => state.canvas], + (canvas: CanvasState) => { + return { + objects: + canvas.currentCanvas === 'outpainting' + ? canvas.outpainting.objects + : undefined, + }; + }, + { + memoizeOptions: { + resultEqualityCheck: _.isEqual, + }, + } +); + +const IAICanvasOutpaintingObjects = () => { + const { objects } = useAppSelector(selector); + + if (!objects) return null; + + return ( + + {objects.map((obj, i) => { + if (isCanvasBaseImage(obj)) { + return ( + + ); + } else if (isCanvasBaseLine(obj)) { + return ( + 0 + strokeWidth={obj.strokeWidth * 2} + tension={0} + lineCap="round" + lineJoin="round" + shadowForStrokeEnabled={false} + listening={false} + globalCompositeOperation={ + obj.tool === 'brush' ? 'source-over' : 'destination-out' + } + /> + ); + } + })} + + ); +}; + +export default IAICanvasOutpaintingObjects; diff --git a/frontend/src/features/canvas/IAICanvasResizer.tsx b/frontend/src/features/canvas/IAICanvasResizer.tsx new file mode 100644 index 0000000000..5649b2b20c --- /dev/null +++ b/frontend/src/features/canvas/IAICanvasResizer.tsx @@ -0,0 +1,78 @@ +import { Spinner } from '@chakra-ui/react'; +import { useLayoutEffect, useRef } from 'react'; +import { RootState, useAppDispatch, useAppSelector } from 'app/store'; +import { activeTabNameSelector } from 'features/options/optionsSelectors'; +import { + baseCanvasImageSelector, + CanvasState, + currentCanvasSelector, + GenericCanvasState, + setStageDimensions, + setStageScale, +} from 'features/canvas/canvasSlice'; +import { createSelector } from '@reduxjs/toolkit'; +import * as InvokeAI from 'app/invokeai'; +import { first } from 'lodash'; + +const canvasResizerSelector = createSelector( + (state: RootState) => state.canvas, + baseCanvasImageSelector, + activeTabNameSelector, + (canvas: CanvasState, baseCanvasImage, activeTabName) => { + const { doesCanvasNeedScaling } = canvas; + + return { + doesCanvasNeedScaling, + activeTabName, + baseCanvasImage, + }; + } +); + +const IAICanvasResizer = () => { + const dispatch = useAppDispatch(); + const { doesCanvasNeedScaling, activeTabName, baseCanvasImage } = + useAppSelector(canvasResizerSelector); + + const ref = useRef(null); + + useLayoutEffect(() => { + window.setTimeout(() => { + if (!ref.current || !baseCanvasImage) return; + + const width = ref.current.clientWidth; + const height = ref.current.clientHeight; + + const scale = Math.min( + 1, + Math.min(width / baseCanvasImage.width, height / baseCanvasImage.height) + ); + + dispatch(setStageScale(scale)); + + if (activeTabName === 'inpainting') { + dispatch( + setStageDimensions({ + width: Math.floor(baseCanvasImage.width * scale), + height: Math.floor(baseCanvasImage.height * scale), + }) + ); + } else if (activeTabName === 'outpainting') { + dispatch( + setStageDimensions({ + width: Math.floor(width), + height: Math.floor(height), + }) + ); + } + }, 0); + }, [dispatch, baseCanvasImage, doesCanvasNeedScaling, activeTabName]); + + return ( +
+ +
+ ); +}; + +export default IAICanvasResizer; diff --git a/frontend/src/features/canvas/IAICanvasSettingsButtonPopover.tsx b/frontend/src/features/canvas/IAICanvasSettingsButtonPopover.tsx new file mode 100644 index 0000000000..3efbaf3fd3 --- /dev/null +++ b/frontend/src/features/canvas/IAICanvasSettingsButtonPopover.tsx @@ -0,0 +1,101 @@ +import { Flex } from '@chakra-ui/react'; +import { createSelector } from '@reduxjs/toolkit'; +import { + currentCanvasSelector, + outpaintingCanvasSelector, + setShouldAutoSave, + setShouldDarkenOutsideBoundingBox, + setShouldShowGrid, + setShouldShowIntermediates, + setShouldSnapToGrid, +} from './canvasSlice'; +import { useAppDispatch, useAppSelector } from 'app/store'; +import _ from 'lodash'; +import IAIIconButton from 'common/components/IAIIconButton'; +import { FaWrench } from 'react-icons/fa'; +import IAIPopover from 'common/components/IAIPopover'; +import IAICheckbox from 'common/components/IAICheckbox'; + +export const canvasControlsSelector = createSelector( + [currentCanvasSelector, outpaintingCanvasSelector], + (currentCanvas, outpaintingCanvas) => { + const { shouldDarkenOutsideBoundingBox, shouldShowIntermediates } = + currentCanvas; + + const { shouldShowGrid, shouldSnapToGrid, shouldAutoSave } = + outpaintingCanvas; + + return { + shouldShowGrid, + shouldSnapToGrid, + shouldAutoSave, + shouldDarkenOutsideBoundingBox, + shouldShowIntermediates, + }; + }, + { + memoizeOptions: { + resultEqualityCheck: _.isEqual, + }, + } +); + +const IAICanvasSettingsButtonPopover = () => { + const dispatch = useAppDispatch(); + const { + shouldShowIntermediates, + shouldShowGrid, + shouldSnapToGrid, + shouldAutoSave, + shouldDarkenOutsideBoundingBox, + } = useAppSelector(canvasControlsSelector); + + return ( + } + /> + } + > + + + dispatch(setShouldShowIntermediates(e.target.checked)) + } + /> + dispatch(setShouldShowGrid(e.target.checked))} + /> + dispatch(setShouldSnapToGrid(e.target.checked))} + /> + + dispatch(setShouldDarkenOutsideBoundingBox(e.target.checked)) + } + /> + dispatch(setShouldAutoSave(e.target.checked))} + /> + + + ); +}; + +export default IAICanvasSettingsButtonPopover; diff --git a/frontend/src/features/canvas/IAICanvasStatusText.tsx b/frontend/src/features/canvas/IAICanvasStatusText.tsx new file mode 100644 index 0000000000..3b9694a7c5 --- /dev/null +++ b/frontend/src/features/canvas/IAICanvasStatusText.tsx @@ -0,0 +1,74 @@ +import { createSelector } from '@reduxjs/toolkit'; +import { useAppSelector } from 'app/store'; +import _ from 'lodash'; +import { currentCanvasSelector } from './canvasSlice'; + +const roundToHundreth = (val: number): number => { + return Math.round(val * 100) / 100; +}; + +const selector = createSelector( + [currentCanvasSelector], + (currentCanvas) => { + const { + stageDimensions: { width: stageWidth, height: stageHeight }, + stageCoordinates: { x: stageX, y: stageY }, + boundingBoxDimensions: { width: boxWidth, height: boxHeight }, + boundingBoxCoordinates: { x: boxX, y: boxY }, + cursorPosition, + stageScale, + } = currentCanvas; + + const position = cursorPosition + ? { cursorX: cursorPosition.x, cursorY: cursorPosition.y } + : { cursorX: -1, cursorY: -1 }; + + return { + stageWidth, + stageHeight, + stageX, + stageY, + boxWidth, + boxHeight, + boxX, + boxY, + stageScale, + ...position, + }; + }, + + { + memoizeOptions: { + resultEqualityCheck: _.isEqual, + }, + } +); +const IAICanvasStatusText = () => { + const { + stageWidth, + stageHeight, + stageX, + stageY, + boxWidth, + boxHeight, + boxX, + boxY, + cursorX, + cursorY, + stageScale, + } = useAppSelector(selector); + return ( +
+
{`Stage: ${stageWidth} x ${stageHeight}`}
+
{`Stage: ${roundToHundreth(stageX)}, ${roundToHundreth( + stageY + )}`}
+
{`Scale: ${roundToHundreth(stageScale)}`}
+
{`Box: ${boxWidth} x ${boxHeight}`}
+
{`Box: ${roundToHundreth(boxX)}, ${roundToHundreth(boxY)}`}
+
{`Cursor: ${cursorX}, ${cursorY}`}
+
+ ); +}; + +export default IAICanvasStatusText; diff --git a/frontend/src/features/canvas/canvasSlice.ts b/frontend/src/features/canvas/canvasSlice.ts new file mode 100644 index 0000000000..f940c4c978 --- /dev/null +++ b/frontend/src/features/canvas/canvasSlice.ts @@ -0,0 +1,764 @@ +import { + createAsyncThunk, + createSelector, + createSlice, +} from '@reduxjs/toolkit'; +import { v4 as uuidv4 } from 'uuid'; +import type { PayloadAction } from '@reduxjs/toolkit'; +import { IRect, Vector2d } from 'konva/lib/types'; +import { RgbaColor } from 'react-colorful'; +import * as InvokeAI from 'app/invokeai'; +import _ from 'lodash'; +import { roundDownToMultiple } from 'common/util/roundDownToMultiple'; +import { RootState } from 'app/store'; +import { activeTabNameSelector } from 'features/options/optionsSelectors'; +import { MutableRefObject } from 'react'; +import Konva from 'konva'; + +export interface GenericCanvasState { + tool: CanvasTool; + brushSize: number; + brushColor: RgbaColor; + eraserSize: number; + maskColor: RgbaColor; + cursorPosition: Vector2d | null; + stageDimensions: Dimensions; + stageCoordinates: Vector2d; + boundingBoxDimensions: Dimensions; + boundingBoxCoordinates: Vector2d; + boundingBoxPreviewFill: RgbaColor; + shouldShowBoundingBox: boolean; + shouldDarkenOutsideBoundingBox: boolean; + isMaskEnabled: boolean; + shouldInvertMask: boolean; + shouldShowCheckboardTransparency: boolean; + shouldShowBrush: boolean; + shouldShowBrushPreview: boolean; + stageScale: number; + isDrawing: boolean; + isTransformingBoundingBox: boolean; + isMouseOverBoundingBox: boolean; + isMovingBoundingBox: boolean; + isMovingStage: boolean; + shouldUseInpaintReplace: boolean; + inpaintReplace: number; + shouldLockBoundingBox: boolean; + isMoveBoundingBoxKeyHeld: boolean; + isMoveStageKeyHeld: boolean; + intermediateImage?: InvokeAI.Image; + shouldShowIntermediates: boolean; +} + +export type CanvasLayer = 'base' | 'mask'; + +export type CanvasDrawingTool = 'brush' | 'eraser'; + +export type CanvasTool = CanvasDrawingTool | 'move'; + +export type Dimensions = { + width: number; + height: number; +}; + +export type CanvasAnyLine = { + kind: 'line'; + tool: CanvasDrawingTool; + strokeWidth: number; + points: number[]; +}; + +export type CanvasImage = { + kind: 'image'; + layer: 'base'; + x: number; + y: number; + image: InvokeAI.Image; +}; + +export type CanvasMaskLine = CanvasAnyLine & { + layer: 'mask'; +}; + +export type CanvasLine = CanvasAnyLine & { + layer: 'base'; + color?: RgbaColor; +}; + +type CanvasObject = CanvasImage | CanvasLine | CanvasMaskLine; + +// type guards +export const isCanvasMaskLine = (obj: CanvasObject): obj is CanvasMaskLine => + obj.kind === 'line' && obj.layer === 'mask'; + +export const isCanvasBaseLine = (obj: CanvasObject): obj is CanvasLine => + obj.kind === 'line' && obj.layer === 'base'; + +export const isCanvasBaseImage = (obj: CanvasObject): obj is CanvasImage => + obj.kind === 'image' && obj.layer === 'base'; + +export const isCanvasAnyLine = ( + obj: CanvasObject +): obj is CanvasMaskLine | CanvasLine => obj.kind === 'line'; + +export type OutpaintingCanvasState = GenericCanvasState & { + layer: CanvasLayer; + objects: CanvasObject[]; + pastObjects: CanvasObject[][]; + futureObjects: CanvasObject[][]; + shouldShowGrid: boolean; + shouldSnapToGrid: boolean; + shouldAutoSave: boolean; + stagingArea: { + images: CanvasImage[]; + selectedImageIndex: number; + }; +}; + +export type InpaintingCanvasState = GenericCanvasState & { + layer: 'mask'; + objects: CanvasObject[]; + pastObjects: CanvasObject[][]; + futureObjects: CanvasObject[][]; + imageToInpaint?: InvokeAI.Image; +}; + +export type BaseCanvasState = InpaintingCanvasState | OutpaintingCanvasState; + +export type ValidCanvasName = 'inpainting' | 'outpainting'; + +export interface CanvasState { + doesCanvasNeedScaling: boolean; + currentCanvas: ValidCanvasName; + inpainting: InpaintingCanvasState; + outpainting: OutpaintingCanvasState; +} + +const initialGenericCanvasState: GenericCanvasState = { + tool: 'brush', + brushColor: { r: 90, g: 90, b: 255, a: 1 }, + brushSize: 50, + maskColor: { r: 255, g: 90, b: 90, a: 0.5 }, + eraserSize: 50, + stageDimensions: { width: 0, height: 0 }, + stageCoordinates: { x: 0, y: 0 }, + boundingBoxDimensions: { width: 512, height: 512 }, + boundingBoxCoordinates: { x: 0, y: 0 }, + boundingBoxPreviewFill: { r: 0, g: 0, b: 0, a: 0.5 }, + shouldShowBoundingBox: true, + shouldDarkenOutsideBoundingBox: false, + cursorPosition: null, + isMaskEnabled: true, + shouldInvertMask: false, + shouldShowCheckboardTransparency: false, + shouldShowBrush: true, + shouldShowBrushPreview: false, + isDrawing: false, + isTransformingBoundingBox: false, + isMouseOverBoundingBox: false, + isMovingBoundingBox: false, + stageScale: 1, + shouldUseInpaintReplace: false, + inpaintReplace: 0.1, + shouldLockBoundingBox: false, + isMoveBoundingBoxKeyHeld: false, + isMoveStageKeyHeld: false, + shouldShowIntermediates: true, + isMovingStage: false, +}; + +const initialCanvasState: CanvasState = { + currentCanvas: 'inpainting', + doesCanvasNeedScaling: false, + inpainting: { + layer: 'mask', + objects: [], + pastObjects: [], + futureObjects: [], + ...initialGenericCanvasState, + }, + outpainting: { + layer: 'base', + objects: [], + pastObjects: [], + futureObjects: [], + stagingArea: { + images: [], + selectedImageIndex: 0, + }, + shouldShowGrid: true, + shouldSnapToGrid: true, + shouldAutoSave: false, + ...initialGenericCanvasState, + }, +}; + +export const canvasSlice = createSlice({ + name: 'canvas', + initialState: initialCanvasState, + reducers: { + setTool: (state, action: PayloadAction) => { + const tool = action.payload; + state[state.currentCanvas].tool = action.payload; + if (tool !== 'move') { + state[state.currentCanvas].isTransformingBoundingBox = false; + state[state.currentCanvas].isMouseOverBoundingBox = false; + state[state.currentCanvas].isMovingBoundingBox = false; + state[state.currentCanvas].isMovingStage = false; + } + }, + setLayer: (state, action: PayloadAction) => { + state[state.currentCanvas].layer = action.payload; + }, + toggleTool: (state) => { + const currentTool = state[state.currentCanvas].tool; + if (currentTool !== 'move') { + state[state.currentCanvas].tool = + currentTool === 'brush' ? 'eraser' : 'brush'; + } + }, + setMaskColor: (state, action: PayloadAction) => { + state[state.currentCanvas].maskColor = action.payload; + }, + setBrushColor: (state, action: PayloadAction) => { + state[state.currentCanvas].brushColor = action.payload; + }, + setBrushSize: (state, action: PayloadAction) => { + state[state.currentCanvas].brushSize = action.payload; + }, + setEraserSize: (state, action: PayloadAction) => { + state[state.currentCanvas].eraserSize = action.payload; + }, + clearMask: (state) => { + state[state.currentCanvas].pastObjects.push( + state[state.currentCanvas].objects + ); + state[state.currentCanvas].objects = state[ + state.currentCanvas + ].objects.filter((obj) => !isCanvasMaskLine(obj)); + state[state.currentCanvas].futureObjects = []; + state[state.currentCanvas].shouldInvertMask = false; + }, + toggleShouldInvertMask: (state) => { + state[state.currentCanvas].shouldInvertMask = + !state[state.currentCanvas].shouldInvertMask; + }, + toggleShouldShowMask: (state) => { + state[state.currentCanvas].isMaskEnabled = + !state[state.currentCanvas].isMaskEnabled; + }, + setShouldInvertMask: (state, action: PayloadAction) => { + state[state.currentCanvas].shouldInvertMask = action.payload; + }, + setIsMaskEnabled: (state, action: PayloadAction) => { + state[state.currentCanvas].isMaskEnabled = action.payload; + state[state.currentCanvas].layer = action.payload ? 'mask' : 'base'; + }, + setShouldShowCheckboardTransparency: ( + state, + action: PayloadAction + ) => { + state[state.currentCanvas].shouldShowCheckboardTransparency = + action.payload; + }, + setShouldShowBrushPreview: (state, action: PayloadAction) => { + state[state.currentCanvas].shouldShowBrushPreview = action.payload; + }, + setShouldShowBrush: (state, action: PayloadAction) => { + state[state.currentCanvas].shouldShowBrush = action.payload; + }, + setCursorPosition: (state, action: PayloadAction) => { + state[state.currentCanvas].cursorPosition = action.payload; + }, + clearImageToInpaint: (state) => { + state.inpainting.imageToInpaint = undefined; + }, + + setImageToOutpaint: (state, action: PayloadAction) => { + const { width: canvasWidth, height: canvasHeight } = + state.outpainting.stageDimensions; + const { width, height } = state.outpainting.boundingBoxDimensions; + const { x, y } = state.outpainting.boundingBoxCoordinates; + + const maxWidth = Math.min(action.payload.width, canvasWidth); + const maxHeight = Math.min(action.payload.height, canvasHeight); + + const newCoordinates: Vector2d = { x, y }; + const newDimensions: Dimensions = { width, height }; + + if (width + x > maxWidth) { + // Bounding box at least needs to be translated + if (width > maxWidth) { + // Bounding box also needs to be resized + newDimensions.width = roundDownToMultiple(maxWidth, 64); + } + newCoordinates.x = maxWidth - newDimensions.width; + } + + if (height + y > maxHeight) { + // Bounding box at least needs to be translated + if (height > maxHeight) { + // Bounding box also needs to be resized + newDimensions.height = roundDownToMultiple(maxHeight, 64); + } + newCoordinates.y = maxHeight - newDimensions.height; + } + + state.outpainting.boundingBoxDimensions = newDimensions; + state.outpainting.boundingBoxCoordinates = newCoordinates; + + // state.outpainting.imageToInpaint = action.payload; + state.outpainting.objects = [ + { + kind: 'image', + layer: 'base', + x: 0, + y: 0, + image: action.payload, + }, + ]; + state.doesCanvasNeedScaling = true; + }, + setImageToInpaint: (state, action: PayloadAction) => { + const { width: canvasWidth, height: canvasHeight } = + state.inpainting.stageDimensions; + const { width, height } = state.inpainting.boundingBoxDimensions; + const { x, y } = state.inpainting.boundingBoxCoordinates; + + const maxWidth = Math.min(action.payload.width, canvasWidth); + const maxHeight = Math.min(action.payload.height, canvasHeight); + + const newCoordinates: Vector2d = { x, y }; + const newDimensions: Dimensions = { width, height }; + + if (width + x > maxWidth) { + // Bounding box at least needs to be translated + if (width > maxWidth) { + // Bounding box also needs to be resized + newDimensions.width = roundDownToMultiple(maxWidth, 64); + } + newCoordinates.x = maxWidth - newDimensions.width; + } + + if (height + y > maxHeight) { + // Bounding box at least needs to be translated + if (height > maxHeight) { + // Bounding box also needs to be resized + newDimensions.height = roundDownToMultiple(maxHeight, 64); + } + newCoordinates.y = maxHeight - newDimensions.height; + } + + state.inpainting.boundingBoxDimensions = newDimensions; + state.inpainting.boundingBoxCoordinates = newCoordinates; + + state.inpainting.imageToInpaint = action.payload; + state.doesCanvasNeedScaling = true; + }, + setStageDimensions: (state, action: PayloadAction) => { + state[state.currentCanvas].stageDimensions = action.payload; + + const { width: canvasWidth, height: canvasHeight } = action.payload; + + const { width: boundingBoxWidth, height: boundingBoxHeight } = + state[state.currentCanvas].boundingBoxDimensions; + + const newBoundingBoxWidth = roundDownToMultiple( + _.clamp( + boundingBoxWidth, + 64, + canvasWidth / state[state.currentCanvas].stageScale + ), + 64 + ); + const newBoundingBoxHeight = roundDownToMultiple( + _.clamp( + boundingBoxHeight, + 64, + canvasHeight / state[state.currentCanvas].stageScale + ), + 64 + ); + + state[state.currentCanvas].boundingBoxDimensions = { + width: newBoundingBoxWidth, + height: newBoundingBoxHeight, + }; + }, + setBoundingBoxDimensions: (state, action: PayloadAction) => { + state[state.currentCanvas].boundingBoxDimensions = action.payload; + const { width: boundingBoxWidth, height: boundingBoxHeight } = + action.payload; + const { x: boundingBoxX, y: boundingBoxY } = + state[state.currentCanvas].boundingBoxCoordinates; + const { width: canvasWidth, height: canvasHeight } = + state[state.currentCanvas].stageDimensions; + + const scaledCanvasWidth = + canvasWidth / state[state.currentCanvas].stageScale; + const scaledCanvasHeight = + canvasHeight / state[state.currentCanvas].stageScale; + + const roundedCanvasWidth = roundDownToMultiple(scaledCanvasWidth, 64); + const roundedCanvasHeight = roundDownToMultiple(scaledCanvasHeight, 64); + + const roundedBoundingBoxWidth = roundDownToMultiple(boundingBoxWidth, 64); + const roundedBoundingBoxHeight = roundDownToMultiple( + boundingBoxHeight, + 64 + ); + + const overflowX = boundingBoxX + boundingBoxWidth - scaledCanvasWidth; + const overflowY = boundingBoxY + boundingBoxHeight - scaledCanvasHeight; + + const newBoundingBoxWidth = _.clamp( + roundedBoundingBoxWidth, + 64, + roundedCanvasWidth + ); + + const newBoundingBoxHeight = _.clamp( + roundedBoundingBoxHeight, + 64, + roundedCanvasHeight + ); + + const overflowCorrectedX = + overflowX > 0 ? boundingBoxX - overflowX : boundingBoxX; + + const overflowCorrectedY = + overflowY > 0 ? boundingBoxY - overflowY : boundingBoxY; + + const clampedX = _.clamp( + overflowCorrectedX, + state[state.currentCanvas].stageCoordinates.x, + roundedCanvasWidth - newBoundingBoxWidth + ); + + const clampedY = _.clamp( + overflowCorrectedY, + state[state.currentCanvas].stageCoordinates.y, + roundedCanvasHeight - newBoundingBoxHeight + ); + + state[state.currentCanvas].boundingBoxDimensions = { + width: newBoundingBoxWidth, + height: newBoundingBoxHeight, + }; + + state[state.currentCanvas].boundingBoxCoordinates = { + x: clampedX, + y: clampedY, + }; + }, + setBoundingBoxCoordinates: (state, action: PayloadAction) => { + state[state.currentCanvas].boundingBoxCoordinates = action.payload; + }, + setStageCoordinates: (state, action: PayloadAction) => { + state[state.currentCanvas].stageCoordinates = action.payload; + }, + setBoundingBoxPreviewFill: (state, action: PayloadAction) => { + state[state.currentCanvas].boundingBoxPreviewFill = action.payload; + }, + setDoesCanvasNeedScaling: (state, action: PayloadAction) => { + state.doesCanvasNeedScaling = action.payload; + }, + setStageScale: (state, action: PayloadAction) => { + state[state.currentCanvas].stageScale = action.payload; + state.doesCanvasNeedScaling = false; + }, + setShouldDarkenOutsideBoundingBox: ( + state, + action: PayloadAction + ) => { + state[state.currentCanvas].shouldDarkenOutsideBoundingBox = + action.payload; + }, + setIsDrawing: (state, action: PayloadAction) => { + state[state.currentCanvas].isDrawing = action.payload; + }, + setClearBrushHistory: (state) => { + state[state.currentCanvas].pastObjects = []; + state[state.currentCanvas].futureObjects = []; + }, + setShouldUseInpaintReplace: (state, action: PayloadAction) => { + state[state.currentCanvas].shouldUseInpaintReplace = action.payload; + }, + setInpaintReplace: (state, action: PayloadAction) => { + state[state.currentCanvas].inpaintReplace = action.payload; + }, + setShouldLockBoundingBox: (state, action: PayloadAction) => { + state[state.currentCanvas].shouldLockBoundingBox = action.payload; + }, + toggleShouldLockBoundingBox: (state) => { + state[state.currentCanvas].shouldLockBoundingBox = + !state[state.currentCanvas].shouldLockBoundingBox; + }, + setShouldShowBoundingBox: (state, action: PayloadAction) => { + state[state.currentCanvas].shouldShowBoundingBox = action.payload; + }, + setIsTransformingBoundingBox: (state, action: PayloadAction) => { + state[state.currentCanvas].isTransformingBoundingBox = action.payload; + }, + setIsMovingBoundingBox: (state, action: PayloadAction) => { + state[state.currentCanvas].isMovingBoundingBox = action.payload; + }, + setIsMouseOverBoundingBox: (state, action: PayloadAction) => { + state[state.currentCanvas].isMouseOverBoundingBox = action.payload; + }, + setIsMoveBoundingBoxKeyHeld: (state, action: PayloadAction) => { + state[state.currentCanvas].isMoveBoundingBoxKeyHeld = action.payload; + }, + setIsMoveStageKeyHeld: (state, action: PayloadAction) => { + state[state.currentCanvas].isMoveStageKeyHeld = action.payload; + }, + setCurrentCanvas: (state, action: PayloadAction) => { + state.currentCanvas = action.payload; + }, + addImageToOutpaintingSesion: ( + state, + action: PayloadAction<{ + boundingBox: IRect; + image: InvokeAI.Image; + }> + ) => { + const { boundingBox, image } = action.payload; + if (!boundingBox || !image) return; + + const { x, y } = boundingBox; + + state.outpainting.pastObjects.push([...state.outpainting.objects]); + state.outpainting.futureObjects = []; + + state.outpainting.objects.push({ + kind: 'image', + layer: 'base', + x, + y, + image, + }); + }, + addLine: (state, action: PayloadAction) => { + const { tool, layer, brushColor, brushSize, eraserSize } = + state[state.currentCanvas]; + + if (tool === 'move') return; + + state[state.currentCanvas].pastObjects.push( + state[state.currentCanvas].objects + ); + + state[state.currentCanvas].objects.push({ + kind: 'line', + layer, + tool, + strokeWidth: tool === 'brush' ? brushSize / 2 : eraserSize / 2, + points: action.payload, + ...(layer === 'base' && tool === 'brush' && { color: brushColor }), + }); + + state[state.currentCanvas].futureObjects = []; + }, + addPointToCurrentLine: (state, action: PayloadAction) => { + const lastLine = + state[state.currentCanvas].objects.findLast(isCanvasAnyLine); + + if (!lastLine) return; + + lastLine.points.push(...action.payload); + }, + undo: (state) => { + if (state.outpainting.objects.length === 0) return; + + const newObjects = state.outpainting.pastObjects.pop(); + if (!newObjects) return; + state.outpainting.futureObjects.unshift(state.outpainting.objects); + state.outpainting.objects = newObjects; + }, + redo: (state) => { + if (state.outpainting.futureObjects.length === 0) return; + const newObjects = state.outpainting.futureObjects.shift(); + if (!newObjects) return; + state.outpainting.pastObjects.push(state.outpainting.objects); + state.outpainting.objects = newObjects; + }, + setShouldShowGrid: (state, action: PayloadAction) => { + state.outpainting.shouldShowGrid = action.payload; + }, + setIsMovingStage: (state, action: PayloadAction) => { + state[state.currentCanvas].isMovingStage = action.payload; + }, + setShouldSnapToGrid: (state, action: PayloadAction) => { + state.outpainting.shouldSnapToGrid = action.payload; + }, + setShouldAutoSave: (state, action: PayloadAction) => { + state.outpainting.shouldAutoSave = action.payload; + }, + setShouldShowIntermediates: (state, action: PayloadAction) => { + state[state.currentCanvas].shouldShowIntermediates = action.payload; + }, + resetCanvas: (state) => { + state[state.currentCanvas].pastObjects.push( + state[state.currentCanvas].objects + ); + + state[state.currentCanvas].objects = []; + state[state.currentCanvas].futureObjects = []; + }, + }, + extraReducers: (builder) => { + builder.addCase(uploadOutpaintingMergedImage.fulfilled, (state, action) => { + if (!action.payload) return; + state.outpainting.pastObjects.push([...state.outpainting.objects]); + state.outpainting.futureObjects = []; + + state.outpainting.objects = [ + { + kind: 'image', + layer: 'base', + ...action.payload, + }, + ]; + }); + }, +}); + +export const { + setTool, + setLayer, + setBrushColor, + setBrushSize, + setEraserSize, + addLine, + addPointToCurrentLine, + setShouldInvertMask, + setIsMaskEnabled, + setShouldShowCheckboardTransparency, + setShouldShowBrushPreview, + setMaskColor, + clearMask, + clearImageToInpaint, + undo, + redo, + setCursorPosition, + setStageDimensions, + setImageToInpaint, + setImageToOutpaint, + setBoundingBoxDimensions, + setBoundingBoxCoordinates, + setBoundingBoxPreviewFill, + setDoesCanvasNeedScaling, + setStageScale, + toggleTool, + setShouldShowBoundingBox, + setShouldDarkenOutsideBoundingBox, + setIsDrawing, + setShouldShowBrush, + setClearBrushHistory, + setShouldUseInpaintReplace, + setInpaintReplace, + setShouldLockBoundingBox, + toggleShouldLockBoundingBox, + setIsMovingBoundingBox, + setIsTransformingBoundingBox, + setIsMouseOverBoundingBox, + setIsMoveBoundingBoxKeyHeld, + setIsMoveStageKeyHeld, + setStageCoordinates, + setCurrentCanvas, + addImageToOutpaintingSesion, + resetCanvas, + setShouldShowGrid, + setShouldSnapToGrid, + setShouldAutoSave, + setShouldShowIntermediates, + setIsMovingStage, +} = canvasSlice.actions; + +export default canvasSlice.reducer; + +export const uploadOutpaintingMergedImage = createAsyncThunk( + 'canvas/uploadOutpaintingMergedImage', + async ( + canvasImageLayerRef: MutableRefObject, + thunkAPI + ) => { + const { getState } = thunkAPI; + + const state = getState() as RootState; + const stageScale = state.canvas.outpainting.stageScale; + + if (!canvasImageLayerRef.current) return; + const tempScale = canvasImageLayerRef.current.scale(); + + const { x: relativeX, y: relativeY } = + canvasImageLayerRef.current.getClientRect({ + relativeTo: canvasImageLayerRef.current.getParent(), + }); + + canvasImageLayerRef.current.scale({ + x: 1 / stageScale, + y: 1 / stageScale, + }); + + const clientRect = canvasImageLayerRef.current.getClientRect(); + + const imageDataURL = canvasImageLayerRef.current.toDataURL(clientRect); + + canvasImageLayerRef.current.scale(tempScale); + + if (!imageDataURL) return; + + const response = await fetch(window.location.origin + '/upload', { + method: 'POST', + headers: { + 'Content-Type': 'application/json', + }, + body: JSON.stringify({ + dataURL: imageDataURL, + name: 'outpaintingmerge.png', + }), + }); + + const data = (await response.json()) as InvokeAI.ImageUploadResponse; + + // eslint-disable-next-line @typescript-eslint/no-unused-vars + const { destination, ...rest } = data; + const image = { + uuid: uuidv4(), + ...rest, + }; + + return { + image, + x: relativeX, + y: relativeY, + }; + } +); + +export const currentCanvasSelector = (state: RootState): BaseCanvasState => + state.canvas[state.canvas.currentCanvas]; + +export const outpaintingCanvasSelector = ( + state: RootState +): OutpaintingCanvasState => state.canvas.outpainting; + +export const inpaintingCanvasSelector = ( + state: RootState +): InpaintingCanvasState => state.canvas.inpainting; + +export const baseCanvasImageSelector = createSelector( + [(state: RootState) => state.canvas, activeTabNameSelector], + (canvas: CanvasState, activeTabName) => { + if (activeTabName === 'inpainting') { + return canvas.inpainting.imageToInpaint; + } else if (activeTabName === 'outpainting') { + const firstImageObject = canvas.outpainting.objects.find( + (obj) => obj.kind === 'image' + ); + if (firstImageObject && firstImageObject.kind === 'image') { + return firstImageObject.image; + } + } + } +); diff --git a/frontend/src/features/canvas/hooks/useCanvasDragMove.ts b/frontend/src/features/canvas/hooks/useCanvasDragMove.ts new file mode 100644 index 0000000000..dedc9f3dc9 --- /dev/null +++ b/frontend/src/features/canvas/hooks/useCanvasDragMove.ts @@ -0,0 +1,49 @@ +import { createSelector } from '@reduxjs/toolkit'; +import { useAppDispatch, useAppSelector } from 'app/store'; +import { activeTabNameSelector } from 'features/options/optionsSelectors'; +import { KonvaEventObject } from 'konva/lib/Node'; +import _ from 'lodash'; +import { useCallback } from 'react'; +import { + currentCanvasSelector, + setIsMovingStage, + setStageCoordinates, +} from '../canvasSlice'; + +const selector = createSelector( + [currentCanvasSelector, activeTabNameSelector], + (canvas, activeTabName) => { + const { tool } = canvas; + return { + tool, + + activeTabName, + }; + }, + { memoizeOptions: { resultEqualityCheck: _.isEqual } } +); + +const useCanvasDrag = () => { + const dispatch = useAppDispatch(); + const { tool, activeTabName } = useAppSelector(selector); + + return { + handleDragStart: useCallback(() => { + if (tool !== 'move' || activeTabName !== 'outpainting') return; + dispatch(setIsMovingStage(true)); + }, [activeTabName, dispatch, tool]), + handleDragMove: useCallback( + (e: KonvaEventObject) => { + if (tool !== 'move' || activeTabName !== 'outpainting') return; + dispatch(setStageCoordinates(e.target.getPosition())); + }, + [activeTabName, dispatch, tool] + ), + handleDragEnd: useCallback(() => { + if (tool !== 'move' || activeTabName !== 'outpainting') return; + dispatch(setIsMovingStage(false)); + }, [activeTabName, dispatch, tool]), + }; +}; + +export default useCanvasDrag; diff --git a/frontend/src/features/canvas/hooks/useCanvasHotkeys.ts b/frontend/src/features/canvas/hooks/useCanvasHotkeys.ts new file mode 100644 index 0000000000..0a4339425b --- /dev/null +++ b/frontend/src/features/canvas/hooks/useCanvasHotkeys.ts @@ -0,0 +1,111 @@ +import { createSelector } from '@reduxjs/toolkit'; +import _ from 'lodash'; +import { useHotkeys } from 'react-hotkeys-hook'; +import { activeTabNameSelector } from 'features/options/optionsSelectors'; +import { OptionsState } from 'features/options/optionsSlice'; +import { + CanvasTool, + setShouldShowBoundingBox, + setTool, + toggleShouldLockBoundingBox, +} from 'features/canvas/canvasSlice'; +import { RootState, useAppDispatch, useAppSelector } from 'app/store'; +import { currentCanvasSelector, GenericCanvasState } from '../canvasSlice'; +import { useRef } from 'react'; + +const inpaintingCanvasHotkeysSelector = createSelector( + [ + (state: RootState) => state.options, + currentCanvasSelector, + activeTabNameSelector, + ], + (options: OptionsState, currentCanvas: GenericCanvasState, activeTabName) => { + const { + isMaskEnabled, + cursorPosition, + shouldLockBoundingBox, + shouldShowBoundingBox, + tool, + } = currentCanvas; + + return { + activeTabName, + isMaskEnabled, + isCursorOnCanvas: Boolean(cursorPosition), + shouldLockBoundingBox, + shouldShowBoundingBox, + tool, + }; + }, + { + memoizeOptions: { + resultEqualityCheck: _.isEqual, + }, + } +); + +const useInpaintingCanvasHotkeys = () => { + const dispatch = useAppDispatch(); + const { isMaskEnabled, activeTabName, shouldShowBoundingBox, tool } = + useAppSelector(inpaintingCanvasHotkeysSelector); + + const previousToolRef = useRef(null); + // Toggle lock bounding box + useHotkeys( + 'shift+w', + (e: KeyboardEvent) => { + e.preventDefault(); + dispatch(toggleShouldLockBoundingBox()); + }, + { + enabled: true, + }, + [activeTabName] + ); + + useHotkeys( + 'shift+h', + (e: KeyboardEvent) => { + e.preventDefault(); + dispatch(setShouldShowBoundingBox(!shouldShowBoundingBox)); + }, + { + enabled: true, + }, + [activeTabName, shouldShowBoundingBox] + ); + + useHotkeys( + ['space'], + (e: KeyboardEvent) => { + if (e.repeat) return; + + if (tool !== 'move') { + previousToolRef.current = tool; + dispatch(setTool('move')); + } + }, + { keyup: false, keydown: true }, + [tool, previousToolRef] + ); + + useHotkeys( + ['space'], + (e: KeyboardEvent) => { + if (e.repeat) return; + + if ( + tool === 'move' && + previousToolRef.current && + previousToolRef.current !== 'move' + ) { + dispatch(setTool(previousToolRef.current)); + previousToolRef.current = 'move'; + } + }, + { keyup: true, keydown: false }, + [tool, previousToolRef] + ); +}; + +export default useInpaintingCanvasHotkeys; diff --git a/frontend/src/features/canvas/hooks/useCanvasMouseDown.ts b/frontend/src/features/canvas/hooks/useCanvasMouseDown.ts new file mode 100644 index 0000000000..8750db005a --- /dev/null +++ b/frontend/src/features/canvas/hooks/useCanvasMouseDown.ts @@ -0,0 +1,56 @@ +import { createSelector } from '@reduxjs/toolkit'; +import { useAppDispatch, useAppSelector } from 'app/store'; +import { activeTabNameSelector } from 'features/options/optionsSelectors'; +import Konva from 'konva'; +import { KonvaEventObject } from 'konva/lib/Node'; +import _ from 'lodash'; +import { MutableRefObject, useCallback } from 'react'; +import { + addLine, + currentCanvasSelector, + setIsDrawing, + setIsMovingStage, +} from '../canvasSlice'; +import getScaledCursorPosition from '../util/getScaledCursorPosition'; + +const selector = createSelector( + [activeTabNameSelector, currentCanvasSelector], + (activeTabName, currentCanvas) => { + const { tool } = currentCanvas; + return { + tool, + activeTabName, + }; + }, + { memoizeOptions: { resultEqualityCheck: _.isEqual } } +); + +const useCanvasMouseDown = (stageRef: MutableRefObject) => { + const dispatch = useAppDispatch(); + const { tool } = useAppSelector(selector); + + return useCallback( + (e: KonvaEventObject) => { + if (!stageRef.current) return; + + if (tool === 'move') { + dispatch(setIsMovingStage(true)); + return; + } + + const scaledCursorPosition = getScaledCursorPosition(stageRef.current); + + if (!scaledCursorPosition) return; + + e.evt.preventDefault(); + + dispatch(setIsDrawing(true)); + + // Add a new line starting from the current cursor position. + dispatch(addLine([scaledCursorPosition.x, scaledCursorPosition.y])); + }, + [stageRef, dispatch, tool] + ); +}; + +export default useCanvasMouseDown; diff --git a/frontend/src/features/canvas/hooks/useCanvasMouseEnter.ts b/frontend/src/features/canvas/hooks/useCanvasMouseEnter.ts new file mode 100644 index 0000000000..73231f911e --- /dev/null +++ b/frontend/src/features/canvas/hooks/useCanvasMouseEnter.ts @@ -0,0 +1,48 @@ +import { createSelector } from '@reduxjs/toolkit'; +import { useAppDispatch, useAppSelector } from 'app/store'; +import { activeTabNameSelector } from 'features/options/optionsSelectors'; +import Konva from 'konva'; +import { KonvaEventObject } from 'konva/lib/Node'; +import _ from 'lodash'; +import { MutableRefObject, useCallback } from 'react'; +import { addLine, currentCanvasSelector, setIsDrawing } from '../canvasSlice'; +import getScaledCursorPosition from '../util/getScaledCursorPosition'; + +const selector = createSelector( + [activeTabNameSelector, currentCanvasSelector], + (activeTabName, currentCanvas) => { + const { tool } = currentCanvas; + return { + tool, + activeTabName, + }; + }, + { memoizeOptions: { resultEqualityCheck: _.isEqual } } +); + +const useCanvasMouseEnter = ( + stageRef: MutableRefObject +) => { + const dispatch = useAppDispatch(); + const { tool } = useAppSelector(selector); + + return useCallback( + (e: KonvaEventObject) => { + if (e.evt.buttons !== 1) return; + + if (!stageRef.current) return; + + const scaledCursorPosition = getScaledCursorPosition(stageRef.current); + + if (!scaledCursorPosition || tool === 'move') return; + + dispatch(setIsDrawing(true)); + + // Add a new line starting from the current cursor position. + dispatch(addLine([scaledCursorPosition.x, scaledCursorPosition.y])); + }, + [stageRef, tool, dispatch] + ); +}; + +export default useCanvasMouseEnter; diff --git a/frontend/src/features/canvas/hooks/useCanvasMouseMove.ts b/frontend/src/features/canvas/hooks/useCanvasMouseMove.ts new file mode 100644 index 0000000000..aa4cbd9557 --- /dev/null +++ b/frontend/src/features/canvas/hooks/useCanvasMouseMove.ts @@ -0,0 +1,64 @@ +import { createSelector } from '@reduxjs/toolkit'; +import { useAppDispatch, useAppSelector } from 'app/store'; +import { activeTabNameSelector } from 'features/options/optionsSelectors'; +import Konva from 'konva'; +import { Vector2d } from 'konva/lib/types'; +import _ from 'lodash'; +import { MutableRefObject, useCallback } from 'react'; +import { + addPointToCurrentLine, + currentCanvasSelector, + GenericCanvasState, + setCursorPosition, +} from '../canvasSlice'; +import getScaledCursorPosition from '../util/getScaledCursorPosition'; + +const selector = createSelector( + [activeTabNameSelector, currentCanvasSelector], + (activeTabName, canvas: GenericCanvasState) => { + const { tool, isDrawing } = canvas; + return { + tool, + isDrawing, + activeTabName, + }; + }, + { memoizeOptions: { resultEqualityCheck: _.isEqual } } +); + +const useCanvasMouseMove = ( + stageRef: MutableRefObject, + didMouseMoveRef: MutableRefObject, + lastCursorPositionRef: MutableRefObject +) => { + const dispatch = useAppDispatch(); + const { isDrawing, tool } = useAppSelector(selector); + + return useCallback(() => { + if (!stageRef.current) return; + + const scaledCursorPosition = getScaledCursorPosition(stageRef.current); + + if (!scaledCursorPosition) return; + + dispatch(setCursorPosition(scaledCursorPosition)); + + lastCursorPositionRef.current = scaledCursorPosition; + + if (!isDrawing || tool === 'move') return; + + didMouseMoveRef.current = true; + dispatch( + addPointToCurrentLine([scaledCursorPosition.x, scaledCursorPosition.y]) + ); + }, [ + didMouseMoveRef, + dispatch, + isDrawing, + lastCursorPositionRef, + stageRef, + tool, + ]); +}; + +export default useCanvasMouseMove; diff --git a/frontend/src/features/canvas/hooks/useCanvasMouseOut.ts b/frontend/src/features/canvas/hooks/useCanvasMouseOut.ts new file mode 100644 index 0000000000..2a29404865 --- /dev/null +++ b/frontend/src/features/canvas/hooks/useCanvasMouseOut.ts @@ -0,0 +1,15 @@ +import { useAppDispatch } from 'app/store'; +import _ from 'lodash'; +import { useCallback } from 'react'; +import { setCursorPosition, setIsDrawing } from '../canvasSlice'; + +const useCanvasMouseOut = () => { + const dispatch = useAppDispatch(); + + return useCallback(() => { + dispatch(setCursorPosition(null)); + dispatch(setIsDrawing(false)); + }, [dispatch]); +}; + +export default useCanvasMouseOut; diff --git a/frontend/src/features/canvas/hooks/useCanvasMouseUp.ts b/frontend/src/features/canvas/hooks/useCanvasMouseUp.ts new file mode 100644 index 0000000000..685d43b3e2 --- /dev/null +++ b/frontend/src/features/canvas/hooks/useCanvasMouseUp.ts @@ -0,0 +1,64 @@ +import { createSelector } from '@reduxjs/toolkit'; +import { useAppDispatch, useAppSelector } from 'app/store'; +import { activeTabNameSelector } from 'features/options/optionsSelectors'; +import Konva from 'konva'; +import _ from 'lodash'; +import { MutableRefObject, useCallback } from 'react'; +import { + // addPointToCurrentEraserLine, + addPointToCurrentLine, + currentCanvasSelector, + GenericCanvasState, + setIsDrawing, + setIsMovingStage, +} from '../canvasSlice'; +import getScaledCursorPosition from '../util/getScaledCursorPosition'; + +const selector = createSelector( + [activeTabNameSelector, currentCanvasSelector], + (activeTabName, canvas: GenericCanvasState) => { + const { tool, isDrawing } = canvas; + return { + tool, + isDrawing, + activeTabName, + }; + }, + { memoizeOptions: { resultEqualityCheck: _.isEqual } } +); + +const useCanvasMouseUp = ( + stageRef: MutableRefObject, + didMouseMoveRef: MutableRefObject +) => { + const dispatch = useAppDispatch(); + const { tool, isDrawing } = useAppSelector(selector); + + return useCallback(() => { + if (tool === 'move') { + dispatch(setIsMovingStage(false)); + return; + } + + if (!didMouseMoveRef.current && isDrawing && stageRef.current) { + const scaledCursorPosition = getScaledCursorPosition(stageRef.current); + + if (!scaledCursorPosition) return; + + /** + * Extend the current line. + * In this case, the mouse didn't move, so we append the same point to + * the line's existing points. This allows the line to render as a circle + * centered on that point. + */ + dispatch( + addPointToCurrentLine([scaledCursorPosition.x, scaledCursorPosition.y]) + ); + } else { + didMouseMoveRef.current = false; + } + dispatch(setIsDrawing(false)); + }, [didMouseMoveRef, dispatch, isDrawing, stageRef, tool]); +}; + +export default useCanvasMouseUp; diff --git a/frontend/src/features/canvas/hooks/useCanvasZoom.ts b/frontend/src/features/canvas/hooks/useCanvasZoom.ts new file mode 100644 index 0000000000..857b023328 --- /dev/null +++ b/frontend/src/features/canvas/hooks/useCanvasZoom.ts @@ -0,0 +1,83 @@ +import { createSelector } from '@reduxjs/toolkit'; +import { useAppDispatch, useAppSelector } from 'app/store'; +import { activeTabNameSelector } from 'features/options/optionsSelectors'; +import Konva from 'konva'; +import { KonvaEventObject } from 'konva/lib/Node'; +import _ from 'lodash'; +import { MutableRefObject, useCallback } from 'react'; +import { + currentCanvasSelector, + GenericCanvasState, + setStageCoordinates, + setStageScale, +} from '../canvasSlice'; +import { + CANVAS_SCALE_BY, + MAX_CANVAS_SCALE, + MIN_CANVAS_SCALE, +} from '../util/constants'; + +const selector = createSelector( + [activeTabNameSelector, currentCanvasSelector], + (activeTabName, canvas: GenericCanvasState) => { + const { isMoveStageKeyHeld, stageScale } = canvas; + return { + isMoveStageKeyHeld, + stageScale, + activeTabName, + }; + }, + { memoizeOptions: { resultEqualityCheck: _.isEqual } } +); + +const useCanvasWheel = (stageRef: MutableRefObject) => { + const dispatch = useAppDispatch(); + const { isMoveStageKeyHeld, stageScale, activeTabName } = + useAppSelector(selector); + + return useCallback( + (e: KonvaEventObject) => { + // stop default scrolling + if (activeTabName !== 'outpainting') return; + + e.evt.preventDefault(); + + // const oldScale = stageRef.current.scaleX(); + if (!stageRef.current || isMoveStageKeyHeld) return; + + const cursorPos = stageRef.current.getPointerPosition(); + + if (!cursorPos) return; + + const mousePointTo = { + x: (cursorPos.x - stageRef.current.x()) / stageScale, + y: (cursorPos.y - stageRef.current.y()) / stageScale, + }; + + let delta = e.evt.deltaY; + + // when we zoom on trackpad, e.evt.ctrlKey is true + // in that case lets revert direction + if (e.evt.ctrlKey) { + delta = -delta; + } + + const newScale = _.clamp( + stageScale * CANVAS_SCALE_BY ** delta, + MIN_CANVAS_SCALE, + MAX_CANVAS_SCALE + ); + + const newPos = { + x: cursorPos.x - mousePointTo.x * newScale, + y: cursorPos.y - mousePointTo.y * newScale, + }; + + dispatch(setStageScale(newScale)); + dispatch(setStageCoordinates(newPos)); + }, + [activeTabName, dispatch, isMoveStageKeyHeld, stageRef, stageScale] + ); +}; + +export default useCanvasWheel; diff --git a/frontend/src/features/canvas/hooks/useUnscaleCanvasValue.ts b/frontend/src/features/canvas/hooks/useUnscaleCanvasValue.ts new file mode 100644 index 0000000000..f2066c5f0b --- /dev/null +++ b/frontend/src/features/canvas/hooks/useUnscaleCanvasValue.ts @@ -0,0 +1,23 @@ +import { createSelector } from '@reduxjs/toolkit'; +import { useAppSelector } from 'app/store'; +import _ from 'lodash'; +import { currentCanvasSelector, GenericCanvasState } from '../canvasSlice'; + +const selector = createSelector( + [currentCanvasSelector], + (currentCanvas: GenericCanvasState) => { + return currentCanvas.stageScale; + }, + { + memoizeOptions: { + resultEqualityCheck: _.isEqual, + }, + } +); + +const useUnscaleCanvasValue = () => { + const stageScale = useAppSelector(selector); + return (value: number) => value / stageScale; +}; + +export default useUnscaleCanvasValue; diff --git a/frontend/src/features/tabs/Inpainting/util/colorToString.ts b/frontend/src/features/canvas/util/colorToString.ts similarity index 100% rename from frontend/src/features/tabs/Inpainting/util/colorToString.ts rename to frontend/src/features/canvas/util/colorToString.ts diff --git a/frontend/src/features/tabs/Inpainting/util/constants.ts b/frontend/src/features/canvas/util/constants.ts similarity index 68% rename from frontend/src/features/tabs/Inpainting/util/constants.ts rename to frontend/src/features/canvas/util/constants.ts index 85fc3eb97c..59a9a46d71 100644 --- a/frontend/src/features/tabs/Inpainting/util/constants.ts +++ b/frontend/src/features/canvas/util/constants.ts @@ -7,4 +7,8 @@ export const MARCHING_ANTS_SPEED = 30; // bounding box anchor size export const TRANSFORMER_ANCHOR_SIZE = 15; +export const CANVAS_SCALE_BY = 0.999; +export const MIN_CANVAS_SCALE = 0.1 + +export const MAX_CANVAS_SCALE = 20 \ No newline at end of file diff --git a/frontend/src/features/canvas/util/generateMask.ts b/frontend/src/features/canvas/util/generateMask.ts new file mode 100644 index 0000000000..7a924b555b --- /dev/null +++ b/frontend/src/features/canvas/util/generateMask.ts @@ -0,0 +1,64 @@ +import Konva from 'konva'; +import { IRect } from 'konva/lib/types'; +import { CanvasMaskLine } from 'features/canvas/canvasSlice'; + +/** + * Generating a mask image from InpaintingCanvas.tsx is not as simple + * as calling toDataURL() on the canvas, because the mask may be represented + * by colored lines or transparency, or the user may have inverted the mask + * display. + * + * So we need to regenerate the mask image by creating an offscreen canvas, + * drawing the mask and compositing everything correctly to output a valid + * mask image. + */ +const generateMask = (lines: CanvasMaskLine[], boundingBox: IRect): string => { + // create an offscreen canvas and add the mask to it + const { width, height } = boundingBox; + + const offscreenContainer = document.createElement('div'); + + const stage = new Konva.Stage({ + container: offscreenContainer, + width: width, + height: height, + }); + + const baseLayer = new Konva.Layer(); + const maskLayer = new Konva.Layer(); + + // composite the image onto the mask layer + baseLayer.add( + new Konva.Rect({ + ...boundingBox, + fill: 'white', + }) + ); + + lines.forEach((line) => + maskLayer.add( + new Konva.Line({ + points: line.points, + stroke: 'black', + strokeWidth: line.strokeWidth * 2, + tension: 0, + lineCap: 'round', + lineJoin: 'round', + shadowForStrokeEnabled: false, + globalCompositeOperation: + line.tool === 'brush' ? 'source-over' : 'destination-out', + }) + ) + ); + + stage.add(baseLayer); + stage.add(maskLayer); + + const dataURL = stage.toDataURL({ ...boundingBox }); + + offscreenContainer.remove(); + + return dataURL; +}; + +export default generateMask; diff --git a/frontend/src/features/tabs/Inpainting/util/getScaledCursorPosition.ts b/frontend/src/features/canvas/util/getScaledCursorPosition.ts similarity index 100% rename from frontend/src/features/tabs/Inpainting/util/getScaledCursorPosition.ts rename to frontend/src/features/canvas/util/getScaledCursorPosition.ts diff --git a/frontend/src/features/gallery/CurrentImageButtons.scss b/frontend/src/features/gallery/CurrentImageButtons.scss index 982fcc4867..a48454bb8c 100644 --- a/frontend/src/features/gallery/CurrentImageButtons.scss +++ b/frontend/src/features/gallery/CurrentImageButtons.scss @@ -13,11 +13,18 @@ max-width: 25rem; } + .current-image-send-to-popover { + .invokeai__button { + place-content: start; + } + } + .chakra-popover__popper { z-index: 11; } .delete-image-btn { + background-color: var(--btn-base-color); svg { fill: var(--btn-delete-image); } diff --git a/frontend/src/features/gallery/CurrentImageButtons.tsx b/frontend/src/features/gallery/CurrentImageButtons.tsx index b95e16dda9..3a21f4b0b1 100644 --- a/frontend/src/features/gallery/CurrentImageButtons.tsx +++ b/frontend/src/features/gallery/CurrentImageButtons.tsx @@ -1,24 +1,25 @@ import { createSelector } from '@reduxjs/toolkit'; import { isEqual } from 'lodash'; -import { useAppDispatch, useAppSelector } from '../../app/store'; -import { RootState } from '../../app/store'; +import { useAppDispatch, useAppSelector } from 'app/store'; +import { RootState } from 'app/store'; import { OptionsState, setActiveTab, setAllParameters, setInitialImage, + setIsLightBoxOpen, setPrompt, setSeed, setShouldShowImageDetails, -} from '../options/optionsSlice'; +} from 'features/options/optionsSlice'; import DeleteImageModal from './DeleteImageModal'; -import { SystemState } from '../system/systemSlice'; -import IAIButton from '../../common/components/IAIButton'; -import { runESRGAN, runFacetool } from '../../app/socketio/actions'; -import IAIIconButton from '../../common/components/IAIIconButton'; -import UpscaleOptions from '../options/AdvancedOptions/Upscale/UpscaleOptions'; -import FaceRestoreOptions from '../options/AdvancedOptions/FaceRestore/FaceRestoreOptions'; +import { SystemState } from 'features/system/systemSlice'; +import IAIButton from 'common/components/IAIButton'; +import { runESRGAN, runFacetool } from 'app/socketio/actions'; +import IAIIconButton from 'common/components/IAIIconButton'; +import UpscaleOptions from 'features/options/AdvancedOptions/Upscale/UpscaleOptions'; +import FaceRestoreOptions from 'features/options/AdvancedOptions/FaceRestore/FaceRestoreOptions'; import { useHotkeys } from 'react-hotkeys-hook'; import { ButtonGroup, Link, useClipboard, useToast } from '@chakra-ui/react'; import { @@ -36,11 +37,12 @@ import { } from 'react-icons/fa'; import { setImageToInpaint, - setNeedsCache, -} from '../tabs/Inpainting/inpaintingSlice'; + setDoesCanvasNeedScaling, + setImageToOutpaint, +} from 'features/canvas/canvasSlice'; import { GalleryState } from './gallerySlice'; -import { activeTabNameSelector } from '../options/optionsSelectors'; -import IAIPopover from '../../common/components/IAIPopover'; +import { activeTabNameSelector } from 'features/options/optionsSelectors'; +import IAIPopover from 'common/components/IAIPopover'; const systemSelector = createSelector( [ @@ -58,8 +60,12 @@ const systemSelector = createSelector( const { isProcessing, isConnected, isGFPGANAvailable, isESRGANAvailable } = system; - const { upscalingLevel, facetoolStrength, shouldShowImageDetails } = - options; + const { + upscalingLevel, + facetoolStrength, + shouldShowImageDetails, + isLightBoxOpen, + } = options; const { intermediateImage, currentImage } = gallery; @@ -74,6 +80,7 @@ const systemSelector = createSelector( currentImage, shouldShowImageDetails, activeTabName, + isLightBoxOpen, }; }, { @@ -99,28 +106,31 @@ const CurrentImageButtons = () => { shouldDisableToolbarButtons, shouldShowImageDetails, currentImage, + isLightBoxOpen, } = useAppSelector(systemSelector); - const { onCopy } = useClipboard( - currentImage ? window.location.toString() + currentImage.url : '' - ); - const toast = useToast(); const handleClickUseAsInitialImage = () => { if (!currentImage) return; + if (isLightBoxOpen) dispatch(setIsLightBoxOpen(false)); dispatch(setInitialImage(currentImage)); dispatch(setActiveTab('img2img')); }; const handleCopyImageLink = () => { - onCopy(); - toast({ - title: 'Image Link Copied', - status: 'success', - duration: 2500, - isClosable: true, - }); + navigator.clipboard + .writeText( + currentImage ? window.location.toString() + currentImage.url : '' + ) + .then(() => { + toast({ + title: 'Image Link Copied', + status: 'success', + duration: 2500, + isClosable: true, + }); + }); }; useHotkeys( @@ -308,11 +318,27 @@ const CurrentImageButtons = () => { const handleSendToInpainting = () => { if (!currentImage) return; + if (isLightBoxOpen) dispatch(setIsLightBoxOpen(false)); dispatch(setImageToInpaint(currentImage)); - dispatch(setActiveTab('inpainting')); - dispatch(setNeedsCache(true)); + dispatch(setDoesCanvasNeedScaling(true)); + + toast({ + title: 'Sent to Inpainting', + status: 'success', + duration: 2500, + isClosable: true, + }); + }; + + const handleSendToOutpainting = () => { + if (!currentImage) return; + if (isLightBoxOpen) dispatch(setIsLightBoxOpen(false)); + + dispatch(setImageToOutpaint(currentImage)); + dispatch(setActiveTab('outpainting')); + dispatch(setDoesCanvasNeedScaling(true)); toast({ title: 'Sent to Inpainting', @@ -363,6 +389,13 @@ const CurrentImageButtons = () => { > Send to Inpainting + } + > + Send to Outpainting + { + dispatch(setIsLightBoxOpen(true)); + }; + return (
{imageToDisplay && ( @@ -83,6 +87,7 @@ export default function CurrentImagePreview() { src={imageToDisplay.url} width={imageToDisplay.width} height={imageToDisplay.height} + onClick={handleLightBox} /> )} {!shouldShowImageDetails && ( diff --git a/frontend/src/features/gallery/DeleteImageModal.tsx b/frontend/src/features/gallery/DeleteImageModal.tsx index 417aa2d393..432062c001 100644 --- a/frontend/src/features/gallery/DeleteImageModal.tsx +++ b/frontend/src/features/gallery/DeleteImageModal.tsx @@ -22,11 +22,11 @@ import { SyntheticEvent, useRef, } from 'react'; -import { useAppDispatch, useAppSelector } from '../../app/store'; -import { deleteImage } from '../../app/socketio/actions'; -import { RootState } from '../../app/store'; -import { setShouldConfirmOnDelete, SystemState } from '../system/systemSlice'; -import * as InvokeAI from '../../app/invokeai'; +import { useAppDispatch, useAppSelector } from 'app/store'; +import { deleteImage } from 'app/socketio/actions'; +import { RootState } from 'app/store'; +import { setShouldConfirmOnDelete, SystemState } from 'features/system/systemSlice'; +import * as InvokeAI from 'app/invokeai'; import { useHotkeys } from 'react-hotkeys-hook'; import _ from 'lodash'; diff --git a/frontend/src/features/gallery/HoverableImage.tsx b/frontend/src/features/gallery/HoverableImage.tsx index 23348a69b7..d7896ce367 100644 --- a/frontend/src/features/gallery/HoverableImage.tsx +++ b/frontend/src/features/gallery/HoverableImage.tsx @@ -6,7 +6,7 @@ import { Tooltip, useToast, } from '@chakra-ui/react'; -import { useAppDispatch, useAppSelector } from '../../app/store'; +import { useAppDispatch, useAppSelector } from 'app/store'; import { setCurrentImage } from './gallerySlice'; import { FaCheck, FaTrashAlt } from 'react-icons/fa'; import DeleteImageModal from './DeleteImageModal'; @@ -16,12 +16,16 @@ import { setAllImageToImageParameters, setAllTextToImageParameters, setInitialImage, + setIsLightBoxOpen, setPrompt, setSeed, -} from '../options/optionsSlice'; -import * as InvokeAI from '../../app/invokeai'; +} from 'features/options/optionsSlice'; +import * as InvokeAI from 'app/invokeai'; import * as ContextMenu from '@radix-ui/react-context-menu'; -import { setImageToInpaint } from '../tabs/Inpainting/inpaintingSlice'; +import { + setImageToInpaint, + setImageToOutpaint, +} from 'features/canvas/canvasSlice'; import { hoverableImageSelector } from './gallerySliceSelectors'; interface HoverableImageProps { @@ -44,6 +48,7 @@ const HoverableImage = memo((props: HoverableImageProps) => { galleryImageObjectFit, galleryImageMinimumWidth, mayDeleteImage, + isLightBoxOpen, } = useAppSelector(hoverableImageSelector); const { image, isSelected } = props; const { url, uuid, metadata } = image; @@ -77,6 +82,7 @@ const HoverableImage = memo((props: HoverableImageProps) => { }; const handleSendToImageToImage = () => { + if (isLightBoxOpen) dispatch(setIsLightBoxOpen(false)); dispatch(setInitialImage(image)); if (activeTabName !== 'img2img') { dispatch(setActiveTab('img2img')); @@ -90,6 +96,7 @@ const HoverableImage = memo((props: HoverableImageProps) => { }; const handleSendToInpainting = () => { + if (isLightBoxOpen) dispatch(setIsLightBoxOpen(false)); dispatch(setImageToInpaint(image)); if (activeTabName !== 'inpainting') { dispatch(setActiveTab('inpainting')); @@ -102,6 +109,20 @@ const HoverableImage = memo((props: HoverableImageProps) => { }); }; + const handleSendToOutpainting = () => { + if (isLightBoxOpen) dispatch(setIsLightBoxOpen(false)); + dispatch(setImageToOutpaint(image)); + if (activeTabName !== 'outpainting') { + dispatch(setActiveTab('outpainting')); + } + toast({ + title: 'Sent to Outpainting', + status: 'success', + duration: 2500, + isClosable: true, + }); + }; + const handleUseAllParameters = () => { metadata && dispatch(setAllTextToImageParameters(metadata)); toast({ @@ -228,6 +249,9 @@ const HoverableImage = memo((props: HoverableImageProps) => { Send to Inpainting + + Send to Outpainting + Delete Image diff --git a/frontend/src/features/gallery/ImageGallery.scss b/frontend/src/features/gallery/ImageGallery.scss index 3b8be38cfb..4321970562 100644 --- a/frontend/src/features/gallery/ImageGallery.scss +++ b/frontend/src/features/gallery/ImageGallery.scss @@ -35,7 +35,7 @@ } .image-gallery-popup { - background-color: var(--tab-color); + background-color: var(--background-color-secondary); padding: 1rem; display: flex; flex-direction: column; @@ -55,16 +55,16 @@ column-gap: 0.5rem; justify-content: space-between; - div { + .image-gallery-header-right-icons { display: flex; - column-gap: 0.5rem; + flex-direction: row; column-gap: 0.5rem; } .image-gallery-icon-btn { - background-color: var(--btn-load-more) !important; + background-color: var(--btn-load-more); &:hover { - background-color: var(--btn-load-more-hover) !important; + background-color: var(--btn-load-more-hover); } } @@ -96,7 +96,8 @@ .image-gallery-container-placeholder { display: flex; flex-direction: column; - background-color: var(--background-color-secondary); + row-gap: 0.5rem; + background-color: var(--background-color); border-radius: 0.5rem; place-items: center; padding: 2rem; @@ -108,26 +109,26 @@ } svg { - width: 5rem; - height: 5rem; + width: 4rem; + height: 4rem; color: var(--svg-color); } } .image-gallery-load-more-btn { - background-color: var(--btn-load-more) !important; - font-size: 0.85rem !important; + background-color: var(--btn-load-more); + font-size: 0.85rem; padding: 0.5rem; margin-top: 1rem; &:disabled { &:hover { - background-color: var(--btn-load-more) !important; + background-color: var(--btn-load-more); } } &:hover { - background-color: var(--btn-load-more-hover) !important; + background-color: var(--btn-load-more-hover); } } } @@ -135,11 +136,15 @@ } .image-gallery-category-btn-group { - width: 100% !important; - column-gap: 0 !important; - justify-content: stretch !important; + width: max-content; + column-gap: 0; + justify-content: stretch; button { + background-color: var(--btn-base-color); + &:hover { + background-color: var(--btn-base-color-hover); + } flex-grow: 1; &[data-selected='true'] { background-color: var(--accent-color); diff --git a/frontend/src/features/gallery/ImageGallery.tsx b/frontend/src/features/gallery/ImageGallery.tsx index 70098588f2..1b60c9c44e 100644 --- a/frontend/src/features/gallery/ImageGallery.tsx +++ b/frontend/src/features/gallery/ImageGallery.tsx @@ -5,9 +5,9 @@ import { ChangeEvent, useEffect, useRef, useState } from 'react'; import { useHotkeys } from 'react-hotkeys-hook'; import { MdPhotoLibrary } from 'react-icons/md'; import { BsPinAngle, BsPinAngleFill } from 'react-icons/bs'; -import { requestImages } from '../../app/socketio/actions'; -import { useAppDispatch, useAppSelector } from '../../app/store'; -import IAIIconButton from '../../common/components/IAIIconButton'; +import { requestImages } from 'app/socketio/actions'; +import { useAppDispatch, useAppSelector } from 'app/store'; +import IAIIconButton from 'common/components/IAIIconButton'; import { selectNextImage, selectPrevImage, @@ -21,19 +21,19 @@ import { setShouldPinGallery, } from './gallerySlice'; import HoverableImage from './HoverableImage'; -import { setShouldShowGallery } from '../gallery/gallerySlice'; +import { setShouldShowGallery } from 'features/gallery/gallerySlice'; import { ButtonGroup, useToast } from '@chakra-ui/react'; import { CSSTransition } from 'react-transition-group'; import { Direction } from 're-resizable/lib/resizer'; import { imageGallerySelector } from './gallerySliceSelectors'; import { FaImage, FaUser, FaWrench } from 'react-icons/fa'; -import IAIPopover from '../../common/components/IAIPopover'; -import IAISlider from '../../common/components/IAISlider'; +import IAIPopover from 'common/components/IAIPopover'; +import IAISlider from 'common/components/IAISlider'; import { BiReset } from 'react-icons/bi'; -import IAICheckbox from '../../common/components/IAICheckbox'; -import { setNeedsCache } from '../tabs/Inpainting/inpaintingSlice'; +import IAICheckbox from 'common/components/IAICheckbox'; +import { setDoesCanvasNeedScaling } from 'features/canvas/canvasSlice'; import _ from 'lodash'; -import useClickOutsideWatcher from '../../common/hooks/useClickOutsideWatcher'; +import useClickOutsideWatcher from 'common/hooks/useClickOutsideWatcher'; const GALLERY_SHOW_BUTTONS_MIN_WIDTH = 320; @@ -56,6 +56,7 @@ export default function ImageGallery() { shouldAutoSwitchToNewImages, areMoreImagesAvailable, galleryWidth, + isLightBoxOpen, } = useAppSelector(imageGallerySelector); const [galleryMinWidth, setGalleryMinWidth] = useState(300); @@ -68,6 +69,13 @@ export default function ImageGallery() { useEffect(() => { if (!shouldPinGallery) return; + if (isLightBoxOpen) { + dispatch(setGalleryWidth(400)); + setGalleryMinWidth(400); + setGalleryMaxWidth(400); + return; + } + if (activeTabName === 'inpainting') { dispatch(setGalleryWidth(190)); setGalleryMinWidth(190); @@ -83,14 +91,14 @@ export default function ImageGallery() { ); setGalleryMaxWidth(590); } - dispatch(setNeedsCache(true)); - }, [dispatch, activeTabName, shouldPinGallery, galleryWidth]); + dispatch(setDoesCanvasNeedScaling(true)); + }, [dispatch, activeTabName, shouldPinGallery, galleryWidth, isLightBoxOpen]); useEffect(() => { if (!shouldPinGallery) { setGalleryMaxWidth(window.innerWidth); } - }, [shouldPinGallery]); + }, [shouldPinGallery, isLightBoxOpen]); const galleryRef = useRef(null); const galleryContainerRef = useRef(null); @@ -98,7 +106,7 @@ export default function ImageGallery() { const handleSetShouldPinGallery = () => { dispatch(setShouldPinGallery(!shouldPinGallery)); - dispatch(setNeedsCache(true)); + dispatch(setDoesCanvasNeedScaling(true)); }; const handleToggleGallery = () => { @@ -107,7 +115,7 @@ export default function ImageGallery() { const handleOpenGallery = () => { dispatch(setShouldShowGallery(true)); - shouldPinGallery && dispatch(setNeedsCache(true)); + shouldPinGallery && dispatch(setDoesCanvasNeedScaling(true)); }; const handleCloseGallery = () => { @@ -119,7 +127,7 @@ export default function ImageGallery() { ) ); dispatch(setShouldHoldGalleryOpen(false)); - // dispatch(setNeedsCache(true)); + // dispatch(setDoesCanvasNeedScaling(true)); }; const handleClickLoadMore = () => { @@ -128,7 +136,7 @@ export default function ImageGallery() { const handleChangeGalleryImageMinimumWidth = (v: number) => { dispatch(setGalleryImageMinimumWidth(v)); - dispatch(setNeedsCache(true)); + dispatch(setDoesCanvasNeedScaling(true)); }; const setCloseGalleryTimer = () => { @@ -143,8 +151,10 @@ export default function ImageGallery() { 'g', () => { handleToggleGallery(); + shouldPinGallery && + setTimeout(() => dispatch(setDoesCanvasNeedScaling(true)), 400); }, - [shouldShowGallery] + [shouldShowGallery, shouldPinGallery] ); useHotkeys('left', () => { @@ -159,6 +169,7 @@ export default function ImageGallery() { 'shift+g', () => { handleSetShouldPinGallery(); + dispatch(setDoesCanvasNeedScaling(true)); }, [shouldPinGallery] ); @@ -168,6 +179,7 @@ export default function ImageGallery() { () => { if (shouldPinGallery) return; dispatch(setShouldShowGallery(false)); + dispatch(setDoesCanvasNeedScaling(true)); }, [shouldPinGallery] ); @@ -339,49 +351,48 @@ export default function ImageGallery() { }} >
-
- - {shouldShowButtons ? ( - <> - - - - ) : ( - <> - } - onClick={() => dispatch(setCurrentCategory('result'))} - /> - } - onClick={() => dispatch(setCurrentCategory('user'))} - /> - - )} - -
-
+ + {shouldShowButtons ? ( + <> + + + + ) : ( + <> + } + onClick={() => dispatch(setCurrentCategory('result'))} + /> + } + onClick={() => dispatch(setCurrentCategory('user'))} + /> + + )} + + +
) => { + setIntermediateImage: ( + state, + action: PayloadAction< + InvokeAI.Image & { boundingBox?: IRect; generationMode?: InvokeTabName } + > + ) => { state.intermediateImage = action.payload; }, clearIntermediateImage: (state) => { diff --git a/frontend/src/features/gallery/gallerySliceSelectors.ts b/frontend/src/features/gallery/gallerySliceSelectors.ts index d0bbb5af40..78bc6fcf58 100644 --- a/frontend/src/features/gallery/gallerySliceSelectors.ts +++ b/frontend/src/features/gallery/gallerySliceSelectors.ts @@ -1,8 +1,8 @@ import { createSelector } from '@reduxjs/toolkit'; -import { RootState } from '../../app/store'; -import { activeTabNameSelector } from '../options/optionsSelectors'; -import { OptionsState } from '../options/optionsSlice'; -import { SystemState } from '../system/systemSlice'; +import { RootState } from 'app/store'; +import { activeTabNameSelector } from 'features/options/optionsSelectors'; +import { OptionsState } from 'features/options/optionsSlice'; +import { SystemState } from 'features/system/systemSlice'; import { GalleryState } from './gallerySlice'; import _ from 'lodash'; @@ -27,6 +27,8 @@ export const imageGallerySelector = createSelector( galleryWidth, } = gallery; + const { isLightBoxOpen } = options; + return { currentImageUuid, shouldPinGallery, @@ -43,6 +45,7 @@ export const imageGallerySelector = createSelector( categories[currentCategory].areMoreImagesAvailable, currentCategory, galleryWidth, + isLightBoxOpen, }; }, { @@ -70,6 +73,7 @@ export const hoverableImageSelector = createSelector( galleryImageObjectFit: gallery.galleryImageObjectFit, galleryImageMinimumWidth: gallery.galleryImageMinimumWidth, activeTabName, + isLightBoxOpen: options.isLightBoxOpen, }; }, { diff --git a/frontend/src/features/lightbox/Lightbox.scss b/frontend/src/features/lightbox/Lightbox.scss new file mode 100644 index 0000000000..74c4fb4fc5 --- /dev/null +++ b/frontend/src/features/lightbox/Lightbox.scss @@ -0,0 +1,74 @@ +@use '../../styles/Mixins/' as *; + +.lightbox-container { + width: 100%; + height: 100%; + color: var(--text-color); + overflow: hidden; + position: absolute; + left: 0; + top: 0; + background-color: var(--background-color-secondary); + z-index: 30; + + .image-gallery-wrapper { + max-height: 100% !important; + + .image-gallery-container { + max-height: calc(100vh - 5rem); + } + } + + .current-image-options { + z-index: 2; + position: absolute; + top: 1rem; + } +} + +.lightbox-close-btn { + z-index: 3; + position: absolute; + left: 1rem; + top: 1rem; + @include BaseButton; +} + +.lightbox-display-container { + display: flex; + flex-direction: row; +} + +.lightbox-preview-wrapper { + overflow: hidden; + background-color: red; + background-color: var(--background-color-secondary); + display: grid; + grid-template-columns: auto max-content; + + place-items: center; + width: 100vw; + height: 100vh; + + .current-image-next-prev-buttons { + position: absolute; + } + + .lightbox-image { + grid-area: lightbox-content; + border-radius: 0.5rem; + } + + .lightbox-image-options { + position: absolute; + z-index: 2; + left: 1rem; + top: 4.5rem; + user-select: none; + border-radius: 0.5rem; + + display: flex; + flex-direction: column; + row-gap: 0.5rem; + } +} diff --git a/frontend/src/features/lightbox/Lightbox.tsx b/frontend/src/features/lightbox/Lightbox.tsx new file mode 100644 index 0000000000..aa8f92885f --- /dev/null +++ b/frontend/src/features/lightbox/Lightbox.tsx @@ -0,0 +1,116 @@ +import { IconButton } from '@chakra-ui/react'; +import { RootState, useAppDispatch, useAppSelector } from 'app/store'; +import IAIIconButton from 'common/components/IAIIconButton'; +import CurrentImageButtons from 'features/gallery/CurrentImageButtons'; +import { imagesSelector } from 'features/gallery/CurrentImagePreview'; +import { + selectNextImage, + selectPrevImage, +} from 'features/gallery/gallerySlice'; +import ImageGallery from 'features/gallery/ImageGallery'; +import { setIsLightBoxOpen } from 'features/options/optionsSlice'; +import React, { useState } from 'react'; +import { useHotkeys } from 'react-hotkeys-hook'; +import { BiExit } from 'react-icons/bi'; +import { FaAngleLeft, FaAngleRight } from 'react-icons/fa'; +import ReactPanZoom from './ReactPanZoom'; + +export default function Lightbox() { + const dispatch = useAppDispatch(); + const isLightBoxOpen = useAppSelector( + (state: RootState) => state.options.isLightBoxOpen + ); + + const { + imageToDisplay, + shouldShowImageDetails, + isOnFirstImage, + isOnLastImage, + } = useAppSelector(imagesSelector); + + const [shouldShowNextPrevButtons, setShouldShowNextPrevButtons] = + useState(false); + + const handleCurrentImagePreviewMouseOver = () => { + setShouldShowNextPrevButtons(true); + }; + + const handleCurrentImagePreviewMouseOut = () => { + setShouldShowNextPrevButtons(false); + }; + + const handleClickPrevButton = () => { + dispatch(selectPrevImage()); + }; + + const handleClickNextButton = () => { + dispatch(selectNextImage()); + }; + + useHotkeys( + 'Esc', + () => { + if (isLightBoxOpen) dispatch(setIsLightBoxOpen(false)); + }, + [isLightBoxOpen] + ); + + return ( +
+ } + aria-label="Exit Viewer" + className="lightbox-close-btn" + onClick={() => { + dispatch(setIsLightBoxOpen(false)); + }} + fontSize={20} + /> + +
+
+ + {!shouldShowImageDetails && ( +
+
+ {shouldShowNextPrevButtons && !isOnFirstImage && ( + } + variant="unstyled" + onClick={handleClickPrevButton} + /> + )} +
+
+ {shouldShowNextPrevButtons && !isOnLastImage && ( + } + variant="unstyled" + onClick={handleClickNextButton} + /> + )} +
+
+ )} + {imageToDisplay && ( + + )} +
+ +
+
+ ); +} diff --git a/frontend/src/features/lightbox/ReactPanZoom.tsx b/frontend/src/features/lightbox/ReactPanZoom.tsx new file mode 100644 index 0000000000..0c84d8a0e8 --- /dev/null +++ b/frontend/src/features/lightbox/ReactPanZoom.tsx @@ -0,0 +1,155 @@ +import IAIIconButton from 'common/components/IAIIconButton'; +import * as React from 'react'; +import { + BiReset, + BiRotateLeft, + BiRotateRight, + BiZoomIn, + BiZoomOut, +} from 'react-icons/bi'; +import { MdFlip } from 'react-icons/md'; +import { PanViewer } from 'react-image-pan-zoom-rotate'; + +type ReactPanZoomProps = { + image: string; + styleClass?: string; + alt?: string; + ref?: any; +}; + +export default function ReactPanZoom({ + image, + alt, + ref, + styleClass, +}: ReactPanZoomProps) { + const [dx, setDx] = React.useState(0); + const [dy, setDy] = React.useState(0); + const [zoom, setZoom] = React.useState(1); + const [rotation, setRotation] = React.useState(0); + const [flip, setFlip] = React.useState(false); + + const resetAll = () => { + setDx(0); + setDy(0); + setZoom(1); + setRotation(0); + setFlip(false); + }; + const zoomIn = () => { + setZoom(zoom + 0.2); + }; + + const zoomOut = () => { + if (zoom >= 0.5) { + setZoom(zoom - 0.2); + } + }; + + const rotateLeft = () => { + if (rotation === -3) { + setRotation(0); + } else { + setRotation(rotation - 1); + } + }; + + const rotateRight = () => { + if (rotation === 3) { + setRotation(0); + } else { + setRotation(rotation + 1); + } + }; + + const flipImage = () => { + setFlip(!flip); + }; + + const onPan = (dx: number, dy: number) => { + setDx(dx); + setDy(dy); + }; + + return ( +
+
+ } + aria-label="Zoom In" + tooltip="Zoom In" + onClick={zoomIn} + fontSize={20} + /> + + } + aria-label="Zoom Out" + tooltip="Zoom Out" + onClick={zoomOut} + fontSize={20} + /> + + } + aria-label="Rotate Left" + tooltip="Rotate Left" + onClick={rotateLeft} + fontSize={20} + /> + + } + aria-label="Rotate Right" + tooltip="Rotate Right" + onClick={rotateRight} + fontSize={20} + /> + + } + aria-label="Flip Image" + tooltip="Flip Image" + onClick={flipImage} + fontSize={20} + /> + + } + aria-label="Reset" + tooltip="Reset" + onClick={resetAll} + fontSize={20} + /> +
+ + {alt} + +
+ ); +} diff --git a/frontend/src/features/options/AccordionItems/AdvancedSettings.scss b/frontend/src/features/options/AccordionItems/AdvancedSettings.scss index fd940e8182..9d0dcd9cca 100644 --- a/frontend/src/features/options/AccordionItems/AdvancedSettings.scss +++ b/frontend/src/features/options/AccordionItems/AdvancedSettings.scss @@ -21,7 +21,20 @@ .advanced-settings-panel { background-color: var(--tab-panel-bg); border-radius: 0 0 0.4rem 0.4rem; - border: 2px solid var(--tab-hover-color); + padding: 1rem; + + button { + background-color: var(--btn-base-color); + &:hover { + background-color: var(--btn-base-color-hover); + } + + &:disabled { + &:hover { + background-color: var(--btn-base-color); + } + } + } } .advanced-settings-header { @@ -33,6 +46,6 @@ } &:hover { - background-color: var(--tab-hover-color) !important; + background-color: var(--tab-hover-color); } } diff --git a/frontend/src/features/options/AccordionItems/InvokeAccordionItem.tsx b/frontend/src/features/options/AccordionItems/InvokeAccordionItem.tsx index 30d6f2a5e8..d11990a6a6 100644 --- a/frontend/src/features/options/AccordionItems/InvokeAccordionItem.tsx +++ b/frontend/src/features/options/AccordionItems/InvokeAccordionItem.tsx @@ -5,8 +5,8 @@ import { AccordionPanel, } from '@chakra-ui/react'; import React, { ReactElement } from 'react'; -import { Feature } from '../../../app/features'; -import GuideIcon from '../../../common/components/GuideIcon'; +import { Feature } from 'app/features'; +import GuideIcon from 'common/components/GuideIcon'; export interface InvokeAccordionItemProps { header: ReactElement; diff --git a/frontend/src/features/options/AdvancedOptions/FaceRestore/FaceRestoreHeader.tsx b/frontend/src/features/options/AdvancedOptions/FaceRestore/FaceRestoreHeader.tsx index 0efe400d22..937a33cdab 100644 --- a/frontend/src/features/options/AdvancedOptions/FaceRestore/FaceRestoreHeader.tsx +++ b/frontend/src/features/options/AdvancedOptions/FaceRestore/FaceRestoreHeader.tsx @@ -4,9 +4,9 @@ import { RootState, useAppDispatch, useAppSelector, -} from '../../../../app/store'; -import IAISwitch from '../../../../common/components/IAISwitch'; -import { setShouldRunFacetool } from '../../optionsSlice'; +} from 'app/store'; +import IAISwitch from 'common/components/IAISwitch'; +import { setShouldRunFacetool } from 'features/options/optionsSlice'; export default function FaceRestoreHeader() { const isGFPGANAvailable = useAppSelector( diff --git a/frontend/src/features/options/AdvancedOptions/FaceRestore/FaceRestoreOptions.tsx b/frontend/src/features/options/AdvancedOptions/FaceRestore/FaceRestoreOptions.tsx index 1f8e170a6f..d0043f2f70 100644 --- a/frontend/src/features/options/AdvancedOptions/FaceRestore/FaceRestoreOptions.tsx +++ b/frontend/src/features/options/AdvancedOptions/FaceRestore/FaceRestoreOptions.tsx @@ -1,7 +1,7 @@ import { Flex } from '@chakra-ui/react'; -import { RootState } from '../../../../app/store'; -import { useAppDispatch, useAppSelector } from '../../../../app/store'; +import { RootState } from 'app/store'; +import { useAppDispatch, useAppSelector } from 'app/store'; import { FacetoolType, @@ -9,14 +9,14 @@ import { setCodeformerFidelity, setFacetoolStrength, setFacetoolType, -} from '../../optionsSlice'; +} from 'features/options/optionsSlice'; import { createSelector } from '@reduxjs/toolkit'; import { isEqual } from 'lodash'; -import { SystemState } from '../../../system/systemSlice'; -import IAINumberInput from '../../../../common/components/IAINumberInput'; -import IAISelect from '../../../../common/components/IAISelect'; -import { FACETOOL_TYPES } from '../../../../app/constants'; +import { SystemState } from 'features/system/systemSlice'; +import IAINumberInput from 'common/components/IAINumberInput'; +import IAISelect from 'common/components/IAISelect'; +import { FACETOOL_TYPES } from 'app/constants'; import { ChangeEvent } from 'react'; const optionsSelector = createSelector( diff --git a/frontend/src/features/options/AdvancedOptions/ImageToImage/ImageFit.tsx b/frontend/src/features/options/AdvancedOptions/ImageToImage/ImageFit.tsx index eaaa08dff4..738c3d2d96 100644 --- a/frontend/src/features/options/AdvancedOptions/ImageToImage/ImageFit.tsx +++ b/frontend/src/features/options/AdvancedOptions/ImageToImage/ImageFit.tsx @@ -3,9 +3,9 @@ import { RootState, useAppDispatch, useAppSelector, -} from '../../../../app/store'; -import IAISwitch from '../../../../common/components/IAISwitch'; -import { setShouldFitToWidthHeight } from '../../optionsSlice'; +} from 'app/store'; +import IAISwitch from 'common/components/IAISwitch'; +import { setShouldFitToWidthHeight } from 'features/options/optionsSlice'; export default function ImageFit() { const dispatch = useAppDispatch(); diff --git a/frontend/src/features/options/AdvancedOptions/ImageToImage/ImageToImageStrength.tsx b/frontend/src/features/options/AdvancedOptions/ImageToImage/ImageToImageStrength.tsx index ea916c5460..624d958fb2 100644 --- a/frontend/src/features/options/AdvancedOptions/ImageToImage/ImageToImageStrength.tsx +++ b/frontend/src/features/options/AdvancedOptions/ImageToImage/ImageToImageStrength.tsx @@ -1,11 +1,7 @@ import React from 'react'; -import { - RootState, - useAppDispatch, - useAppSelector, -} from '../../../../app/store'; -import IAINumberInput from '../../../../common/components/IAINumberInput'; -import { setImg2imgStrength } from '../../optionsSlice'; +import { RootState, useAppDispatch, useAppSelector } from 'app/store'; +import IAISlider from 'common/components/IAISlider'; +import { setImg2imgStrength } from 'features/options/optionsSlice'; interface ImageToImageStrengthProps { label?: string; @@ -22,17 +18,36 @@ export default function ImageToImageStrength(props: ImageToImageStrengthProps) { const handleChangeStrength = (v: number) => dispatch(setImg2imgStrength(v)); + const handleImg2ImgStrengthReset = () => { + dispatch(setImg2imgStrength(0.5)); + }; + return ( - + // ); } diff --git a/frontend/src/features/options/AdvancedOptions/Inpainting/BoundingBoxSettings/BoundingBoxDarkenOutside.tsx b/frontend/src/features/options/AdvancedOptions/Inpainting/BoundingBoxSettings/BoundingBoxDarkenOutside.tsx index b91f5d5736..82f832d904 100644 --- a/frontend/src/features/options/AdvancedOptions/Inpainting/BoundingBoxSettings/BoundingBoxDarkenOutside.tsx +++ b/frontend/src/features/options/AdvancedOptions/Inpainting/BoundingBoxSettings/BoundingBoxDarkenOutside.tsx @@ -1,26 +1,33 @@ import React from 'react'; +import { RootState, useAppDispatch, useAppSelector } from 'app/store'; +import IAICheckbox from 'common/components/IAICheckbox'; import { - RootState, - useAppDispatch, - useAppSelector, -} from '../../../../../app/store'; -import IAICheckbox from '../../../../../common/components/IAICheckbox'; -import { setShouldShowBoundingBoxFill } from '../../../../tabs/Inpainting/inpaintingSlice'; + currentCanvasSelector, + GenericCanvasState, + setShouldDarkenOutsideBoundingBox, +} from 'features/canvas/canvasSlice'; +import { createSelector } from '@reduxjs/toolkit'; + +const selector = createSelector( + currentCanvasSelector, + (currentCanvas: GenericCanvasState) => + currentCanvas.shouldDarkenOutsideBoundingBox +); export default function BoundingBoxDarkenOutside() { const dispatch = useAppDispatch(); - const shouldShowBoundingBoxFill = useAppSelector( - (state: RootState) => state.inpainting.shouldShowBoundingBoxFill - ); + const shouldDarkenOutsideBoundingBox = useAppSelector(selector); const handleChangeShouldShowBoundingBoxFill = () => { - dispatch(setShouldShowBoundingBoxFill(!shouldShowBoundingBoxFill)); + dispatch( + setShouldDarkenOutsideBoundingBox(!shouldDarkenOutsideBoundingBox) + ); }; return ( diff --git a/frontend/src/features/options/AdvancedOptions/Inpainting/BoundingBoxSettings/BoundingBoxDimensionSlider.tsx b/frontend/src/features/options/AdvancedOptions/Inpainting/BoundingBoxSettings/BoundingBoxDimensionSlider.tsx index 709a86a80b..aa8964aa89 100644 --- a/frontend/src/features/options/AdvancedOptions/Inpainting/BoundingBoxSettings/BoundingBoxDimensionSlider.tsx +++ b/frontend/src/features/options/AdvancedOptions/Inpainting/BoundingBoxSettings/BoundingBoxDimensionSlider.tsx @@ -1,30 +1,25 @@ import React from 'react'; -import IAISlider from '../../../../../common/components/IAISlider'; -import IAINumberInput from '../../../../../common/components/IAINumberInput'; -import IAIIconButton from '../../../../../common/components/IAIIconButton'; -import { BiReset } from 'react-icons/bi'; +import IAISlider from 'common/components/IAISlider'; -import { - RootState, - useAppDispatch, - useAppSelector, -} from '../../../../../app/store'; +import { RootState, useAppDispatch, useAppSelector } from 'app/store'; import { createSelector } from '@reduxjs/toolkit'; import { - InpaintingState, + currentCanvasSelector, + GenericCanvasState, + // InpaintingState, setBoundingBoxDimensions, -} from '../../../../tabs/Inpainting/inpaintingSlice'; +} from 'features/canvas/canvasSlice'; -import { roundDownToMultiple } from '../../../../../common/util/roundDownToMultiple'; +import { roundDownToMultiple } from 'common/util/roundDownToMultiple'; import _ from 'lodash'; const boundingBoxDimensionsSelector = createSelector( - (state: RootState) => state.inpainting, - (inpainting: InpaintingState) => { - const { canvasDimensions, boundingBoxDimensions, shouldLockBoundingBox } = - inpainting; + currentCanvasSelector, + (currentCanvas: GenericCanvasState) => { + const { stageDimensions, boundingBoxDimensions, shouldLockBoundingBox } = + currentCanvas; return { - canvasDimensions, + stageDimensions, boundingBoxDimensions, shouldLockBoundingBox, }; @@ -38,17 +33,18 @@ const boundingBoxDimensionsSelector = createSelector( type BoundingBoxDimensionSlidersType = { dimension: 'width' | 'height'; + label: string; }; export default function BoundingBoxDimensionSlider( props: BoundingBoxDimensionSlidersType ) { - const { dimension } = props; + const { dimension, label } = props; const dispatch = useAppDispatch(); - const { shouldLockBoundingBox, canvasDimensions, boundingBoxDimensions } = + const { shouldLockBoundingBox, stageDimensions, boundingBoxDimensions } = useAppSelector(boundingBoxDimensionsSelector); - const canvasDimension = canvasDimensions[dimension]; + const canvasDimension = stageDimensions[dimension]; const boundingBoxDimension = boundingBoxDimensions[dimension]; const handleBoundingBoxDimension = (v: number) => { @@ -91,38 +87,22 @@ export default function BoundingBoxDimensionSlider( }; return ( -
- - - } - styleClass="inpainting-bounding-box-reset-icon-btn" - isDisabled={ - shouldLockBoundingBox || canvasDimension === boundingBoxDimension - } - /> -
+ ); } diff --git a/frontend/src/features/options/AdvancedOptions/Inpainting/BoundingBoxSettings/BoundingBoxLock.tsx b/frontend/src/features/options/AdvancedOptions/Inpainting/BoundingBoxSettings/BoundingBoxLock.tsx index adea1f3f54..ba90b02abb 100644 --- a/frontend/src/features/options/AdvancedOptions/Inpainting/BoundingBoxSettings/BoundingBoxLock.tsx +++ b/frontend/src/features/options/AdvancedOptions/Inpainting/BoundingBoxSettings/BoundingBoxLock.tsx @@ -1,16 +1,20 @@ import React from 'react'; +import { RootState, useAppDispatch, useAppSelector } from 'app/store'; +import IAICheckbox from 'common/components/IAICheckbox'; import { - RootState, - useAppDispatch, - useAppSelector, -} from '../../../../../app/store'; -import IAICheckbox from '../../../../../common/components/IAICheckbox'; -import { setShouldLockBoundingBox } from '../../../../tabs/Inpainting/inpaintingSlice'; + currentCanvasSelector, + GenericCanvasState, + setShouldLockBoundingBox, +} from 'features/canvas/canvasSlice'; +import { createSelector } from '@reduxjs/toolkit'; + +const boundingBoxLockSelector = createSelector( + currentCanvasSelector, + (currentCanvas: GenericCanvasState) => currentCanvas.shouldLockBoundingBox +); export default function BoundingBoxLock() { - const shouldLockBoundingBox = useAppSelector( - (state: RootState) => state.inpainting.shouldLockBoundingBox - ); + const shouldLockBoundingBox = useAppSelector(boundingBoxLockSelector); const dispatch = useAppDispatch(); const handleChangeShouldLockBoundingBox = () => { diff --git a/frontend/src/features/options/AdvancedOptions/Inpainting/BoundingBoxSettings/BoundingBoxSettings.scss b/frontend/src/features/options/AdvancedOptions/Inpainting/BoundingBoxSettings/BoundingBoxSettings.scss index 5eef7cc47d..b9fd319458 100644 --- a/frontend/src/features/options/AdvancedOptions/Inpainting/BoundingBoxSettings/BoundingBoxSettings.scss +++ b/frontend/src/features/options/AdvancedOptions/Inpainting/BoundingBoxSettings/BoundingBoxSettings.scss @@ -11,15 +11,15 @@ flex-direction: row; justify-content: space-between; padding: 0.5rem 1rem; - border-radius: 0.4rem 0.4rem 0 0; + border-radius: 0.3rem 0.3rem 0 0; align-items: center; button { - width: 0.5rem !important; - height: 1.2rem !important; - background: none !important; + width: 0.5rem; + height: 1.2rem; + background: none; &:hover { - background: none !important; + background: none; } } @@ -35,9 +35,9 @@ row-gap: 1rem; .inpainting-bounding-box-reset-icon-btn { - background-color: var(--btn-load-more) !important; + background-color: var(--btn-base-color); &:hover { - background-color: var(--btn-load-more-hover) !important; + background-color: var(--btn-base-color-hover); } } } diff --git a/frontend/src/features/options/AdvancedOptions/Inpainting/BoundingBoxSettings/BoundingBoxSettings.tsx b/frontend/src/features/options/AdvancedOptions/Inpainting/BoundingBoxSettings/BoundingBoxSettings.tsx index 5038823d85..018d16cca1 100644 --- a/frontend/src/features/options/AdvancedOptions/Inpainting/BoundingBoxSettings/BoundingBoxSettings.tsx +++ b/frontend/src/features/options/AdvancedOptions/Inpainting/BoundingBoxSettings/BoundingBoxSettings.tsx @@ -12,8 +12,8 @@ const BoundingBoxSettings = () => {
- - + + diff --git a/frontend/src/features/options/AdvancedOptions/Inpainting/BoundingBoxSettings/BoundingBoxVisibility.tsx b/frontend/src/features/options/AdvancedOptions/Inpainting/BoundingBoxSettings/BoundingBoxVisibility.tsx index ef0a76d166..b6b5a1b5de 100644 --- a/frontend/src/features/options/AdvancedOptions/Inpainting/BoundingBoxSettings/BoundingBoxVisibility.tsx +++ b/frontend/src/features/options/AdvancedOptions/Inpainting/BoundingBoxSettings/BoundingBoxVisibility.tsx @@ -1,17 +1,21 @@ import React from 'react'; import { BiHide, BiShow } from 'react-icons/bi'; +import { RootState, useAppDispatch, useAppSelector } from 'app/store'; +import IAIIconButton from 'common/components/IAIIconButton'; import { - RootState, - useAppDispatch, - useAppSelector, -} from '../../../../../app/store'; -import IAIIconButton from '../../../../../common/components/IAIIconButton'; -import { setShouldShowBoundingBox } from '../../../../tabs/Inpainting/inpaintingSlice'; + currentCanvasSelector, + GenericCanvasState, + setShouldShowBoundingBox, +} from 'features/canvas/canvasSlice'; +import { createSelector } from '@reduxjs/toolkit'; + +const boundingBoxVisibilitySelector = createSelector( + currentCanvasSelector, + (currentCanvas: GenericCanvasState) => currentCanvas.shouldShowBoundingBox +); export default function BoundingBoxVisibility() { - const shouldShowBoundingBox = useAppSelector( - (state: RootState) => state.inpainting.shouldShowBoundingBox - ); + const shouldShowBoundingBox = useAppSelector(boundingBoxVisibilitySelector); const dispatch = useAppDispatch(); const handleShowBoundingBox = () => diff --git a/frontend/src/features/options/AdvancedOptions/Inpainting/ClearBrushHistory.tsx b/frontend/src/features/options/AdvancedOptions/Inpainting/ClearBrushHistory.tsx index fd47f50196..4f8307b367 100644 --- a/frontend/src/features/options/AdvancedOptions/Inpainting/ClearBrushHistory.tsx +++ b/frontend/src/features/options/AdvancedOptions/Inpainting/ClearBrushHistory.tsx @@ -1,24 +1,24 @@ import { useToast } from '@chakra-ui/react'; import { createSelector } from '@reduxjs/toolkit'; +import { useAppDispatch, useAppSelector } from 'app/store'; +import IAIButton from 'common/components/IAIButton'; import { - RootState, - useAppDispatch, - useAppSelector, -} from '../../../../app/store'; -import IAIButton from '../../../../common/components/IAIButton'; -import { - InpaintingState, + currentCanvasSelector, + InpaintingCanvasState, + OutpaintingCanvasState, setClearBrushHistory, -} from '../../../tabs/Inpainting/inpaintingSlice'; +} from 'features/canvas/canvasSlice'; import _ from 'lodash'; const clearBrushHistorySelector = createSelector( - (state: RootState) => state.inpainting, - (inpainting: InpaintingState) => { - const { pastLines, futureLines } = inpainting; + currentCanvasSelector, + (currentCanvas) => { + const { pastObjects, futureObjects } = currentCanvas as + | InpaintingCanvasState + | OutpaintingCanvasState; return { mayClearBrushHistory: - futureLines.length > 0 || pastLines.length > 0 ? false : true, + futureObjects.length > 0 || pastObjects.length > 0 ? false : true, }; }, { diff --git a/frontend/src/features/options/AdvancedOptions/Inpainting/InpaintReplace.tsx b/frontend/src/features/options/AdvancedOptions/Inpainting/InpaintReplace.tsx index 5333f7b8ab..837ce8d470 100644 --- a/frontend/src/features/options/AdvancedOptions/Inpainting/InpaintReplace.tsx +++ b/frontend/src/features/options/AdvancedOptions/Inpainting/InpaintReplace.tsx @@ -4,20 +4,22 @@ import { useAppDispatch, useAppSelector, } from '../../../../app/store'; -import IAINumberInput from '../../../../common/components/IAINumberInput'; import _ from 'lodash'; import { createSelector } from '@reduxjs/toolkit'; +import IAISwitch from '../../../../common/components/IAISwitch'; +import IAISlider from '../../../../common/components/IAISlider'; +import { Flex } from '@chakra-ui/react'; import { - InpaintingState, + currentCanvasSelector, + GenericCanvasState, setInpaintReplace, setShouldUseInpaintReplace, -} from '../../../tabs/Inpainting/inpaintingSlice'; -import IAISwitch from '../../../../common/components/IAISwitch'; +} from 'features/canvas/canvasSlice'; -const inpaintReplaceSelector = createSelector( - (state: RootState) => state.inpainting, - (inpainting: InpaintingState) => { - const { inpaintReplace, shouldUseInpaintReplace } = inpainting; +const canvasInpaintReplaceSelector = createSelector( + currentCanvasSelector, + (currentCanvas: GenericCanvasState) => { + const { inpaintReplace, shouldUseInpaintReplace } = currentCanvas; return { inpaintReplace, shouldUseInpaintReplace, @@ -32,32 +34,29 @@ const inpaintReplaceSelector = createSelector( export default function InpaintReplace() { const { inpaintReplace, shouldUseInpaintReplace } = useAppSelector( - inpaintReplaceSelector + canvasInpaintReplaceSelector ); const dispatch = useAppDispatch(); return ( -
- + { dispatch(setInpaintReplace(v)); }} + min={0} + max={1.0} + step={0.05} + isInteger={false} + isSliderDisabled={!shouldUseInpaintReplace} + withSliderMarks + sliderMarkRightOffset={-2} + withReset + handleReset={() => dispatch(setInpaintReplace(1))} + isResetDisabled={!shouldUseInpaintReplace} /> -
+
); } diff --git a/frontend/src/features/options/AdvancedOptions/Output/HiresOptions.tsx b/frontend/src/features/options/AdvancedOptions/Output/HiresOptions.tsx index fc5606d027..4b65907b4d 100644 --- a/frontend/src/features/options/AdvancedOptions/Output/HiresOptions.tsx +++ b/frontend/src/features/options/AdvancedOptions/Output/HiresOptions.tsx @@ -4,9 +4,9 @@ import { RootState, useAppDispatch, useAppSelector, -} from '../../../../app/store'; -import IAISwitch from '../../../../common/components/IAISwitch'; -import { setHiresFix } from '../../optionsSlice'; +} from 'app/store'; +import IAISwitch from 'common/components/IAISwitch'; +import { setHiresFix } from 'features/options/optionsSlice'; /** * Hires Fix Toggle diff --git a/frontend/src/features/options/AdvancedOptions/Output/SeamlessOptions.tsx b/frontend/src/features/options/AdvancedOptions/Output/SeamlessOptions.tsx index df15292870..7b477844e7 100644 --- a/frontend/src/features/options/AdvancedOptions/Output/SeamlessOptions.tsx +++ b/frontend/src/features/options/AdvancedOptions/Output/SeamlessOptions.tsx @@ -4,9 +4,9 @@ import { RootState, useAppDispatch, useAppSelector, -} from '../../../../app/store'; -import IAISwitch from '../../../../common/components/IAISwitch'; -import { setSeamless } from '../../optionsSlice'; +} from 'app/store'; +import IAISwitch from 'common/components/IAISwitch'; +import { setSeamless } from 'features/options/optionsSlice'; /** * Seamless tiling toggle diff --git a/frontend/src/features/options/AdvancedOptions/Seed/Perlin.tsx b/frontend/src/features/options/AdvancedOptions/Seed/Perlin.tsx index 4b3df41305..c0049335d3 100644 --- a/frontend/src/features/options/AdvancedOptions/Seed/Perlin.tsx +++ b/frontend/src/features/options/AdvancedOptions/Seed/Perlin.tsx @@ -3,9 +3,9 @@ import { RootState, useAppDispatch, useAppSelector, -} from '../../../../app/store'; -import IAINumberInput from '../../../../common/components/IAINumberInput'; -import { setPerlin } from '../../optionsSlice'; +} from 'app/store'; +import IAINumberInput from 'common/components/IAINumberInput'; +import { setPerlin } from 'features/options/optionsSlice'; export default function Perlin() { const dispatch = useAppDispatch(); diff --git a/frontend/src/features/options/AdvancedOptions/Seed/RandomizeSeed.tsx b/frontend/src/features/options/AdvancedOptions/Seed/RandomizeSeed.tsx index 904d82dcc2..d812d165d3 100644 --- a/frontend/src/features/options/AdvancedOptions/Seed/RandomizeSeed.tsx +++ b/frontend/src/features/options/AdvancedOptions/Seed/RandomizeSeed.tsx @@ -4,9 +4,9 @@ import { RootState, useAppDispatch, useAppSelector, -} from '../../../../app/store'; -import IAISwitch from '../../../../common/components/IAISwitch'; -import { setShouldRandomizeSeed } from '../../optionsSlice'; +} from 'app/store'; +import IAISwitch from 'common/components/IAISwitch'; +import { setShouldRandomizeSeed } from 'features/options/optionsSlice'; export default function RandomizeSeed() { const dispatch = useAppDispatch(); diff --git a/frontend/src/features/options/AdvancedOptions/Seed/Seed.tsx b/frontend/src/features/options/AdvancedOptions/Seed/Seed.tsx index 3fc33012cc..46599c7188 100644 --- a/frontend/src/features/options/AdvancedOptions/Seed/Seed.tsx +++ b/frontend/src/features/options/AdvancedOptions/Seed/Seed.tsx @@ -1,12 +1,12 @@ import React from 'react'; -import { NUMPY_RAND_MAX, NUMPY_RAND_MIN } from '../../../../app/constants'; +import { NUMPY_RAND_MAX, NUMPY_RAND_MIN } from 'app/constants'; import { RootState, useAppDispatch, useAppSelector, -} from '../../../../app/store'; -import IAINumberInput from '../../../../common/components/IAINumberInput'; -import { setSeed } from '../../optionsSlice'; +} from 'app/store'; +import IAINumberInput from 'common/components/IAINumberInput'; +import { setSeed } from 'features/options/optionsSlice'; export default function Seed() { const seed = useAppSelector((state: RootState) => state.options.seed); diff --git a/frontend/src/features/options/AdvancedOptions/Seed/ShuffleSeed.tsx b/frontend/src/features/options/AdvancedOptions/Seed/ShuffleSeed.tsx index d2b235ddd0..a95562bc5c 100644 --- a/frontend/src/features/options/AdvancedOptions/Seed/ShuffleSeed.tsx +++ b/frontend/src/features/options/AdvancedOptions/Seed/ShuffleSeed.tsx @@ -1,13 +1,9 @@ import { Button } from '@chakra-ui/react'; import React from 'react'; -import { NUMPY_RAND_MAX, NUMPY_RAND_MIN } from '../../../../app/constants'; -import { - RootState, - useAppDispatch, - useAppSelector, -} from '../../../../app/store'; -import randomInt from '../../../../common/util/randomInt'; -import { setSeed } from '../../optionsSlice'; +import { NUMPY_RAND_MAX, NUMPY_RAND_MIN } from 'app/constants'; +import { RootState, useAppDispatch, useAppSelector } from 'app/store'; +import randomInt from 'common/util/randomInt'; +import { setSeed } from 'features/options/optionsSlice'; export default function ShuffleSeed() { const dispatch = useAppDispatch(); diff --git a/frontend/src/features/options/AdvancedOptions/Seed/Threshold.tsx b/frontend/src/features/options/AdvancedOptions/Seed/Threshold.tsx index 1b0f0e106e..a80b5497da 100644 --- a/frontend/src/features/options/AdvancedOptions/Seed/Threshold.tsx +++ b/frontend/src/features/options/AdvancedOptions/Seed/Threshold.tsx @@ -3,9 +3,9 @@ import { RootState, useAppDispatch, useAppSelector, -} from '../../../../app/store'; -import IAINumberInput from '../../../../common/components/IAINumberInput'; -import { setThreshold } from '../../optionsSlice'; +} from 'app/store'; +import IAINumberInput from 'common/components/IAINumberInput'; +import { setThreshold } from 'features/options/optionsSlice'; export default function Threshold() { const dispatch = useAppDispatch(); diff --git a/frontend/src/features/options/AdvancedOptions/Upscale/UpscaleHeader.tsx b/frontend/src/features/options/AdvancedOptions/Upscale/UpscaleHeader.tsx index 4bb0347f04..10d37800b4 100644 --- a/frontend/src/features/options/AdvancedOptions/Upscale/UpscaleHeader.tsx +++ b/frontend/src/features/options/AdvancedOptions/Upscale/UpscaleHeader.tsx @@ -4,9 +4,9 @@ import { RootState, useAppDispatch, useAppSelector, -} from '../../../../app/store'; -import IAISwitch from '../../../../common/components/IAISwitch'; -import { setShouldRunESRGAN } from '../../optionsSlice'; +} from 'app/store'; +import IAISwitch from 'common/components/IAISwitch'; +import { setShouldRunESRGAN } from 'features/options/optionsSlice'; export default function UpscaleHeader() { const isESRGANAvailable = useAppSelector( diff --git a/frontend/src/features/options/AdvancedOptions/Upscale/UpscaleOptions.tsx b/frontend/src/features/options/AdvancedOptions/Upscale/UpscaleOptions.tsx index 482f773aa0..e95c367e95 100644 --- a/frontend/src/features/options/AdvancedOptions/Upscale/UpscaleOptions.tsx +++ b/frontend/src/features/options/AdvancedOptions/Upscale/UpscaleOptions.tsx @@ -1,20 +1,20 @@ -import { RootState } from '../../../../app/store'; -import { useAppDispatch, useAppSelector } from '../../../../app/store'; +import { RootState } from 'app/store'; +import { useAppDispatch, useAppSelector } from 'app/store'; import { setUpscalingLevel, setUpscalingStrength, UpscalingLevel, OptionsState, -} from '../../optionsSlice'; +} from 'features/options/optionsSlice'; -import { UPSCALING_LEVELS } from '../../../../app/constants'; +import { UPSCALING_LEVELS } from 'app/constants'; import { createSelector } from '@reduxjs/toolkit'; import { isEqual } from 'lodash'; -import { SystemState } from '../../../system/systemSlice'; +import { SystemState } from 'features/system/systemSlice'; import { ChangeEvent } from 'react'; -import IAINumberInput from '../../../../common/components/IAINumberInput'; -import IAISelect from '../../../../common/components/IAISelect'; +import IAINumberInput from 'common/components/IAINumberInput'; +import IAISelect from 'common/components/IAISelect'; const optionsSelector = createSelector( (state: RootState) => state.options, diff --git a/frontend/src/features/options/AdvancedOptions/Variations/GenerateVariations.tsx b/frontend/src/features/options/AdvancedOptions/Variations/GenerateVariations.tsx index f17685b0a9..8d9d0fb522 100644 --- a/frontend/src/features/options/AdvancedOptions/Variations/GenerateVariations.tsx +++ b/frontend/src/features/options/AdvancedOptions/Variations/GenerateVariations.tsx @@ -3,9 +3,9 @@ import { RootState, useAppDispatch, useAppSelector, -} from '../../../../app/store'; -import IAISwitch from '../../../../common/components/IAISwitch'; -import { setShouldGenerateVariations } from '../../optionsSlice'; +} from 'app/store'; +import IAISwitch from 'common/components/IAISwitch'; +import { setShouldGenerateVariations } from 'features/options/optionsSlice'; export default function GenerateVariations() { const shouldGenerateVariations = useAppSelector( diff --git a/frontend/src/features/options/AdvancedOptions/Variations/SeedWeights.tsx b/frontend/src/features/options/AdvancedOptions/Variations/SeedWeights.tsx index 10e7d754b4..627b5458ee 100644 --- a/frontend/src/features/options/AdvancedOptions/Variations/SeedWeights.tsx +++ b/frontend/src/features/options/AdvancedOptions/Variations/SeedWeights.tsx @@ -3,10 +3,10 @@ import { RootState, useAppDispatch, useAppSelector, -} from '../../../../app/store'; -import IAIInput from '../../../../common/components/IAIInput'; -import { validateSeedWeights } from '../../../../common/util/seedWeightPairs'; -import { setSeedWeights } from '../../optionsSlice'; +} from 'app/store'; +import IAIInput from 'common/components/IAIInput'; +import { validateSeedWeights } from 'common/util/seedWeightPairs'; +import { setSeedWeights } from 'features/options/optionsSlice'; export default function SeedWeights() { const seedWeights = useAppSelector( diff --git a/frontend/src/features/options/AdvancedOptions/Variations/VariationAmount.tsx b/frontend/src/features/options/AdvancedOptions/Variations/VariationAmount.tsx index 24fc81bb3e..9114aaeb64 100644 --- a/frontend/src/features/options/AdvancedOptions/Variations/VariationAmount.tsx +++ b/frontend/src/features/options/AdvancedOptions/Variations/VariationAmount.tsx @@ -3,9 +3,9 @@ import { RootState, useAppDispatch, useAppSelector, -} from '../../../../app/store'; -import IAINumberInput from '../../../../common/components/IAINumberInput'; -import { setVariationAmount } from '../../optionsSlice'; +} from 'app/store'; +import IAINumberInput from 'common/components/IAINumberInput'; +import { setVariationAmount } from 'features/options/optionsSlice'; export default function VariationAmount() { const variationAmount = useAppSelector( diff --git a/frontend/src/features/options/MainOptions/MainAdvancedOptionsCheckbox.tsx b/frontend/src/features/options/MainOptions/MainAdvancedOptionsCheckbox.tsx index b8b580856e..aa88af0382 100644 --- a/frontend/src/features/options/MainOptions/MainAdvancedOptionsCheckbox.tsx +++ b/frontend/src/features/options/MainOptions/MainAdvancedOptionsCheckbox.tsx @@ -1,7 +1,7 @@ import React, { ChangeEvent } from 'react'; -import { RootState, useAppDispatch, useAppSelector } from '../../../app/store'; -import IAICheckbox from '../../../common/components/IAICheckbox'; -import { setShowAdvancedOptions } from '../optionsSlice'; +import { RootState, useAppDispatch, useAppSelector } from 'app/store'; +import IAICheckbox from 'common/components/IAICheckbox'; +import { setShowAdvancedOptions } from 'features/options/optionsSlice'; export default function MainAdvancedOptionsCheckbox() { const showAdvancedOptions = useAppSelector( diff --git a/frontend/src/features/options/MainOptions/MainCFGScale.tsx b/frontend/src/features/options/MainOptions/MainCFGScale.tsx index 07395c9fb6..3a4b753b91 100644 --- a/frontend/src/features/options/MainOptions/MainCFGScale.tsx +++ b/frontend/src/features/options/MainOptions/MainCFGScale.tsx @@ -1,8 +1,8 @@ import React from 'react'; -import { RootState, useAppDispatch, useAppSelector } from '../../../app/store'; -import IAINumberInput from '../../../common/components/IAINumberInput'; -import { setCfgScale } from '../optionsSlice'; -import { fontSize, inputWidth } from './MainOptions'; +import { RootState, useAppDispatch, useAppSelector } from 'app/store'; +import IAINumberInput from 'common/components/IAINumberInput'; +import { setCfgScale } from 'features/options/optionsSlice'; +import { inputWidth } from './MainOptions'; export default function MainCFGScale() { const dispatch = useAppDispatch(); @@ -19,7 +19,6 @@ export default function MainCFGScale() { onChange={handleChangeCfgScale} value={cfgScale} width={inputWidth} - fontSize={fontSize} styleClass="main-option-block" textAlign="center" isInteger={false} diff --git a/frontend/src/features/options/MainOptions/MainHeight.tsx b/frontend/src/features/options/MainOptions/MainHeight.tsx index 78285f7944..61ba0eb25c 100644 --- a/frontend/src/features/options/MainOptions/MainHeight.tsx +++ b/frontend/src/features/options/MainOptions/MainHeight.tsx @@ -1,10 +1,9 @@ import React, { ChangeEvent } from 'react'; -import { HEIGHTS } from '../../../app/constants'; -import { RootState, useAppDispatch, useAppSelector } from '../../../app/store'; -import IAISelect from '../../../common/components/IAISelect'; -import { activeTabNameSelector } from '../optionsSelectors'; -import { setHeight } from '../optionsSlice'; -import { fontSize } from './MainOptions'; +import { HEIGHTS } from 'app/constants'; +import { RootState, useAppDispatch, useAppSelector } from 'app/store'; +import IAISelect from 'common/components/IAISelect'; +import { activeTabNameSelector } from 'features/options/optionsSelectors'; +import { setHeight } from 'features/options/optionsSlice'; export default function MainHeight() { const height = useAppSelector((state: RootState) => state.options.height); @@ -22,7 +21,6 @@ export default function MainHeight() { flexGrow={1} onChange={handleChangeHeight} validValues={HEIGHTS} - fontSize={fontSize} styleClass="main-option-block" /> ); diff --git a/frontend/src/features/options/MainOptions/MainIterations.tsx b/frontend/src/features/options/MainOptions/MainIterations.tsx index e244e02f05..10986f994e 100644 --- a/frontend/src/features/options/MainOptions/MainIterations.tsx +++ b/frontend/src/features/options/MainOptions/MainIterations.tsx @@ -1,11 +1,11 @@ import { createSelector } from '@reduxjs/toolkit'; import _ from 'lodash'; import React from 'react'; -import { RootState, useAppDispatch, useAppSelector } from '../../../app/store'; -import IAINumberInput from '../../../common/components/IAINumberInput'; -import { mayGenerateMultipleImagesSelector } from '../optionsSelectors'; -import { OptionsState, setIterations } from '../optionsSlice'; -import { fontSize, inputWidth } from './MainOptions'; +import { RootState, useAppDispatch, useAppSelector } from 'app/store'; +import IAINumberInput from 'common/components/IAINumberInput'; +import { mayGenerateMultipleImagesSelector } from 'features/options/optionsSelectors'; +import { OptionsState, setIterations } from 'features/options/optionsSlice'; +import { inputWidth } from './MainOptions'; const mainIterationsSelector = createSelector( [(state: RootState) => state.options, mayGenerateMultipleImagesSelector], @@ -42,7 +42,7 @@ export default function MainIterations() { onChange={handleChangeIterations} value={iterations} width={inputWidth} - fontSize={fontSize} + labelFontSize={0.5} styleClass="main-option-block" textAlign="center" /> diff --git a/frontend/src/features/options/MainOptions/MainOptions.scss b/frontend/src/features/options/MainOptions/MainOptions.scss index b9854397a5..40423a112c 100644 --- a/frontend/src/features/options/MainOptions/MainOptions.scss +++ b/frontend/src/features/options/MainOptions/MainOptions.scss @@ -13,7 +13,7 @@ .main-options-row { display: grid; grid-template-columns: repeat(3, auto); - column-gap: 1rem; + column-gap: 0.5rem; max-width: $options-bar-max-width; } @@ -21,27 +21,22 @@ border-radius: 0.5rem; display: grid !important; grid-template-columns: auto !important; - row-gap: 0.4rem; + row-gap: 0.5rem; .invokeai__number-input-form-label, .invokeai__select-label { - width: 100%; - font-size: 0.9rem !important; font-weight: bold; + font-size: 0.9rem !important; } - .number-input-entry { - padding: 0; - height: 2.4rem; - } - - .iai-select-picker { - height: 2.4rem; - border-radius: 0.3rem; + .invokeai__select-label { + margin: 0; } } .advanced-options-checkbox { - padding: 1rem; + background-color: var(--background-color-secondary); + padding: 0.5rem 1rem; + border-radius: 0.4rem; font-weight: bold; } diff --git a/frontend/src/features/options/MainOptions/MainOptions.tsx b/frontend/src/features/options/MainOptions/MainOptions.tsx index 092cdea50d..15b92652ec 100644 --- a/frontend/src/features/options/MainOptions/MainOptions.tsx +++ b/frontend/src/features/options/MainOptions/MainOptions.tsx @@ -5,7 +5,6 @@ import MainSampler from './MainSampler'; import MainSteps from './MainSteps'; import MainWidth from './MainWidth'; -export const fontSize = '0.9rem'; export const inputWidth = 'auto'; export default function MainOptions() { diff --git a/frontend/src/features/options/MainOptions/MainSampler.tsx b/frontend/src/features/options/MainOptions/MainSampler.tsx index c6b0ae7dd3..992207aa6e 100644 --- a/frontend/src/features/options/MainOptions/MainSampler.tsx +++ b/frontend/src/features/options/MainOptions/MainSampler.tsx @@ -1,9 +1,8 @@ import React, { ChangeEvent } from 'react'; -import { SAMPLERS } from '../../../app/constants'; -import { RootState, useAppDispatch, useAppSelector } from '../../../app/store'; -import IAISelect from '../../../common/components/IAISelect'; -import { setSampler } from '../optionsSlice'; -import { fontSize } from './MainOptions'; +import { SAMPLERS } from 'app/constants'; +import { RootState, useAppDispatch, useAppSelector } from 'app/store'; +import IAISelect from 'common/components/IAISelect'; +import { setSampler } from 'features/options/optionsSlice'; export default function MainSampler() { const sampler = useAppSelector((state: RootState) => state.options.sampler); @@ -18,7 +17,6 @@ export default function MainSampler() { value={sampler} onChange={handleChangeSampler} validValues={SAMPLERS} - fontSize={fontSize} styleClass="main-option-block" /> ); diff --git a/frontend/src/features/options/MainOptions/MainSteps.tsx b/frontend/src/features/options/MainOptions/MainSteps.tsx index 20670fc208..16be24a087 100644 --- a/frontend/src/features/options/MainOptions/MainSteps.tsx +++ b/frontend/src/features/options/MainOptions/MainSteps.tsx @@ -1,8 +1,8 @@ import React from 'react'; -import { RootState, useAppDispatch, useAppSelector } from '../../../app/store'; -import IAINumberInput from '../../../common/components/IAINumberInput'; -import { setSteps } from '../optionsSlice'; -import { fontSize, inputWidth } from './MainOptions'; +import { RootState, useAppDispatch, useAppSelector } from 'app/store'; +import IAINumberInput from 'common/components/IAINumberInput'; +import { setSteps } from 'features/options/optionsSlice'; +import { inputWidth } from './MainOptions'; export default function MainSteps() { const dispatch = useAppDispatch(); @@ -19,7 +19,6 @@ export default function MainSteps() { onChange={handleChangeSteps} value={steps} width={inputWidth} - fontSize={fontSize} styleClass="main-option-block" textAlign="center" /> diff --git a/frontend/src/features/options/MainOptions/MainWidth.tsx b/frontend/src/features/options/MainOptions/MainWidth.tsx index 69841f3954..779b1cb1ac 100644 --- a/frontend/src/features/options/MainOptions/MainWidth.tsx +++ b/frontend/src/features/options/MainOptions/MainWidth.tsx @@ -1,10 +1,9 @@ import React, { ChangeEvent } from 'react'; -import { WIDTHS } from '../../../app/constants'; -import { RootState, useAppDispatch, useAppSelector } from '../../../app/store'; -import IAISelect from '../../../common/components/IAISelect'; -import { activeTabNameSelector } from '../optionsSelectors'; -import { setWidth } from '../optionsSlice'; -import { fontSize } from './MainOptions'; +import { WIDTHS } from 'app/constants'; +import { RootState, useAppDispatch, useAppSelector } from 'app/store'; +import IAISelect from 'common/components/IAISelect'; +import { activeTabNameSelector } from 'features/options/optionsSelectors'; +import { setWidth } from 'features/options/optionsSlice'; export default function MainWidth() { const width = useAppSelector((state: RootState) => state.options.width); @@ -23,7 +22,6 @@ export default function MainWidth() { flexGrow={1} onChange={handleChangeWidth} validValues={WIDTHS} - fontSize={fontSize} styleClass="main-option-block" /> ); diff --git a/frontend/src/features/options/OptionsAccordion.tsx b/frontend/src/features/options/OptionsAccordion.tsx index 9971d017a0..c3c1d68162 100644 --- a/frontend/src/features/options/OptionsAccordion.tsx +++ b/frontend/src/features/options/OptionsAccordion.tsx @@ -1,6 +1,6 @@ import { Accordion, ExpandedIndex } from '@chakra-ui/react'; -import { RootState, useAppDispatch, useAppSelector } from '../../app/store'; -import { setOpenAccordions } from '../system/systemSlice'; +import { RootState, useAppDispatch, useAppSelector } from 'app/store'; +import { setOpenAccordions } from 'features/system/systemSlice'; import InvokeAccordionItem, { InvokeAccordionItemProps, } from './AccordionItems/InvokeAccordionItem'; diff --git a/frontend/src/features/options/ProcessButtons/CancelButton.tsx b/frontend/src/features/options/ProcessButtons/CancelButton.tsx index 7034a0338f..bd77ccd973 100644 --- a/frontend/src/features/options/ProcessButtons/CancelButton.tsx +++ b/frontend/src/features/options/ProcessButtons/CancelButton.tsx @@ -1,12 +1,12 @@ import { MdCancel } from 'react-icons/md'; -import { cancelProcessing } from '../../../app/socketio/actions'; -import { RootState, useAppDispatch, useAppSelector } from '../../../app/store'; +import { cancelProcessing } from 'app/socketio/actions'; +import { RootState, useAppDispatch, useAppSelector } from 'app/store'; import IAIIconButton, { IAIIconButtonProps, -} from '../../../common/components/IAIIconButton'; +} from 'common/components/IAIIconButton'; import { useHotkeys } from 'react-hotkeys-hook'; import { createSelector } from '@reduxjs/toolkit'; -import { SystemState } from '../../system/systemSlice'; +import { SystemState } from 'features/system/systemSlice'; import _ from 'lodash'; const cancelButtonSelector = createSelector( diff --git a/frontend/src/features/options/ProcessButtons/InvokeButton.tsx b/frontend/src/features/options/ProcessButtons/InvokeButton.tsx index e9a61002b4..793aa3fded 100644 --- a/frontend/src/features/options/ProcessButtons/InvokeButton.tsx +++ b/frontend/src/features/options/ProcessButtons/InvokeButton.tsx @@ -1,17 +1,15 @@ import { ListItem, UnorderedList } from '@chakra-ui/react'; import { useHotkeys } from 'react-hotkeys-hook'; import { FaPlay } from 'react-icons/fa'; -import { readinessSelector } from '../../../app/selectors/readinessSelector'; -import { generateImage } from '../../../app/socketio/actions'; -import { useAppDispatch, useAppSelector } from '../../../app/store'; -import IAIButton, { - IAIButtonProps, -} from '../../../common/components/IAIButton'; +import { readinessSelector } from 'app/selectors/readinessSelector'; +import { generateImage } from 'app/socketio/actions'; +import { useAppDispatch, useAppSelector } from 'app/store'; +import IAIButton, { IAIButtonProps } from 'common/components/IAIButton'; import IAIIconButton, { IAIIconButtonProps, -} from '../../../common/components/IAIIconButton'; -import IAIPopover from '../../../common/components/IAIPopover'; -import { activeTabNameSelector } from '../optionsSelectors'; +} from 'common/components/IAIIconButton'; +import IAIPopover from 'common/components/IAIPopover'; +import { activeTabNameSelector } from 'features/options/optionsSelectors'; interface InvokeButton extends Omit { @@ -29,7 +27,7 @@ export default function InvokeButton(props: InvokeButton) { }; useHotkeys( - 'ctrl+enter, cmd+enter', + ['ctrl+enter', 'meta+enter'], () => { if (isReady) { dispatch(generateImage(activeTabName)); @@ -47,7 +45,7 @@ export default function InvokeButton(props: InvokeButton) { icon={} isDisabled={!isReady} onClick={handleClickGenerate} - className="invoke-btn invoke" + className="invoke-btn" tooltip="Invoke" tooltipProps={{ placement: 'bottom' }} {...rest} @@ -80,20 +78,4 @@ export default function InvokeButton(props: InvokeButton) { )} ); - - // return isReady ? ( - // buttonComponent - // ) : ( - // - // {reasonsWhyNotReady ? ( - // - // {reasonsWhyNotReady.map((reason, i) => ( - // {reason} - // ))} - // - // ) : ( - // 'test' - // )} - // - // ); } diff --git a/frontend/src/features/options/ProcessButtons/Loopback.tsx b/frontend/src/features/options/ProcessButtons/Loopback.tsx index 6d360f4f25..77eb5530f6 100644 --- a/frontend/src/features/options/ProcessButtons/Loopback.tsx +++ b/frontend/src/features/options/ProcessButtons/Loopback.tsx @@ -1,8 +1,8 @@ import { createSelector } from '@reduxjs/toolkit'; import { FaRecycle } from 'react-icons/fa'; -import { RootState, useAppDispatch, useAppSelector } from '../../../app/store'; -import IAIIconButton from '../../../common/components/IAIIconButton'; -import { OptionsState, setShouldLoopback } from '../optionsSlice'; +import { RootState, useAppDispatch, useAppSelector } from 'app/store'; +import IAIIconButton from 'common/components/IAIIconButton'; +import { OptionsState, setShouldLoopback } from 'features/options/optionsSlice'; const loopbackSelector = createSelector( (state: RootState) => state.options, diff --git a/frontend/src/features/options/ProcessButtons/ProcessButtons.scss b/frontend/src/features/options/ProcessButtons/ProcessButtons.scss index 0c107e0865..3b39cb55aa 100644 --- a/frontend/src/features/options/ProcessButtons/ProcessButtons.scss +++ b/frontend/src/features/options/ProcessButtons/ProcessButtons.scss @@ -8,14 +8,11 @@ .invoke-btn { flex-grow: 1; width: 100%; - svg { - width: 18px !important; - height: 18px !important; - } + @include Button( $btn-color: var(--accent-color), $btn-color-hover: var(--accent-color-hover), - // $btn-width: 5rem + $icon-size: 16px ); } @@ -23,19 +20,19 @@ @include Button( $btn-color: var(--destructive-color), $btn-color-hover: var(--destructive-color-hover), - // $btn-width: 3rem + $btn-width: 3rem ); } .loopback-btn { &[data-as-checkbox='true'] { - background-color: var(--btn-grey); - border: 3px solid var(--btn-grey); + background-color: var(--btn-btn-base-color); + border: 3px solid var(--btn-btn-base-color); svg { fill: var(--text-color); } &:hover { - background-color: var(--btn-grey); + background-color: var(--btn-btn-base-color); border-color: var(--btn-checkbox-border-hover); svg { fill: var(--text-color); @@ -43,13 +40,13 @@ } &[data-selected='true'] { border-color: var(--accent-color); - background-color: var(--btn-grey); + background-color: var(--btn-btn-base-color); svg { fill: var(--text-color); } &:hover { border-color: var(--accent-color); - background-color: var(--btn-grey); + background-color: var(--btn-btn-base-color); svg { fill: var(--text-color); } diff --git a/frontend/src/features/options/PromptInput/PromptInput.tsx b/frontend/src/features/options/PromptInput/PromptInput.tsx index 035d085013..165a82d651 100644 --- a/frontend/src/features/options/PromptInput/PromptInput.tsx +++ b/frontend/src/features/options/PromptInput/PromptInput.tsx @@ -1,14 +1,14 @@ import { FormControl, Textarea } from '@chakra-ui/react'; import { ChangeEvent, KeyboardEvent, useRef } from 'react'; -import { RootState, useAppDispatch, useAppSelector } from '../../../app/store'; -import { generateImage } from '../../../app/socketio/actions'; +import { RootState, useAppDispatch, useAppSelector } from 'app/store'; +import { generateImage } from 'app/socketio/actions'; -import { OptionsState, setPrompt } from '../optionsSlice'; +import { OptionsState, setPrompt } from 'features/options/optionsSlice'; import { createSelector } from '@reduxjs/toolkit'; import _ from 'lodash'; import { useHotkeys } from 'react-hotkeys-hook'; -import { activeTabNameSelector } from '../optionsSelectors'; -import { readinessSelector } from '../../../app/selectors/readinessSelector'; +import { activeTabNameSelector } from 'features/options/optionsSelectors'; +import { readinessSelector } from 'app/selectors/readinessSelector'; const promptInputSelector = createSelector( [(state: RootState) => state.options, activeTabNameSelector], diff --git a/frontend/src/features/options/optionsSelectors.ts b/frontend/src/features/options/optionsSelectors.ts index 6a1f31c850..c02512e34f 100644 --- a/frontend/src/features/options/optionsSelectors.ts +++ b/frontend/src/features/options/optionsSelectors.ts @@ -1,7 +1,7 @@ import { createSelector } from '@reduxjs/toolkit'; import _ from 'lodash'; -import { RootState } from '../../app/store'; -import { tabMap } from '../tabs/InvokeTabs'; +import { RootState } from 'app/store'; +import { tabMap } from 'features/tabs/InvokeTabs'; import { OptionsState } from './optionsSlice'; export const activeTabNameSelector = createSelector( diff --git a/frontend/src/features/options/optionsSlice.ts b/frontend/src/features/options/optionsSlice.ts index 64f40a0307..1b6d3f63d9 100644 --- a/frontend/src/features/options/optionsSlice.ts +++ b/frontend/src/features/options/optionsSlice.ts @@ -1,10 +1,10 @@ import { createSlice } from '@reduxjs/toolkit'; import type { PayloadAction } from '@reduxjs/toolkit'; -import * as InvokeAI from '../../app/invokeai'; -import promptToString from '../../common/util/promptToString'; -import { seedWeightsToString } from '../../common/util/seedWeightPairs'; -import { FACETOOL_TYPES } from '../../app/constants'; -import { InvokeTabName, tabMap } from '../tabs/InvokeTabs'; +import * as InvokeAI from 'app/invokeai'; +import promptToString from 'common/util/promptToString'; +import { seedWeightsToString } from 'common/util/seedWeightPairs'; +import { FACETOOL_TYPES } from 'app/constants'; +import { InvokeTabName, tabMap } from 'features/tabs/InvokeTabs'; export type UpscalingLevel = 2 | 4; @@ -47,6 +47,8 @@ export interface OptionsState { optionsPanelScrollPosition: number; shouldHoldOptionsPanelOpen: boolean; shouldLoopback: boolean; + currentTheme: string; + isLightBoxOpen: boolean; } const initialOptionsState: OptionsState = { @@ -85,6 +87,8 @@ const initialOptionsState: OptionsState = { optionsPanelScrollPosition: 0, shouldHoldOptionsPanelOpen: false, shouldLoopback: false, + currentTheme: 'dark', + isLightBoxOpen: false, }; const initialState: OptionsState = initialOptionsState; @@ -349,6 +353,12 @@ export const optionsSlice = createSlice({ setShouldLoopback: (state, action: PayloadAction) => { state.shouldLoopback = action.payload; }, + setCurrentTheme: (state, action: PayloadAction) => { + state.currentTheme = action.payload; + }, + setIsLightBoxOpen: (state, action: PayloadAction) => { + state.isLightBoxOpen = action.payload; + }, }, }); @@ -396,6 +406,8 @@ export const { setOptionsPanelScrollPosition, setShouldHoldOptionsPanelOpen, setShouldLoopback, + setCurrentTheme, + setIsLightBoxOpen, } = optionsSlice.actions; export default optionsSlice.reducer; diff --git a/frontend/src/features/system/Console.scss b/frontend/src/features/system/Console.scss index 0246e33ca3..e043d58d51 100644 --- a/frontend/src/features/system/Console.scss +++ b/frontend/src/features/system/Console.scss @@ -37,39 +37,39 @@ } .console-toggle-icon-button { - background: var(--console-icon-button-bg-color) !important; - position: fixed !important; + background: var(--console-icon-button-bg-color); + position: fixed; left: 0.5rem; bottom: 0.5rem; z-index: 10000; &:hover { - background: var(--console-icon-button-bg-color-hover) !important; + background: var(--console-icon-button-bg-color-hover); } &[data-error-seen='true'] { - background: var(--status-bad-color) !important; + background: var(--status-bad-color); &:hover { - background: var(--status-bad-color) !important; + background: var(--status-bad-color); } } } .console-autoscroll-icon-button { - background: var(--console-icon-button-bg-color) !important; - position: fixed !important; + background: var(--console-icon-button-bg-color); + position: fixed; left: 0.5rem; bottom: 3rem; z-index: 10000; &:hover { - background: var(--console-icon-button-bg-color-hover) !important; + background: var(--console-icon-button-bg-color-hover); } &[data-autoscroll-enabled='true'] { - background: var(--accent-color) !important; + background: var(--accent-color); &:hover { - background: var(--accent-color-hover) !important; + background: var(--accent-color-hover); } } } diff --git a/frontend/src/features/system/Console.tsx b/frontend/src/features/system/Console.tsx index 2916d740f4..ed5867437d 100644 --- a/frontend/src/features/system/Console.tsx +++ b/frontend/src/features/system/Console.tsx @@ -1,6 +1,6 @@ import { IconButton, Tooltip } from '@chakra-ui/react'; -import { useAppDispatch, useAppSelector } from '../../app/store'; -import { RootState } from '../../app/store'; +import { useAppDispatch, useAppSelector } from 'app/store'; +import { RootState } from 'app/store'; import { errorSeen, setShouldShowLogViewer, SystemState } from './systemSlice'; import { useLayoutEffect, useRef, useState } from 'react'; import { FaAngleDoubleDown, FaCode, FaMinus } from 'react-icons/fa'; diff --git a/frontend/src/features/system/HotkeysModal/HotkeysModal.scss b/frontend/src/features/system/HotkeysModal/HotkeysModal.scss index 0a216b5c4b..5dd544a68e 100644 --- a/frontend/src/features/system/HotkeysModal/HotkeysModal.scss +++ b/frontend/src/features/system/HotkeysModal/HotkeysModal.scss @@ -1,11 +1,10 @@ @use '../../../styles/Mixins/' as *; .hotkeys-modal { - width: 36rem !important; - max-width: 36rem !important; + width: 36rem; + max-width: 36rem; display: grid; padding: 1rem; - background-color: var(--settings-modal-bg) !important; row-gap: 1rem; font-family: Inter; @@ -42,7 +41,7 @@ } button { - border-radius: 0.3rem !important; + border-radius: 0.3rem; &[aria-expanded='true'] { background-color: var(--tab-hover-color); @@ -81,7 +80,7 @@ .hotkey-key { font-size: 0.8rem; font-weight: bold; - border: 2px solid var(--settings-modal-bg); + background-color: var(--background-color-light); padding: 0.2rem 0.5rem; border-radius: 0.3rem; } diff --git a/frontend/src/features/system/HotkeysModal/HotkeysModal.tsx b/frontend/src/features/system/HotkeysModal/HotkeysModal.tsx index 0c36f5fda9..90f83f569f 100644 --- a/frontend/src/features/system/HotkeysModal/HotkeysModal.tsx +++ b/frontend/src/features/system/HotkeysModal/HotkeysModal.tsx @@ -49,21 +49,27 @@ export default function HotkeysModal({ children }: HotkeysModalProps) { desc: 'Pin the options panel', hotkey: 'Shift+O', }, + { + title: 'Toggle Viewer', + desc: 'Open and close Image Viewer', + hotkey: 'V', + }, { title: 'Toggle Gallery', desc: 'Open and close the gallery drawer', hotkey: 'G', }, + { + title: 'Maximize Workspace', + desc: 'Close panels and maximize work area', + hotkey: 'F', + }, { title: 'Change Tabs', desc: 'Switch to another workspace', hotkey: '1-6', }, - { - title: 'Theme Toggle', - desc: 'Switch between dark and light modes', - hotkey: 'Shift+D', - }, + { title: 'Console Toggle', desc: 'Open and close console', @@ -200,12 +206,17 @@ export default function HotkeysModal({ children }: HotkeysModalProps) { { title: 'Lock Bounding Box', desc: 'Locks the bounding box', - hotkey: 'Shift+Q', + hotkey: 'Shift+W', + }, + { + title: 'Show/Hide Bounding Box', + desc: 'Toggle visibility of bounding box', + hotkey: 'Shift+H', }, { title: 'Quick Toggle Lock Bounding Box', desc: 'Hold to toggle locking the bounding box', - hotkey: 'Q', + hotkey: 'W', }, { title: 'Expand Inpainting Area', @@ -214,6 +225,14 @@ export default function HotkeysModal({ children }: HotkeysModalProps) { }, ]; + const outpaintingHotkeys = [ + { + title: 'Erase Canvas', + desc: 'Erase the images on the canvas', + hotkey: 'Shift+E', + }, + ]; + const renderHotkeyModalItems = (hotkeys: HotkeyList[]) => { const hotkeyModalItemsToRender: ReactElement[] = []; @@ -240,8 +259,8 @@ export default function HotkeysModal({ children }: HotkeysModalProps) { })} - - + +

Keyboard Shorcuts

@@ -285,6 +304,16 @@ export default function HotkeysModal({ children }: HotkeysModalProps) { {renderHotkeyModalItems(inpaintingHotkeys)} + + + +

Outpainting Hotkeys

+ +
+ + {renderHotkeyModalItems(outpaintingHotkeys)} + +
diff --git a/frontend/src/features/system/Modal.scss b/frontend/src/features/system/Modal.scss new file mode 100644 index 0000000000..7ba1233fb3 --- /dev/null +++ b/frontend/src/features/system/Modal.scss @@ -0,0 +1,10 @@ +@use '../../styles/Mixins/' as *; + +.modal { + background-color: var(--background-color-secondary); + color: var(--text-color); +} + +.modal-close-btn { + @include BaseButton; +} diff --git a/frontend/src/features/system/ProgressBar.scss b/frontend/src/features/system/ProgressBar.scss index dcbcec98b5..9f60d5b8fc 100644 --- a/frontend/src/features/system/ProgressBar.scss +++ b/frontend/src/features/system/ProgressBar.scss @@ -2,7 +2,7 @@ .progress-bar { background-color: var(--root-bg-color); - height: $progress-bar-thickness !important; + height: $progress-bar-thickness; z-index: 99; div { diff --git a/frontend/src/features/system/ProgressBar.tsx b/frontend/src/features/system/ProgressBar.tsx index 9cbfcb8c5d..fa1d61f81b 100644 --- a/frontend/src/features/system/ProgressBar.tsx +++ b/frontend/src/features/system/ProgressBar.tsx @@ -1,9 +1,9 @@ import { Progress } from '@chakra-ui/react'; import { createSelector } from '@reduxjs/toolkit'; import { isEqual } from 'lodash'; -import { useAppSelector } from '../../app/store'; -import { RootState } from '../../app/store'; -import { SystemState } from '../system/systemSlice'; +import { useAppSelector } from 'app/store'; +import { RootState } from 'app/store'; +import { SystemState } from 'features/system/systemSlice'; const systemSelector = createSelector( (state: RootState) => state.system, diff --git a/frontend/src/features/system/SettingsModal/ModelList.scss b/frontend/src/features/system/SettingsModal/ModelList.scss index f7951b0c7e..47e2d593c3 100644 --- a/frontend/src/features/system/SettingsModal/ModelList.scss +++ b/frontend/src/features/system/SettingsModal/ModelList.scss @@ -8,7 +8,7 @@ // } // button { -// border-radius: 0.3rem !important; +// border-radius: 0.3rem; // &[aria-expanded='true'] { // // background-color: var(--tab-hover-color); @@ -29,7 +29,7 @@ } div { - border: none !important; + border: none; } .model-list-button { @@ -79,6 +79,13 @@ .model-list-item-load-btn { button { padding: 0.5rem; + background-color: var(--btn-base-color); + color: var(--text-color); + border-radius: 0.2rem; + + &:hover { + background-color: var(--btn-base-color-hover); + } } } } diff --git a/frontend/src/features/system/SettingsModal/ModelList.tsx b/frontend/src/features/system/SettingsModal/ModelList.tsx index 66fc5129de..0feab08db8 100644 --- a/frontend/src/features/system/SettingsModal/ModelList.tsx +++ b/frontend/src/features/system/SettingsModal/ModelList.tsx @@ -10,10 +10,10 @@ import { } from '@chakra-ui/react'; import { createSelector } from '@reduxjs/toolkit'; import _ from 'lodash'; -import { ModelStatus } from '../../../app/invokeai'; -import { requestModelChange } from '../../../app/socketio/actions'; -import { RootState, useAppDispatch, useAppSelector } from '../../../app/store'; -import { SystemState } from '../systemSlice'; +import { ModelStatus } from 'app/invokeai'; +import { requestModelChange } from 'app/socketio/actions'; +import { RootState, useAppDispatch, useAppSelector } from 'app/store'; +import { SystemState } from 'features/system/systemSlice'; type ModelListItemProps = { name: string; diff --git a/frontend/src/features/system/SettingsModal/SettingsModal.scss b/frontend/src/features/system/SettingsModal/SettingsModal.scss index 27adb3025e..689fcd22e5 100644 --- a/frontend/src/features/system/SettingsModal/SettingsModal.scss +++ b/frontend/src/features/system/SettingsModal/SettingsModal.scss @@ -1,7 +1,6 @@ @use '../../../styles/Mixins/' as *; .settings-modal { - background-color: var(--settings-modal-bg) !important; max-height: 36rem; font-family: Inter; diff --git a/frontend/src/features/system/SettingsModal/SettingsModal.tsx b/frontend/src/features/system/SettingsModal/SettingsModal.tsx index 835f3fe296..174a5cca1b 100644 --- a/frontend/src/features/system/SettingsModal/SettingsModal.tsx +++ b/frontend/src/features/system/SettingsModal/SettingsModal.tsx @@ -15,21 +15,22 @@ import { import { createSelector } from '@reduxjs/toolkit'; import _, { isEqual } from 'lodash'; import { ChangeEvent, cloneElement, ReactElement } from 'react'; -import { RootState, useAppDispatch, useAppSelector } from '../../../app/store'; -import { persistor } from '../../../main'; +import { RootState, useAppDispatch, useAppSelector } from 'app/store'; +import { persistor } from 'main'; import { InProgressImageType, + setEnableImageDebugging, setSaveIntermediatesInterval, setShouldConfirmOnDelete, setShouldDisplayGuides, setShouldDisplayInProgressType, SystemState, -} from '../systemSlice'; +} from 'features/system/systemSlice'; import ModelList from './ModelList'; -import { IN_PROGRESS_IMAGE_TYPES } from '../../../app/constants'; -import IAISwitch from '../../../common/components/IAISwitch'; -import IAISelect from '../../../common/components/IAISelect'; -import IAINumberInput from '../../../common/components/IAINumberInput'; +import { IN_PROGRESS_IMAGE_TYPES } from 'app/constants'; +import IAISwitch from 'common/components/IAISwitch'; +import IAISelect from 'common/components/IAISelect'; +import IAINumberInput from 'common/components/IAINumberInput'; const systemSelector = createSelector( (state: RootState) => state.system, @@ -39,12 +40,16 @@ const systemSelector = createSelector( shouldConfirmOnDelete, shouldDisplayGuides, model_list, + saveIntermediatesInterval, + enableImageDebugging, } = system; return { shouldDisplayInProgressType, shouldConfirmOnDelete, shouldDisplayGuides, models: _.map(model_list, (_model, key) => key), + saveIntermediatesInterval, + enableImageDebugging, }; }, { @@ -66,10 +71,6 @@ type SettingsModalProps = { const SettingsModal = ({ children }: SettingsModalProps) => { const dispatch = useAppDispatch(); - const saveIntermediatesInterval = useAppSelector( - (state: RootState) => state.system.saveIntermediatesInterval - ); - const steps = useAppSelector((state: RootState) => state.options.steps); const { @@ -88,6 +89,8 @@ const SettingsModal = ({ children }: SettingsModalProps) => { shouldDisplayInProgressType, shouldConfirmOnDelete, shouldDisplayGuides, + saveIntermediatesInterval, + enableImageDebugging, } = useAppSelector(systemSelector); /** @@ -115,9 +118,9 @@ const SettingsModal = ({ children }: SettingsModalProps) => { - + Settings - +
@@ -170,6 +173,18 @@ const SettingsModal = ({ children }: SettingsModalProps) => { />
+
+

Developer

+ ) => + dispatch(setEnableImageDebugging(e.target.checked)) + } + /> +
+
Reset Web UI + diff --git a/frontend/src/features/system/SiteHeader.scss b/frontend/src/features/system/SiteHeader.scss index f9b40912c0..3c4d267ae5 100644 --- a/frontend/src/features/system/SiteHeader.scss +++ b/frontend/src/features/system/SiteHeader.scss @@ -24,3 +24,14 @@ align-items: center; column-gap: 0.5rem; } + +.theme-changer-dropdown { + .invokeai__select-picker { + background-color: var(--background-color-light) !important; + font-size: 0.9rem; + &:focus { + border: none !important; + box-shadow: none !important; + } + } +} diff --git a/frontend/src/features/system/SiteHeader.tsx b/frontend/src/features/system/SiteHeader.tsx index 86e916ed3f..b93306fd49 100644 --- a/frontend/src/features/system/SiteHeader.tsx +++ b/frontend/src/features/system/SiteHeader.tsx @@ -1,10 +1,6 @@ -import { Link, useColorMode } from '@chakra-ui/react'; - -import { useHotkeys } from 'react-hotkeys-hook'; +import { Link } from '@chakra-ui/react'; import { - FaSun, - FaMoon, FaGithub, FaDiscord, FaBug, @@ -12,28 +8,19 @@ import { FaWrench, } from 'react-icons/fa'; -import InvokeAILogo from '../../assets/images/logo.png'; -import IAIIconButton from '../../common/components/IAIIconButton'; +import InvokeAILogo from 'assets/images/logo.png'; +import IAIIconButton from 'common/components/IAIIconButton'; import HotkeysModal from './HotkeysModal/HotkeysModal'; import SettingsModal from './SettingsModal/SettingsModal'; import StatusIndicator from './StatusIndicator'; +import ThemeChanger from './ThemeChanger'; /** * Header, includes color mode toggle, settings button, status message. */ const SiteHeader = () => { - const { colorMode, toggleColorMode } = useColorMode(); - - useHotkeys( - 'shift+d', - () => { - toggleColorMode(); - }, - [colorMode, toggleColorMode] - ); - return (
@@ -58,16 +45,7 @@ const SiteHeader = () => { /> - : } - /> + state.options.currentTheme + ); + + const themeChangeHandler = (e: ChangeEvent) => { + setColorMode(e.target.value); + dispatch(setCurrentTheme(e.target.value)); + }; + + return ( + + ); +} diff --git a/frontend/src/features/system/systemSlice.ts b/frontend/src/features/system/systemSlice.ts index 76ecf82e48..3b1feb9e61 100644 --- a/frontend/src/features/system/systemSlice.ts +++ b/frontend/src/features/system/systemSlice.ts @@ -1,7 +1,7 @@ import { createSlice } from '@reduxjs/toolkit'; import type { PayloadAction } from '@reduxjs/toolkit'; import { ExpandedIndex } from '@chakra-ui/react'; -import * as InvokeAI from '../../app/invokeai'; +import * as InvokeAI from 'app/invokeai'; export type LogLevel = 'info' | 'warning' | 'error'; @@ -44,6 +44,7 @@ export interface SystemState wasErrorSeen: boolean; isCancelable: boolean; saveIntermediatesInterval: number; + enableImageDebugging: boolean; } const initialSystemState: SystemState = { @@ -74,6 +75,7 @@ const initialSystemState: SystemState = { wasErrorSeen: true, isCancelable: true, saveIntermediatesInterval: 5, + enableImageDebugging: false, }; export const systemSlice = createSlice({ @@ -191,6 +193,9 @@ export const systemSlice = createSlice({ setSaveIntermediatesInterval: (state, action: PayloadAction) => { state.saveIntermediatesInterval = action.payload; }, + setEnableImageDebugging: (state, action: PayloadAction) => { + state.enableImageDebugging = action.payload; + }, }, }); @@ -214,6 +219,7 @@ export const { setIsCancelable, modelChangeRequested, setSaveIntermediatesInterval, + setEnableImageDebugging, } = systemSlice.actions; export default systemSlice.reducer; diff --git a/frontend/src/features/tabs/FloatingButton.scss b/frontend/src/features/tabs/FloatingButton.scss index 7e39d884f3..c985ead031 100644 --- a/frontend/src/features/tabs/FloatingButton.scss +++ b/frontend/src/features/tabs/FloatingButton.scss @@ -1,41 +1,42 @@ @use '../../styles/Mixins/' as *; .floating-show-hide-button { - position: absolute !important; + position: absolute; top: 50%; transform: translate(0, -50%); z-index: 20; padding: 0; + background-color: red !important; &.left { left: 0; - border-radius: 0 0.5rem 0.5rem 0 !important; + border-radius: 0 0.5rem 0.5rem 0; } &.right { right: 0; - border-radius: 0.5rem 0 0 0.5rem !important; + border-radius: 0.5rem 0 0 0.5rem; } @include Button( - $btn-width: 1rem, + $btn-width: 2rem, $btn-height: 12rem, $icon-size: 20px, - $btn-color: var(--btn-grey), - $btn-color-hover: var(--btn-grey-hover) + $btn-color: var(--btn-btn-base-color), + $btn-color-hover: var(--btn-btn-base-color-hover) ); } .show-hide-button-options { - position: absolute !important; + position: absolute; transform: translate(0, -50%); z-index: 20; - min-width: 2rem !important; + min-width: 2rem; top: 50%; left: calc(42px + 2rem); - border-radius: 0 0.5rem 0.5rem 0 !important; + border-radius: 0 0.5rem 0.5rem 0; display: flex; flex-direction: column; @@ -43,10 +44,9 @@ button { border-radius: 0 0.3rem 0.3rem 0; - background-color: var(--btn-grey); - - svg { - width: 18px; - } } } + +.show-hide-button-gallery { + background-color: var(--background-color) !important; +} diff --git a/frontend/src/features/tabs/FloatingGalleryButton.tsx b/frontend/src/features/tabs/FloatingGalleryButton.tsx index 0f17e2271a..3c714d60d7 100644 --- a/frontend/src/features/tabs/FloatingGalleryButton.tsx +++ b/frontend/src/features/tabs/FloatingGalleryButton.tsx @@ -1,13 +1,20 @@ import { MdPhotoLibrary } from 'react-icons/md'; -import { useAppDispatch } from '../../app/store'; -import IAIIconButton from '../../common/components/IAIIconButton'; -import { setShouldShowGallery } from '../gallery/gallerySlice'; +import { RootState, useAppDispatch, useAppSelector } from 'app/store'; +import IAIIconButton from 'common/components/IAIIconButton'; +import { setShouldShowGallery } from 'features/gallery/gallerySlice'; +import { setDoesCanvasNeedScaling } from 'features/canvas/canvasSlice'; const FloatingGalleryButton = () => { const dispatch = useAppDispatch(); + const shouldPinGallery = useAppSelector( + (state: RootState) => state.gallery.shouldPinGallery + ); const handleShowGallery = () => { dispatch(setShouldShowGallery(true)); + if (shouldPinGallery) { + dispatch(setDoesCanvasNeedScaling(true)); + } }; return ( @@ -15,8 +22,8 @@ const FloatingGalleryButton = () => { tooltip="Show Gallery (G)" tooltipProps={{ placement: 'top' }} aria-label="Show Gallery" - styleClass="floating-show-hide-button right" - onMouseOver={handleShowGallery} + styleClass="floating-show-hide-button right show-hide-button-gallery" + onClick={handleShowGallery} > diff --git a/frontend/src/features/tabs/FloatingOptionsPanelButtons.tsx b/frontend/src/features/tabs/FloatingOptionsPanelButtons.tsx index 82ae0c4bca..4834c3309b 100644 --- a/frontend/src/features/tabs/FloatingOptionsPanelButtons.tsx +++ b/frontend/src/features/tabs/FloatingOptionsPanelButtons.tsx @@ -1,15 +1,16 @@ import { createSelector } from '@reduxjs/toolkit'; import { IoMdOptions } from 'react-icons/io'; -import { RootState, useAppDispatch, useAppSelector } from '../../app/store'; -import IAIIconButton from '../../common/components/IAIIconButton'; +import { RootState, useAppDispatch, useAppSelector } from 'app/store'; +import IAIIconButton from 'common/components/IAIIconButton'; import { OptionsState, setShouldShowOptionsPanel, -} from '../options/optionsSlice'; -import CancelButton from '../options/ProcessButtons/CancelButton'; -import InvokeButton from '../options/ProcessButtons/InvokeButton'; +} from 'features/options/optionsSlice'; +import CancelButton from 'features/options/ProcessButtons/CancelButton'; +import InvokeButton from 'features/options/ProcessButtons/InvokeButton'; import _ from 'lodash'; -import LoopbackButton from '../options/ProcessButtons/Loopback'; +import LoopbackButton from 'features/options/ProcessButtons/Loopback'; +import { setDoesCanvasNeedScaling } from 'features/canvas/canvasSlice'; const canInvokeSelector = createSelector( (state: RootState) => state.options, @@ -17,6 +18,7 @@ const canInvokeSelector = createSelector( (options: OptionsState) => { const { shouldPinOptionsPanel, shouldShowOptionsPanel } = options; return { + shouldPinOptionsPanel, shouldShowProcessButtons: !shouldPinOptionsPanel || !shouldShowOptionsPanel, }; @@ -26,10 +28,14 @@ const canInvokeSelector = createSelector( const FloatingOptionsPanelButtons = () => { const dispatch = useAppDispatch(); - const { shouldShowProcessButtons } = useAppSelector(canInvokeSelector); + const { shouldShowProcessButtons, shouldPinOptionsPanel } = + useAppSelector(canInvokeSelector); const handleShowOptionsPanel = () => { dispatch(setShouldShowOptionsPanel(true)); + if (shouldPinOptionsPanel) { + setTimeout(() => dispatch(setDoesCanvasNeedScaling(true)), 400); + } }; return ( diff --git a/frontend/src/features/tabs/ImageToImage/ImageToImage.scss b/frontend/src/features/tabs/ImageToImage/ImageToImage.scss index ecc488f3d3..29850f2a3c 100644 --- a/frontend/src/features/tabs/ImageToImage/ImageToImage.scss +++ b/frontend/src/features/tabs/ImageToImage/ImageToImage.scss @@ -9,11 +9,12 @@ } .image-to-image-strength-main-option { - display: grid; - grid-template-columns: none !important; + display: flex; + row-gap: 0.5rem !important; - .number-input-entry { - padding: 0 1rem; + .invokeai__slider-component-label { + color: var(--text-color-secondary); + font-size: 0.9rem !important; } } diff --git a/frontend/src/features/tabs/ImageToImage/ImageToImageDisplay.tsx b/frontend/src/features/tabs/ImageToImage/ImageToImageDisplay.tsx index aa217069aa..9a986e0feb 100644 --- a/frontend/src/features/tabs/ImageToImage/ImageToImageDisplay.tsx +++ b/frontend/src/features/tabs/ImageToImage/ImageToImageDisplay.tsx @@ -1,6 +1,6 @@ -import { RootState, useAppSelector } from '../../../app/store'; -import ImageUploadButton from '../../../common/components/ImageUploaderButton'; -import CurrentImageDisplay from '../../gallery/CurrentImageDisplay'; +import { RootState, useAppSelector } from 'app/store'; +import ImageUploadButton from 'common/components/ImageUploaderButton'; +import CurrentImageDisplay from 'features/gallery/CurrentImageDisplay'; import InitImagePreview from './InitImagePreview'; const ImageToImageDisplay = () => { diff --git a/frontend/src/features/tabs/ImageToImage/ImageToImagePanel.tsx b/frontend/src/features/tabs/ImageToImage/ImageToImagePanel.tsx index d6e0b3b08e..65117d1972 100644 --- a/frontend/src/features/tabs/ImageToImage/ImageToImagePanel.tsx +++ b/frontend/src/features/tabs/ImageToImage/ImageToImagePanel.tsx @@ -1,23 +1,23 @@ -import { Feature } from '../../../app/features'; -import { RootState, useAppSelector } from '../../../app/store'; -import FaceRestoreHeader from '../../options/AdvancedOptions/FaceRestore/FaceRestoreHeader'; -import FaceRestoreOptions from '../../options/AdvancedOptions/FaceRestore/FaceRestoreOptions'; -import ImageFit from '../../options/AdvancedOptions/ImageToImage/ImageFit'; -import ImageToImageStrength from '../../options/AdvancedOptions/ImageToImage/ImageToImageStrength'; -import OutputHeader from '../../options/AdvancedOptions/Output/OutputHeader'; -import OutputOptions from '../../options/AdvancedOptions/Output/OutputOptions'; -import SeedHeader from '../../options/AdvancedOptions/Seed/SeedHeader'; -import SeedOptions from '../../options/AdvancedOptions/Seed/SeedOptions'; -import UpscaleHeader from '../../options/AdvancedOptions/Upscale/UpscaleHeader'; -import UpscaleOptions from '../../options/AdvancedOptions/Upscale/UpscaleOptions'; -import VariationsHeader from '../../options/AdvancedOptions/Variations/VariationsHeader'; -import VariationsOptions from '../../options/AdvancedOptions/Variations/VariationsOptions'; -import MainAdvancedOptionsCheckbox from '../../options/MainOptions/MainAdvancedOptionsCheckbox'; -import MainOptions from '../../options/MainOptions/MainOptions'; -import OptionsAccordion from '../../options/OptionsAccordion'; -import ProcessButtons from '../../options/ProcessButtons/ProcessButtons'; -import PromptInput from '../../options/PromptInput/PromptInput'; -import InvokeOptionsPanel from '../InvokeOptionsPanel'; +import { Feature } from 'app/features'; +import { RootState, useAppSelector } from 'app/store'; +import FaceRestoreHeader from 'features/options/AdvancedOptions/FaceRestore/FaceRestoreHeader'; +import FaceRestoreOptions from 'features/options/AdvancedOptions/FaceRestore/FaceRestoreOptions'; +import ImageFit from 'features/options/AdvancedOptions/ImageToImage/ImageFit'; +import ImageToImageStrength from 'features/options/AdvancedOptions/ImageToImage/ImageToImageStrength'; +import OutputHeader from 'features/options/AdvancedOptions/Output/OutputHeader'; +import OutputOptions from 'features/options/AdvancedOptions/Output/OutputOptions'; +import SeedHeader from 'features/options/AdvancedOptions/Seed/SeedHeader'; +import SeedOptions from 'features/options/AdvancedOptions/Seed/SeedOptions'; +import UpscaleHeader from 'features/options/AdvancedOptions/Upscale/UpscaleHeader'; +import UpscaleOptions from 'features/options/AdvancedOptions/Upscale/UpscaleOptions'; +import VariationsHeader from 'features/options/AdvancedOptions/Variations/VariationsHeader'; +import VariationsOptions from 'features/options/AdvancedOptions/Variations/VariationsOptions'; +import MainAdvancedOptionsCheckbox from 'features/options/MainOptions/MainAdvancedOptionsCheckbox'; +import MainOptions from 'features/options/MainOptions/MainOptions'; +import OptionsAccordion from 'features/options/OptionsAccordion'; +import ProcessButtons from 'features/options/ProcessButtons/ProcessButtons'; +import PromptInput from 'features/options/PromptInput/PromptInput'; +import InvokeOptionsPanel from 'features/tabs/InvokeOptionsPanel'; export default function ImageToImagePanel() { const showAdvancedOptions = useAppSelector( diff --git a/frontend/src/features/tabs/ImageToImage/InitImagePreview.tsx b/frontend/src/features/tabs/ImageToImage/InitImagePreview.tsx index 5b2b8b4eb1..7a79f5f7ee 100644 --- a/frontend/src/features/tabs/ImageToImage/InitImagePreview.tsx +++ b/frontend/src/features/tabs/ImageToImage/InitImagePreview.tsx @@ -1,8 +1,8 @@ import { Image, useToast } from '@chakra-ui/react'; import { SyntheticEvent } from 'react'; -import { RootState, useAppDispatch, useAppSelector } from '../../../app/store'; -import ImageUploaderIconButton from '../../../common/components/ImageUploaderIconButton'; -import { clearInitialImage } from '../../options/optionsSlice'; +import { RootState, useAppDispatch, useAppSelector } from 'app/store'; +import ImageUploaderIconButton from 'common/components/ImageUploaderIconButton'; +import { clearInitialImage } from 'features/options/optionsSlice'; export default function InitImagePreview() { const initialImage = useAppSelector( diff --git a/frontend/src/features/tabs/ImageToImage/InitialImageOverlay.tsx b/frontend/src/features/tabs/ImageToImage/InitialImageOverlay.tsx index 0c342821cf..90f4f64709 100644 --- a/frontend/src/features/tabs/ImageToImage/InitialImageOverlay.tsx +++ b/frontend/src/features/tabs/ImageToImage/InitialImageOverlay.tsx @@ -1,6 +1,6 @@ import { Image } from '@chakra-ui/react'; import React from 'react'; -import { RootState, useAppSelector } from '../../../app/store'; +import { RootState, useAppSelector } from 'app/store'; export default function InitialImageOverlay() { const initialImage = useAppSelector( diff --git a/frontend/src/features/tabs/ImageToImage/index.tsx b/frontend/src/features/tabs/ImageToImage/index.tsx index 5363c95f06..1a6e496089 100644 --- a/frontend/src/features/tabs/ImageToImage/index.tsx +++ b/frontend/src/features/tabs/ImageToImage/index.tsx @@ -1,7 +1,7 @@ import React from 'react'; import ImageToImagePanel from './ImageToImagePanel'; import ImageToImageDisplay from './ImageToImageDisplay'; -import InvokeWorkarea from '../InvokeWorkarea'; +import InvokeWorkarea from 'features/tabs/InvokeWorkarea'; export default function ImageToImageWorkarea() { return ( diff --git a/frontend/src/features/tabs/Inpainting/InpaintingCanvas.tsx b/frontend/src/features/tabs/Inpainting/InpaintingCanvas.tsx deleted file mode 100644 index ee3c4c7d26..0000000000 --- a/frontend/src/features/tabs/Inpainting/InpaintingCanvas.tsx +++ /dev/null @@ -1,309 +0,0 @@ -// lib -import { - MutableRefObject, - useCallback, - useEffect, - useRef, - useState, -} from 'react'; -import Konva from 'konva'; -import { Layer, Stage } from 'react-konva'; -import { Image as KonvaImage } from 'react-konva'; -import { Stage as StageType } from 'konva/lib/Stage'; - -// app -import { useAppDispatch, useAppSelector } from '../../../app/store'; -import { - addLine, - addPointToCurrentLine, - clearImageToInpaint, - setCursorPosition, - setIsDrawing, -} from './inpaintingSlice'; -import { inpaintingCanvasSelector } from './inpaintingSliceSelectors'; - -// component -import InpaintingCanvasLines from './components/InpaintingCanvasLines'; -import InpaintingCanvasBrushPreview from './components/InpaintingCanvasBrushPreview'; -import InpaintingCanvasBrushPreviewOutline from './components/InpaintingCanvasBrushPreviewOutline'; -import Cacher from './components/Cacher'; -import { Vector2d } from 'konva/lib/types'; -import getScaledCursorPosition from './util/getScaledCursorPosition'; -import InpaintingBoundingBoxPreview, { - InpaintingBoundingBoxPreviewOverlay, -} from './components/InpaintingBoundingBoxPreview'; -import { KonvaEventObject } from 'konva/lib/Node'; -import KeyboardEventManager from './KeyboardEventManager'; -import { useToast } from '@chakra-ui/react'; - -// Use a closure allow other components to use these things... not ideal... -export let stageRef: MutableRefObject; -export let maskLayerRef: MutableRefObject; -export let inpaintingImageElementRef: MutableRefObject; - -const InpaintingCanvas = () => { - const dispatch = useAppDispatch(); - - const { - tool, - brushSize, - shouldInvertMask, - shouldShowMask, - shouldShowCheckboardTransparency, - maskColor, - imageToInpaint, - stageScale, - shouldShowBoundingBox, - shouldShowBoundingBoxFill, - isDrawing, - isModifyingBoundingBox, - stageCursor, - } = useAppSelector(inpaintingCanvasSelector); - - const toast = useToast(); - - // set the closure'd refs - stageRef = useRef(null); - maskLayerRef = useRef(null); - inpaintingImageElementRef = useRef(null); - - const lastCursorPosition = useRef({ x: 0, y: 0 }); - - // Use refs for values that do not affect rendering, other values in redux - const didMouseMoveRef = useRef(false); - - // Load the image into this - const [canvasBgImage, setCanvasBgImage] = useState( - null - ); - - // Load the image and set the options panel width & height - useEffect(() => { - if (imageToInpaint) { - const image = new Image(); - image.onload = () => { - inpaintingImageElementRef.current = image; - setCanvasBgImage(image); - }; - image.onerror = () => { - toast({ - title: 'Unable to Load Image', - description: `Image ${imageToInpaint.url} failed to load`, - status: 'error', - isClosable: true, - }); - dispatch(clearImageToInpaint()); - }; - image.src = imageToInpaint.url; - } else { - setCanvasBgImage(null); - } - }, [imageToInpaint, dispatch, stageScale, toast]); - - /** - * - * Canvas onMouseDown - * - */ - const handleMouseDown = useCallback(() => { - if (!stageRef.current) return; - - const scaledCursorPosition = getScaledCursorPosition(stageRef.current); - - if ( - !scaledCursorPosition || - !maskLayerRef.current || - isModifyingBoundingBox - ) - return; - - dispatch(setIsDrawing(true)); - - // Add a new line starting from the current cursor position. - dispatch( - addLine({ - tool, - strokeWidth: brushSize / 2, - points: [scaledCursorPosition.x, scaledCursorPosition.y], - }) - ); - }, [dispatch, brushSize, tool, isModifyingBoundingBox]); - - /** - * - * Canvas onMouseMove - * - */ - const handleMouseMove = useCallback(() => { - if (!stageRef.current) return; - - const scaledCursorPosition = getScaledCursorPosition(stageRef.current); - - if (!scaledCursorPosition) return; - - dispatch(setCursorPosition(scaledCursorPosition)); - - if (!maskLayerRef.current) { - return; - } - - lastCursorPosition.current = scaledCursorPosition; - - if (!isDrawing || isModifyingBoundingBox) return; - - didMouseMoveRef.current = true; - // Extend the current line - dispatch( - addPointToCurrentLine([scaledCursorPosition.x, scaledCursorPosition.y]) - ); - }, [dispatch, isDrawing, isModifyingBoundingBox]); - - /** - * - * Canvas onMouseUp - * - */ - const handleMouseUp = useCallback(() => { - if (!didMouseMoveRef.current && isDrawing && stageRef.current) { - const scaledCursorPosition = getScaledCursorPosition(stageRef.current); - - if ( - !scaledCursorPosition || - !maskLayerRef.current || - isModifyingBoundingBox - ) - return; - - /** - * Extend the current line. - * In this case, the mouse didn't move, so we append the same point to - * the line's existing points. This allows the line to render as a circle - * centered on that point. - */ - dispatch( - addPointToCurrentLine([scaledCursorPosition.x, scaledCursorPosition.y]) - ); - } else { - didMouseMoveRef.current = false; - } - dispatch(setIsDrawing(false)); - }, [dispatch, isDrawing, isModifyingBoundingBox]); - - /** - * - * Canvas onMouseOut - * - */ - const handleMouseOutCanvas = useCallback(() => { - dispatch(setCursorPosition(null)); - dispatch(setIsDrawing(false)); - }, [dispatch]); - - /** - * - * Canvas onMouseEnter - * - */ - const handleMouseEnter = useCallback( - (e: KonvaEventObject) => { - if (e.evt.buttons === 1) { - if (!stageRef.current) return; - - const scaledCursorPosition = getScaledCursorPosition(stageRef.current); - - if ( - !scaledCursorPosition || - !maskLayerRef.current || - isModifyingBoundingBox - ) - return; - - dispatch(setIsDrawing(true)); - - // Add a new line starting from the current cursor position. - dispatch( - addLine({ - tool, - strokeWidth: brushSize / 2, - points: [scaledCursorPosition.x, scaledCursorPosition.y], - }) - ); - } - }, - [dispatch, brushSize, tool, isModifyingBoundingBox] - ); - - return ( -
-
- {canvasBgImage && ( - - {!shouldInvertMask && !shouldShowCheckboardTransparency && ( - - - - )} - {shouldShowMask && ( - <> - - - - - - {shouldInvertMask && ( - - )} - {!shouldInvertMask && shouldShowCheckboardTransparency && ( - - )} - - - {shouldShowBoundingBoxFill && shouldShowBoundingBox && ( - - )} - {shouldShowBoundingBox && } - - - - - )} - - )} - - -
-
- ); -}; - -export default InpaintingCanvas; diff --git a/frontend/src/features/tabs/Inpainting/InpaintingCanvasPlaceholder.tsx b/frontend/src/features/tabs/Inpainting/InpaintingCanvasPlaceholder.tsx deleted file mode 100644 index a0c893e57f..0000000000 --- a/frontend/src/features/tabs/Inpainting/InpaintingCanvasPlaceholder.tsx +++ /dev/null @@ -1,36 +0,0 @@ -import { Spinner } from '@chakra-ui/react'; -import { useLayoutEffect, useRef } from 'react'; -import { RootState, useAppDispatch, useAppSelector } from '../../../app/store'; -import { setStageScale } from './inpaintingSlice'; - -const InpaintingCanvasPlaceholder = () => { - const dispatch = useAppDispatch(); - const { needsCache, imageToInpaint } = useAppSelector( - (state: RootState) => state.inpainting - ); - const ref = useRef(null); - - useLayoutEffect(() => { - window.setTimeout(() => { - if (!ref.current || !imageToInpaint) return; - - const width = ref.current.clientWidth; - const height = ref.current.clientHeight; - - const scale = Math.min( - 1, - Math.min(width / imageToInpaint.width, height / imageToInpaint.height) - ); - - dispatch(setStageScale(scale)); - }, 0); - }, [dispatch, imageToInpaint, needsCache]); - - return ( -
- -
- ); -}; - -export default InpaintingCanvasPlaceholder; diff --git a/frontend/src/features/tabs/Inpainting/InpaintingCanvasStatusIcons.scss b/frontend/src/features/tabs/Inpainting/InpaintingCanvasStatusIcons.scss deleted file mode 100644 index dc57eea117..0000000000 --- a/frontend/src/features/tabs/Inpainting/InpaintingCanvasStatusIcons.scss +++ /dev/null @@ -1,29 +0,0 @@ -.inpainting-alerts { - position: absolute; - top: 0; - left: 0; - z-index: 2; - margin: 0.5rem; - - button { - background-color: var(--inpainting-alerts-bg); - - svg { - fill: var(--inpainting-alerts-icon-color); - } - - &[data-selected='true'] { - background-color: var(--inpainting-alerts-bg-active); - svg { - fill: var(--inpainting-alerts-icon-active); - } - } - - &[data-alert='true'] { - background-color: var(--inpainting-alerts-bg-alert); - svg { - fill: var(--inpainting-alerts-icon-alert); - } - } - } -} diff --git a/frontend/src/features/tabs/Inpainting/InpaintingCanvasStatusIcons.tsx b/frontend/src/features/tabs/Inpainting/InpaintingCanvasStatusIcons.tsx deleted file mode 100644 index 68b5360252..0000000000 --- a/frontend/src/features/tabs/Inpainting/InpaintingCanvasStatusIcons.tsx +++ /dev/null @@ -1,126 +0,0 @@ -import _ from 'lodash'; - -const inpaintingCanvasStatusIconsSelector = createSelector( - (state: RootState) => state.inpainting, - (inpainting: InpaintingState) => { - const { - shouldShowMask, - shouldInvertMask, - shouldLockBoundingBox, - shouldShowBoundingBox, - boundingBoxDimensions, - } = inpainting; - - return { - shouldShowMask, - shouldInvertMask, - shouldLockBoundingBox, - shouldShowBoundingBox, - isBoundingBoxTooSmall: - boundingBoxDimensions.width < 512 || boundingBoxDimensions.height < 512, - }; - }, - { - memoizeOptions: { - resultEqualityCheck: _.isEqual, - }, - } -); - -import { ButtonGroup, IconButton, Tooltip } from '@chakra-ui/react'; -import { createSelector } from '@reduxjs/toolkit'; -import { BiHide, BiShow } from 'react-icons/bi'; -import { GiResize } from 'react-icons/gi'; -import { BsBoundingBox } from 'react-icons/bs'; -import { FaLock, FaUnlock } from 'react-icons/fa'; -import { MdInvertColors, MdInvertColorsOff } from 'react-icons/md'; -import { RootState, useAppSelector } from '../../../app/store'; -import { InpaintingState } from './inpaintingSlice'; -import { MouseEvent, useRef, useState } from 'react'; - -const InpaintingCanvasStatusIcons = () => { - const { - shouldShowMask, - shouldInvertMask, - shouldLockBoundingBox, - shouldShowBoundingBox, - isBoundingBoxTooSmall, - } = useAppSelector(inpaintingCanvasStatusIconsSelector); - - const [shouldAcceptPointerEvents, setShouldAcceptPointerEvents] = - useState(false); - const timeoutRef = useRef(0); - - const handleMouseOver = () => { - if (!shouldAcceptPointerEvents) { - timeoutRef.current = window.setTimeout( - () => setShouldAcceptPointerEvents(true), - 1000 - ); - } - }; - - const handleMouseOut = () => { - if (!shouldAcceptPointerEvents) { - setShouldAcceptPointerEvents(false); - window.clearTimeout(timeoutRef.current); - } - }; - - return ( -
- - - : } - /> - - : } - /> - : } - /> - } - /> - } - /> - -
- ); -}; - -export default InpaintingCanvasStatusIcons; diff --git a/frontend/src/features/tabs/Inpainting/InpaintingControls.tsx b/frontend/src/features/tabs/Inpainting/InpaintingControls.tsx deleted file mode 100644 index 67e09e445c..0000000000 --- a/frontend/src/features/tabs/Inpainting/InpaintingControls.tsx +++ /dev/null @@ -1,40 +0,0 @@ -import InpaintingBrushControl from './InpaintingControls/InpaintingBrushControl'; -import InpaintingEraserControl from './InpaintingControls/InpaintingEraserControl'; -import InpaintingUndoControl from './InpaintingControls/InpaintingUndoControl'; -import InpaintingRedoControl from './InpaintingControls/InpaintingRedoControl'; -import { ButtonGroup } from '@chakra-ui/react'; -import InpaintingMaskClear from './InpaintingControls/InpaintingMaskControls/InpaintingMaskClear'; -import InpaintingMaskVisibilityControl from './InpaintingControls/InpaintingMaskControls/InpaintingMaskVisibilityControl'; -import InpaintingMaskInvertControl from './InpaintingControls/InpaintingMaskControls/InpaintingMaskInvertControl'; -import InpaintingLockBoundingBoxControl from './InpaintingControls/InpaintingLockBoundingBoxControl'; -import InpaintingShowHideBoundingBoxControl from './InpaintingControls/InpaintingShowHideBoundingBoxControl'; -import ImageUploaderIconButton from '../../../common/components/ImageUploaderIconButton'; - -const InpaintingControls = () => { - return ( -
- - - - - - - - - - - - - - - - - - - - -
- ); -}; - -export default InpaintingControls; diff --git a/frontend/src/features/tabs/Inpainting/InpaintingControls/InpaintingEraserControl.tsx b/frontend/src/features/tabs/Inpainting/InpaintingControls/InpaintingEraserControl.tsx deleted file mode 100644 index ce98017fe3..0000000000 --- a/frontend/src/features/tabs/Inpainting/InpaintingControls/InpaintingEraserControl.tsx +++ /dev/null @@ -1,67 +0,0 @@ -import { createSelector } from '@reduxjs/toolkit'; -import React from 'react'; -import { useHotkeys } from 'react-hotkeys-hook'; -import { FaEraser } from 'react-icons/fa'; -import { - RootState, - useAppDispatch, - useAppSelector, -} from '../../../../app/store'; -import IAIIconButton from '../../../../common/components/IAIIconButton'; -import { InpaintingState, setTool } from '../inpaintingSlice'; - -import _ from 'lodash'; -import { activeTabNameSelector } from '../../../options/optionsSelectors'; - -const inpaintingEraserSelector = createSelector( - [(state: RootState) => state.inpainting, activeTabNameSelector], - (inpainting: InpaintingState, activeTabName) => { - const { tool, shouldShowMask } = inpainting; - - return { - tool, - shouldShowMask, - activeTabName, - }; - }, - { - memoizeOptions: { - resultEqualityCheck: _.isEqual, - }, - } -); - -export default function InpaintingEraserControl() { - const { tool, shouldShowMask, activeTabName } = useAppSelector( - inpaintingEraserSelector - ); - const dispatch = useAppDispatch(); - - const handleSelectEraserTool = () => dispatch(setTool('eraser')); - - // Hotkeys - // Set tool to eraser - useHotkeys( - 'e', - (e: KeyboardEvent) => { - e.preventDefault(); - if (activeTabName !== 'inpainting' || !shouldShowMask) return; - handleSelectEraserTool(); - }, - { - enabled: activeTabName === 'inpainting' && shouldShowMask, - }, - [activeTabName, shouldShowMask] - ); - - return ( - } - onClick={handleSelectEraserTool} - data-selected={tool === 'eraser'} - isDisabled={!shouldShowMask} - /> - ); -} diff --git a/frontend/src/features/tabs/Inpainting/InpaintingControls/InpaintingLockBoundingBoxControl.tsx b/frontend/src/features/tabs/Inpainting/InpaintingControls/InpaintingLockBoundingBoxControl.tsx deleted file mode 100644 index 15710be39a..0000000000 --- a/frontend/src/features/tabs/Inpainting/InpaintingControls/InpaintingLockBoundingBoxControl.tsx +++ /dev/null @@ -1,29 +0,0 @@ -import { FaLock, FaUnlock } from 'react-icons/fa'; -import { - RootState, - useAppDispatch, - useAppSelector, -} from '../../../../app/store'; -import IAIIconButton from '../../../../common/components/IAIIconButton'; -import { setShouldLockBoundingBox } from '../inpaintingSlice'; - -const InpaintingLockBoundingBoxControl = () => { - const dispatch = useAppDispatch(); - const shouldLockBoundingBox = useAppSelector( - (state: RootState) => state.inpainting.shouldLockBoundingBox - ); - - return ( - : } - data-selected={shouldLockBoundingBox} - onClick={() => { - dispatch(setShouldLockBoundingBox(!shouldLockBoundingBox)); - }} - /> - ); -}; - -export default InpaintingLockBoundingBoxControl; diff --git a/frontend/src/features/tabs/Inpainting/InpaintingControls/InpaintingMaskControl.tsx b/frontend/src/features/tabs/Inpainting/InpaintingControls/InpaintingMaskControl.tsx deleted file mode 100644 index 1bd750dcaf..0000000000 --- a/frontend/src/features/tabs/Inpainting/InpaintingControls/InpaintingMaskControl.tsx +++ /dev/null @@ -1,38 +0,0 @@ -import React, { useState } from 'react'; -import { FaMask } from 'react-icons/fa'; - -import IAIIconButton from '../../../../common/components/IAIIconButton'; -import IAIPopover from '../../../../common/components/IAIPopover'; - -import InpaintingMaskVisibilityControl from './InpaintingMaskControls/InpaintingMaskVisibilityControl'; -import InpaintingMaskInvertControl from './InpaintingMaskControls/InpaintingMaskInvertControl'; -import InpaintingMaskColorPicker from './InpaintingMaskControls/InpaintingMaskColorPicker'; - -export default function InpaintingMaskControl() { - const [maskOptionsOpen, setMaskOptionsOpen] = useState(false); - - return ( - <> - setMaskOptionsOpen(true)} - onClose={() => setMaskOptionsOpen(false)} - triggerComponent={ - } - cursor={'pointer'} - data-selected={maskOptionsOpen} - /> - } - > -
- - - -
-
- - ); -} diff --git a/frontend/src/features/tabs/Inpainting/InpaintingControls/InpaintingMaskControls/InpaintingMaskClear.tsx b/frontend/src/features/tabs/Inpainting/InpaintingControls/InpaintingMaskControls/InpaintingMaskClear.tsx deleted file mode 100644 index ea03f3cb6a..0000000000 --- a/frontend/src/features/tabs/Inpainting/InpaintingControls/InpaintingMaskControls/InpaintingMaskClear.tsx +++ /dev/null @@ -1,70 +0,0 @@ -import { createSelector } from '@reduxjs/toolkit'; -import React from 'react'; -import { FaPlus } from 'react-icons/fa'; -import { - RootState, - useAppDispatch, - useAppSelector, -} from '../../../../../app/store'; -import IAIIconButton from '../../../../../common/components/IAIIconButton'; -import { activeTabNameSelector } from '../../../../options/optionsSelectors'; -import { clearMask, InpaintingState } from '../../inpaintingSlice'; - -import _ from 'lodash'; -import { useHotkeys } from 'react-hotkeys-hook'; -import { useToast } from '@chakra-ui/react'; - -const inpaintingMaskClearSelector = createSelector( - [(state: RootState) => state.inpainting, activeTabNameSelector], - (inpainting: InpaintingState, activeTabName) => { - const { shouldShowMask, lines } = inpainting; - - return { shouldShowMask, activeTabName, isMaskEmpty: lines.length === 0 }; - }, - { - memoizeOptions: { - resultEqualityCheck: _.isEqual, - }, - } -); - -export default function InpaintingMaskClear() { - const { shouldShowMask, activeTabName, isMaskEmpty } = useAppSelector( - inpaintingMaskClearSelector - ); - - const dispatch = useAppDispatch(); - const toast = useToast(); - - const handleClearMask = () => { - dispatch(clearMask()); - }; - - // Clear mask - useHotkeys( - 'shift+c', - (e: KeyboardEvent) => { - e.preventDefault(); - handleClearMask(); - toast({ - title: 'Mask Cleared', - status: 'success', - duration: 2500, - isClosable: true, - }); - }, - { - enabled: activeTabName === 'inpainting' && shouldShowMask && !isMaskEmpty, - }, - [activeTabName, isMaskEmpty, shouldShowMask] - ); - return ( - } - onClick={handleClearMask} - isDisabled={isMaskEmpty || !shouldShowMask} - /> - ); -} diff --git a/frontend/src/features/tabs/Inpainting/InpaintingControls/InpaintingMaskControls/InpaintingMaskVisibilityControl.tsx b/frontend/src/features/tabs/Inpainting/InpaintingControls/InpaintingMaskControls/InpaintingMaskVisibilityControl.tsx deleted file mode 100644 index 82e66ea629..0000000000 --- a/frontend/src/features/tabs/Inpainting/InpaintingControls/InpaintingMaskControls/InpaintingMaskVisibilityControl.tsx +++ /dev/null @@ -1,61 +0,0 @@ -import React from 'react'; -import { useHotkeys } from 'react-hotkeys-hook'; -import { BiHide, BiShow } from 'react-icons/bi'; -import { createSelector } from 'reselect'; -import { - RootState, - useAppDispatch, - useAppSelector, -} from '../../../../../app/store'; -import IAIIconButton from '../../../../../common/components/IAIIconButton'; -import { activeTabNameSelector } from '../../../../options/optionsSelectors'; -import { InpaintingState, setShouldShowMask } from '../../inpaintingSlice'; - -import _ from 'lodash'; - -const inpaintingMaskVisibilitySelector = createSelector( - [(state: RootState) => state.inpainting, activeTabNameSelector], - (inpainting: InpaintingState, activeTabName) => { - const { shouldShowMask } = inpainting; - - return { shouldShowMask, activeTabName }; - }, - { - memoizeOptions: { - resultEqualityCheck: _.isEqual, - }, - } -); - -export default function InpaintingMaskVisibilityControl() { - const dispatch = useAppDispatch(); - - const { shouldShowMask, activeTabName } = useAppSelector( - inpaintingMaskVisibilitySelector - ); - - const handleToggleShouldShowMask = () => - dispatch(setShouldShowMask(!shouldShowMask)); - // Hotkeys - // Show/hide mask - useHotkeys( - 'h', - (e: KeyboardEvent) => { - e.preventDefault(); - handleToggleShouldShowMask(); - }, - { - enabled: activeTabName === 'inpainting', - }, - [activeTabName, shouldShowMask] - ); - return ( - : } - onClick={handleToggleShouldShowMask} - /> - ); -} diff --git a/frontend/src/features/tabs/Inpainting/InpaintingControls/InpaintingRedoControl.tsx b/frontend/src/features/tabs/Inpainting/InpaintingControls/InpaintingRedoControl.tsx deleted file mode 100644 index c97ceb89bf..0000000000 --- a/frontend/src/features/tabs/Inpainting/InpaintingControls/InpaintingRedoControl.tsx +++ /dev/null @@ -1,66 +0,0 @@ -import { createSelector } from '@reduxjs/toolkit'; -import React from 'react'; -import { useHotkeys } from 'react-hotkeys-hook'; -import { FaRedo } from 'react-icons/fa'; -import { - RootState, - useAppDispatch, - useAppSelector, -} from '../../../../app/store'; -import IAIIconButton from '../../../../common/components/IAIIconButton'; -import { activeTabNameSelector } from '../../../options/optionsSelectors'; -import { InpaintingState, redo } from '../inpaintingSlice'; - -import _ from 'lodash'; - -const inpaintingRedoSelector = createSelector( - [(state: RootState) => state.inpainting, activeTabNameSelector], - (inpainting: InpaintingState, activeTabName) => { - const { futureLines, shouldShowMask } = inpainting; - - return { - canRedo: futureLines.length > 0, - shouldShowMask, - activeTabName, - }; - }, - { - memoizeOptions: { - resultEqualityCheck: _.isEqual, - }, - } -); - -export default function InpaintingRedoControl() { - const dispatch = useAppDispatch(); - const { canRedo, shouldShowMask, activeTabName } = useAppSelector( - inpaintingRedoSelector - ); - - const handleRedo = () => dispatch(redo()); - - // Hotkeys - - // Redo - useHotkeys( - 'cmd+shift+z, control+shift+z, control+y, cmd+y', - (e: KeyboardEvent) => { - e.preventDefault(); - handleRedo(); - }, - { - enabled: activeTabName === 'inpainting' && shouldShowMask && canRedo, - }, - [activeTabName, shouldShowMask, canRedo] - ); - - return ( - } - onClick={handleRedo} - isDisabled={!canRedo || !shouldShowMask} - /> - ); -} diff --git a/frontend/src/features/tabs/Inpainting/InpaintingControls/InpaintingShowHideBoundingBoxControl.tsx b/frontend/src/features/tabs/Inpainting/InpaintingControls/InpaintingShowHideBoundingBoxControl.tsx deleted file mode 100644 index a91d83d864..0000000000 --- a/frontend/src/features/tabs/Inpainting/InpaintingControls/InpaintingShowHideBoundingBoxControl.tsx +++ /dev/null @@ -1,29 +0,0 @@ -import { FaVectorSquare } from 'react-icons/fa'; -import { - RootState, - useAppDispatch, - useAppSelector, -} from '../../../../app/store'; -import IAIIconButton from '../../../../common/components/IAIIconButton'; -import { setShouldShowBoundingBox } from '../inpaintingSlice'; - -const InpaintingShowHideBoundingBoxControl = () => { - const dispatch = useAppDispatch(); - const shouldShowBoundingBox = useAppSelector( - (state: RootState) => state.inpainting.shouldShowBoundingBox - ); - - return ( - } - data-alert={!shouldShowBoundingBox} - onClick={() => { - dispatch(setShouldShowBoundingBox(!shouldShowBoundingBox)); - }} - /> - ); -}; - -export default InpaintingShowHideBoundingBoxControl; diff --git a/frontend/src/features/tabs/Inpainting/InpaintingControls/InpaintingUndoControl.tsx b/frontend/src/features/tabs/Inpainting/InpaintingControls/InpaintingUndoControl.tsx deleted file mode 100644 index 4721487da6..0000000000 --- a/frontend/src/features/tabs/Inpainting/InpaintingControls/InpaintingUndoControl.tsx +++ /dev/null @@ -1,66 +0,0 @@ -import { createSelector } from '@reduxjs/toolkit'; -import React from 'react'; -import { useHotkeys } from 'react-hotkeys-hook'; -import { FaUndo } from 'react-icons/fa'; -import { - RootState, - useAppDispatch, - useAppSelector, -} from '../../../../app/store'; -import IAIIconButton from '../../../../common/components/IAIIconButton'; -import { InpaintingState, undo } from '../inpaintingSlice'; - -import _ from 'lodash'; -import { activeTabNameSelector } from '../../../options/optionsSelectors'; - -const inpaintingUndoSelector = createSelector( - [(state: RootState) => state.inpainting, activeTabNameSelector], - (inpainting: InpaintingState, activeTabName) => { - const { pastLines, shouldShowMask } = inpainting; - - return { - canUndo: pastLines.length > 0, - shouldShowMask, - activeTabName, - }; - }, - { - memoizeOptions: { - resultEqualityCheck: _.isEqual, - }, - } -); - -export default function InpaintingUndoControl() { - const dispatch = useAppDispatch(); - - const { canUndo, shouldShowMask, activeTabName } = useAppSelector( - inpaintingUndoSelector - ); - - const handleUndo = () => dispatch(undo()); - - // Hotkeys - // Undo - useHotkeys( - 'cmd+z, control+z', - (e: KeyboardEvent) => { - e.preventDefault(); - handleUndo(); - }, - { - enabled: activeTabName === 'inpainting' && shouldShowMask && canUndo, - }, - [activeTabName, shouldShowMask, canUndo] - ); - - return ( - } - onClick={handleUndo} - isDisabled={!canUndo || !shouldShowMask} - /> - ); -} diff --git a/frontend/src/features/tabs/Inpainting/InpaintingDisplay.tsx b/frontend/src/features/tabs/Inpainting/InpaintingDisplay.tsx index 3f58002721..77d39dc2c3 100644 --- a/frontend/src/features/tabs/Inpainting/InpaintingDisplay.tsx +++ b/frontend/src/features/tabs/Inpainting/InpaintingDisplay.tsx @@ -1,22 +1,29 @@ import { createSelector } from '@reduxjs/toolkit'; +// import IAICanvas from 'features/canvas/IAICanvas'; +import IAICanvasControls from 'features/canvas/IAICanvasControls'; +import IAICanvasResizer from 'features/canvas/IAICanvasResizer'; import _ from 'lodash'; import { useLayoutEffect } from 'react'; -import { RootState, useAppDispatch, useAppSelector } from '../../../app/store'; -import ImageUploadButton from '../../../common/components/ImageUploaderButton'; -import CurrentImageDisplay from '../../gallery/CurrentImageDisplay'; -import { OptionsState } from '../../options/optionsSlice'; -import InpaintingCanvas from './InpaintingCanvas'; -import InpaintingCanvasPlaceholder from './InpaintingCanvasPlaceholder'; -import InpaintingControls from './InpaintingControls'; -import { InpaintingState, setNeedsCache } from './inpaintingSlice'; +import { RootState, useAppDispatch, useAppSelector } from 'app/store'; +import ImageUploadButton from 'common/components/ImageUploaderButton'; +import CurrentImageDisplay from 'features/gallery/CurrentImageDisplay'; +import { OptionsState } from 'features/options/optionsSlice'; +import { + CanvasState, + setDoesCanvasNeedScaling, +} from 'features/canvas/canvasSlice'; +import IAICanvas from 'features/canvas/IAICanvas'; const inpaintingDisplaySelector = createSelector( - [(state: RootState) => state.inpainting, (state: RootState) => state.options], - (inpainting: InpaintingState, options: OptionsState) => { - const { needsCache, imageToInpaint } = inpainting; + [(state: RootState) => state.canvas, (state: RootState) => state.options], + (canvas: CanvasState, options: OptionsState) => { + const { + doesCanvasNeedScaling, + inpainting: { imageToInpaint }, + } = canvas; const { showDualDisplay } = options; return { - needsCache, + doesCanvasNeedScaling, showDualDisplay, imageToInpaint, }; @@ -30,21 +37,23 @@ const inpaintingDisplaySelector = createSelector( const InpaintingDisplay = () => { const dispatch = useAppDispatch(); - const { showDualDisplay, needsCache, imageToInpaint } = useAppSelector( - inpaintingDisplaySelector - ); + const { showDualDisplay, doesCanvasNeedScaling, imageToInpaint } = + useAppSelector(inpaintingDisplaySelector); useLayoutEffect(() => { - const resizeCallback = _.debounce(() => dispatch(setNeedsCache(true)), 250); + const resizeCallback = _.debounce( + () => dispatch(setDoesCanvasNeedScaling(true)), + 250 + ); window.addEventListener('resize', resizeCallback); return () => window.removeEventListener('resize', resizeCallback); }, [dispatch]); const inpaintingComponent = imageToInpaint ? (
- +
- {needsCache ? : } + {doesCanvasNeedScaling ? : }
) : ( @@ -57,7 +66,7 @@ const InpaintingDisplay = () => { showDualDisplay ? 'workarea-split-view' : 'workarea-single-view' } > -
{inpaintingComponent}
+
{inpaintingComponent}
{showDualDisplay && (
diff --git a/frontend/src/features/tabs/Inpainting/InpaintingPanel.tsx b/frontend/src/features/tabs/Inpainting/InpaintingPanel.tsx index 7bdc226dd5..fc2500428e 100644 --- a/frontend/src/features/tabs/Inpainting/InpaintingPanel.tsx +++ b/frontend/src/features/tabs/Inpainting/InpaintingPanel.tsx @@ -1,21 +1,22 @@ -import { Feature } from '../../../app/features'; -import { RootState, useAppSelector } from '../../../app/store'; -import FaceRestoreHeader from '../../options/AdvancedOptions/FaceRestore/FaceRestoreHeader'; -import FaceRestoreOptions from '../../options/AdvancedOptions/FaceRestore/FaceRestoreOptions'; -import ImageToImageStrength from '../../options/AdvancedOptions/ImageToImage/ImageToImageStrength'; -import InpaintingSettings from '../../options/AdvancedOptions/Inpainting/InpaintingSettings'; -import SeedHeader from '../../options/AdvancedOptions/Seed/SeedHeader'; -import SeedOptions from '../../options/AdvancedOptions/Seed/SeedOptions'; -import UpscaleHeader from '../../options/AdvancedOptions/Upscale/UpscaleHeader'; -import UpscaleOptions from '../../options/AdvancedOptions/Upscale/UpscaleOptions'; -import VariationsHeader from '../../options/AdvancedOptions/Variations/VariationsHeader'; -import VariationsOptions from '../../options/AdvancedOptions/Variations/VariationsOptions'; -import MainAdvancedOptionsCheckbox from '../../options/MainOptions/MainAdvancedOptionsCheckbox'; -import MainOptions from '../../options/MainOptions/MainOptions'; -import OptionsAccordion from '../../options/OptionsAccordion'; -import ProcessButtons from '../../options/ProcessButtons/ProcessButtons'; -import PromptInput from '../../options/PromptInput/PromptInput'; -import InvokeOptionsPanel from '../InvokeOptionsPanel'; +// import { Feature } from 'app/features'; +import { Feature } from 'app/features'; +import { RootState, useAppSelector } from 'app/store'; +import FaceRestoreHeader from 'features/options/AdvancedOptions/FaceRestore/FaceRestoreHeader'; +import FaceRestoreOptions from 'features/options/AdvancedOptions/FaceRestore/FaceRestoreOptions'; +import ImageToImageStrength from 'features/options/AdvancedOptions/ImageToImage/ImageToImageStrength'; +import InpaintingSettings from 'features/options/AdvancedOptions/Inpainting/InpaintingSettings'; +import SeedHeader from 'features/options/AdvancedOptions/Seed/SeedHeader'; +import SeedOptions from 'features/options/AdvancedOptions/Seed/SeedOptions'; +import UpscaleHeader from 'features/options/AdvancedOptions/Upscale/UpscaleHeader'; +import UpscaleOptions from 'features/options/AdvancedOptions/Upscale/UpscaleOptions'; +import VariationsHeader from 'features/options/AdvancedOptions/Variations/VariationsHeader'; +import VariationsOptions from 'features/options/AdvancedOptions/Variations/VariationsOptions'; +import MainAdvancedOptionsCheckbox from 'features/options/MainOptions/MainAdvancedOptionsCheckbox'; +import MainOptions from 'features/options/MainOptions/MainOptions'; +import OptionsAccordion from 'features/options/OptionsAccordion'; +import ProcessButtons from 'features/options/ProcessButtons/ProcessButtons'; +import PromptInput from 'features/options/PromptInput/PromptInput'; +import InvokeOptionsPanel from 'features/tabs/InvokeOptionsPanel'; export default function InpaintingPanel() { const showAdvancedOptions = useAppSelector( @@ -56,9 +57,9 @@ export default function InpaintingPanel() { /> - {showAdvancedOptions ? ( + {showAdvancedOptions && ( - ) : null} + )} ); } diff --git a/frontend/src/features/tabs/Inpainting/Inpainting.scss b/frontend/src/features/tabs/Inpainting/InpaintingWorkarea.scss similarity index 94% rename from frontend/src/features/tabs/Inpainting/Inpainting.scss rename to frontend/src/features/tabs/Inpainting/InpaintingWorkarea.scss index de5871a080..dfc8c4244f 100644 --- a/frontend/src/features/tabs/Inpainting/Inpainting.scss +++ b/frontend/src/features/tabs/Inpainting/InpaintingWorkarea.scss @@ -30,7 +30,7 @@ } .inpainting-color-picker { - margin-left: 1rem !important; + margin-left: 1rem; } .inpainting-brush-options { @@ -70,6 +70,8 @@ .inpainting-canvas-stage { border-radius: 0.5rem; + border: 1px solid var(--border-color-light); + canvas { border-radius: 0.5rem; } diff --git a/frontend/src/features/tabs/Inpainting/InpaintingWorkarea.tsx b/frontend/src/features/tabs/Inpainting/InpaintingWorkarea.tsx new file mode 100644 index 0000000000..b224d10b0a --- /dev/null +++ b/frontend/src/features/tabs/Inpainting/InpaintingWorkarea.tsx @@ -0,0 +1,22 @@ +import InpaintingPanel from './InpaintingPanel'; +import InpaintingDisplay from './InpaintingDisplay'; +import InvokeWorkarea from 'features/tabs/InvokeWorkarea'; +import { useAppDispatch } from 'app/store'; +import { useEffect } from 'react'; +import { setCurrentCanvas, setDoesCanvasNeedScaling } from 'features/canvas/canvasSlice'; + +export default function InpaintingWorkarea() { + const dispatch = useAppDispatch(); + useEffect(() => { + dispatch(setCurrentCanvas('inpainting')); + dispatch(setDoesCanvasNeedScaling(true)); + }, [dispatch]); + return ( + } + styleClass="inpainting-workarea-overrides" + > + + + ); +} diff --git a/frontend/src/features/tabs/Inpainting/KeyboardEventManager.tsx b/frontend/src/features/tabs/Inpainting/KeyboardEventManager.tsx deleted file mode 100644 index a00b996847..0000000000 --- a/frontend/src/features/tabs/Inpainting/KeyboardEventManager.tsx +++ /dev/null @@ -1,143 +0,0 @@ -import { createSelector } from '@reduxjs/toolkit'; -import _ from 'lodash'; -import { useEffect, useRef } from 'react'; -import { useHotkeys } from 'react-hotkeys-hook'; -import { RootState, useAppDispatch, useAppSelector } from '../../../app/store'; -import { activeTabNameSelector } from '../../options/optionsSelectors'; -import { OptionsState } from '../../options/optionsSlice'; -import { - InpaintingState, - setIsSpacebarHeld, - setShouldLockBoundingBox, - toggleShouldLockBoundingBox, - toggleTool, -} from './inpaintingSlice'; - -const keyboardEventManagerSelector = createSelector( - [ - (state: RootState) => state.options, - (state: RootState) => state.inpainting, - activeTabNameSelector, - ], - (options: OptionsState, inpainting: InpaintingState, activeTabName) => { - const { - shouldShowMask, - cursorPosition, - shouldLockBoundingBox, - shouldShowBoundingBox, - } = inpainting; - return { - activeTabName, - shouldShowMask, - isCursorOnCanvas: Boolean(cursorPosition), - shouldLockBoundingBox, - shouldShowBoundingBox, - }; - }, - { - memoizeOptions: { - resultEqualityCheck: _.isEqual, - }, - } -); - -const KeyboardEventManager = () => { - const dispatch = useAppDispatch(); - const { - shouldShowMask, - activeTabName, - isCursorOnCanvas, - shouldLockBoundingBox, - shouldShowBoundingBox, - } = useAppSelector(keyboardEventManagerSelector); - - const wasLastEventOverCanvas = useRef(false); - const lastEvent = useRef(null); - - // Toggle lock bounding box - useHotkeys( - 'shift+q', - (e: KeyboardEvent) => { - e.preventDefault(); - dispatch(toggleShouldLockBoundingBox()); - }, - { - enabled: activeTabName === 'inpainting' && shouldShowMask, - }, - [activeTabName, shouldShowMask] - ); - - // Manages hold-style keyboard shortcuts - useEffect(() => { - const listener = (e: KeyboardEvent) => { - if ( - !['x', 'q'].includes(e.key) || - activeTabName !== 'inpainting' || - !shouldShowMask - ) { - return; - } - - // cursor is NOT over canvas - if (!isCursorOnCanvas) { - if (!lastEvent.current) { - lastEvent.current = e; - } - - wasLastEventOverCanvas.current = false; - return; - } - e.stopPropagation(); - e.preventDefault(); - if (e.repeat) return; - // cursor is over canvas, we can preventDefault now - - // if this is the first event - if (!lastEvent.current) { - wasLastEventOverCanvas.current = true; - lastEvent.current = e; - } - - if (!wasLastEventOverCanvas.current && e.type === 'keyup') { - wasLastEventOverCanvas.current = true; - lastEvent.current = e; - return; - } - - switch (e.key) { - case 'x': { - dispatch(toggleTool()); - break; - } - case 'q': { - if (!shouldShowMask || !shouldShowBoundingBox) break; - dispatch(setIsSpacebarHeld(e.type === 'keydown')); - dispatch(setShouldLockBoundingBox(e.type !== 'keydown')); - break; - } - } - - lastEvent.current = e; - wasLastEventOverCanvas.current = true; - }; - - document.addEventListener('keydown', listener); - document.addEventListener('keyup', listener); - - return () => { - document.removeEventListener('keydown', listener); - document.removeEventListener('keyup', listener); - }; - }, [ - dispatch, - activeTabName, - shouldShowMask, - isCursorOnCanvas, - shouldLockBoundingBox, - shouldShowBoundingBox, - ]); - - return null; -}; - -export default KeyboardEventManager; diff --git a/frontend/src/features/tabs/Inpainting/components/Cacher.tsx b/frontend/src/features/tabs/Inpainting/components/Cacher.tsx deleted file mode 100644 index 7a6d96c3c9..0000000000 --- a/frontend/src/features/tabs/Inpainting/components/Cacher.tsx +++ /dev/null @@ -1,97 +0,0 @@ -import { useEffect, useLayoutEffect } from 'react'; -import { RootState, useAppSelector } from '../../../../app/store'; -import { maskLayerRef } from '../InpaintingCanvas'; - -/** - * Konva's cache() method basically rasterizes an object/canvas. - * This is needed to rasterize the mask, before setting the opacity. - * If we do not cache the maskLayer, the brush strokes will have opacity - * set individually. - * - * This logical component simply uses useLayoutEffect() to synchronously - * cache the mask layer every time something that changes how it should draw - * is changed. - */ -const Cacher = () => { - const { - tool, - lines, - cursorPosition, - brushSize, - canvasDimensions: { width, height }, - maskColor, - shouldInvertMask, - shouldShowMask, - shouldShowBrushPreview, - shouldShowCheckboardTransparency, - imageToInpaint, - shouldShowBrush, - shouldShowBoundingBoxFill, - shouldLockBoundingBox, - stageScale, - pastLines, - futureLines, - needsCache, - isDrawing, - isTransformingBoundingBox, - isMovingBoundingBox, - shouldShowBoundingBox, - } = useAppSelector((state: RootState) => state.inpainting); - - useLayoutEffect(() => { - if (!maskLayerRef.current) return; - maskLayerRef.current.cache({ - x: 0, - y: 0, - width, - height, - }); - }, [ - lines, - cursorPosition, - width, - height, - tool, - brushSize, - maskColor, - shouldInvertMask, - shouldShowMask, - shouldShowBrushPreview, - shouldShowCheckboardTransparency, - imageToInpaint, - shouldShowBrush, - shouldShowBoundingBoxFill, - shouldShowBoundingBox, - shouldLockBoundingBox, - stageScale, - pastLines, - futureLines, - needsCache, - isDrawing, - isTransformingBoundingBox, - isMovingBoundingBox, - ]); - - /** - * Hack to cache the mask layer after the canvas is ready. - */ - useEffect(() => { - const intervalId = window.setTimeout(() => { - if (!maskLayerRef.current) return; - maskLayerRef.current.cache({ - x: 0, - y: 0, - width, - height, - }); - }, 0); - - return () => { - window.clearTimeout(intervalId); - }; - }); - - return null; -}; - -export default Cacher; diff --git a/frontend/src/features/tabs/Inpainting/components/InpaintingCanvasBrushPreview.tsx b/frontend/src/features/tabs/Inpainting/components/InpaintingCanvasBrushPreview.tsx deleted file mode 100644 index 42beadd2b7..0000000000 --- a/frontend/src/features/tabs/Inpainting/components/InpaintingCanvasBrushPreview.tsx +++ /dev/null @@ -1,75 +0,0 @@ -import { createSelector } from '@reduxjs/toolkit'; -import _ from 'lodash'; -import { Circle } from 'react-konva'; -import { RootState, useAppSelector } from '../../../../app/store'; -import { InpaintingState } from '../inpaintingSlice'; -import { rgbaColorToRgbString } from '../util/colorToString'; - -const inpaintingCanvasBrushPreviewSelector = createSelector( - (state: RootState) => state.inpainting, - (inpainting: InpaintingState) => { - const { - cursorPosition, - canvasDimensions: { width, height }, - brushSize, - maskColor, - tool, - shouldShowBrush, - isMovingBoundingBox, - isTransformingBoundingBox, - } = inpainting; - - return { - cursorPosition, - width, - height, - brushSize, - maskColorString: rgbaColorToRgbString(maskColor), - tool, - shouldShowBrush, - shouldDrawBrushPreview: - !( - isMovingBoundingBox || - isTransformingBoundingBox || - !cursorPosition - ) && shouldShowBrush, - }; - }, - { - memoizeOptions: { - resultEqualityCheck: _.isEqual, - }, - } -); - -/** - * Draws a black circle around the canvas brush preview. - */ -const InpaintingCanvasBrushPreview = () => { - const { - cursorPosition, - width, - height, - brushSize, - maskColorString, - tool, - shouldDrawBrushPreview, - } = useAppSelector(inpaintingCanvasBrushPreviewSelector); - - if (!shouldDrawBrushPreview) return null; - - return ( - - ); -}; - -export default InpaintingCanvasBrushPreview; diff --git a/frontend/src/features/tabs/Inpainting/components/InpaintingCanvasBrushPreviewOutline.tsx b/frontend/src/features/tabs/Inpainting/components/InpaintingCanvasBrushPreviewOutline.tsx deleted file mode 100644 index 3a99d696ae..0000000000 --- a/frontend/src/features/tabs/Inpainting/components/InpaintingCanvasBrushPreviewOutline.tsx +++ /dev/null @@ -1,80 +0,0 @@ -import { createSelector } from '@reduxjs/toolkit'; -import _ from 'lodash'; -import { Circle } from 'react-konva'; -import { RootState, useAppSelector } from '../../../../app/store'; -import { InpaintingState } from '../inpaintingSlice'; - -const inpaintingCanvasBrushPrevieOutlineSelector = createSelector( - (state: RootState) => state.inpainting, - (inpainting: InpaintingState) => { - const { - cursorPosition, - canvasDimensions: { width, height }, - brushSize, - tool, - shouldShowBrush, - isMovingBoundingBox, - isTransformingBoundingBox, - stageScale, - } = inpainting; - - return { - cursorPosition, - width, - height, - brushSize, - tool, - strokeWidth: 1 / stageScale, // scale stroke thickness - radius: 1 / stageScale, // scale stroke thickness - shouldDrawBrushPreview: - !( - isMovingBoundingBox || - isTransformingBoundingBox || - !cursorPosition - ) && shouldShowBrush, - }; - }, - { - memoizeOptions: { - resultEqualityCheck: _.isEqual, - }, - } -); - -/** - * Draws the canvas brush preview outline. - */ -const InpaintingCanvasBrushPreviewOutline = () => { - const { - cursorPosition, - width, - height, - brushSize, - shouldDrawBrushPreview, - strokeWidth, - radius, - } = useAppSelector(inpaintingCanvasBrushPrevieOutlineSelector); - - if (!shouldDrawBrushPreview) return null; - return ( - <> - - - - ); -}; -export default InpaintingCanvasBrushPreviewOutline; diff --git a/frontend/src/features/tabs/Inpainting/components/InpaintingCanvasLines.tsx b/frontend/src/features/tabs/Inpainting/components/InpaintingCanvasLines.tsx deleted file mode 100644 index d9cc41038d..0000000000 --- a/frontend/src/features/tabs/Inpainting/components/InpaintingCanvasLines.tsx +++ /dev/null @@ -1,37 +0,0 @@ -import { Line } from 'react-konva'; -import { useAppSelector } from '../../../../app/store'; -import { inpaintingCanvasLinesSelector } from '../inpaintingSliceSelectors'; - -/** - * Draws the lines which comprise the mask. - * - * Uses globalCompositeOperation to handle the brush and eraser tools. - */ -const InpaintingCanvasLines = () => { - const { lines, maskColorString } = useAppSelector( - inpaintingCanvasLinesSelector - ); - - return ( - <> - {lines.map((line, i) => ( - - ))} - - ); -}; - -export default InpaintingCanvasLines; diff --git a/frontend/src/features/tabs/Inpainting/hooks/_useInpaintingHotkeys.ts b/frontend/src/features/tabs/Inpainting/hooks/_useInpaintingHotkeys.ts deleted file mode 100644 index af7f380fef..0000000000 --- a/frontend/src/features/tabs/Inpainting/hooks/_useInpaintingHotkeys.ts +++ /dev/null @@ -1,146 +0,0 @@ -import { useToast } from '@chakra-ui/react'; -import { useHotkeys } from 'react-hotkeys-hook'; - -type UseInpaintingHotkeysConfig = { - activeTab: string; - brushSize: number; - handleChangeBrushSize: (newBrushSize: number) => void; - handleSelectEraserTool: () => void; - handleSelectBrushTool: () => void; - canUndo: boolean; - handleUndo: () => void; - canRedo: boolean; - handleRedo: () => void; - canClearMask: boolean; - handleClearMask: () => void; -}; - -const useInpaintingHotkeys = (config: UseInpaintingHotkeysConfig) => { - const { - activeTab, - brushSize, - handleChangeBrushSize, - handleSelectEraserTool, - handleSelectBrushTool, - canUndo, - handleUndo, - canRedo, - handleRedo, - canClearMask, - handleClearMask, - } = config; - - const toast = useToast(); - // Hotkeys - useHotkeys( - '[', - () => { - if (activeTab === 'inpainting' && brushSize - 5 > 0) { - handleChangeBrushSize(brushSize - 5); - } else { - handleChangeBrushSize(1); - } - }, - [brushSize] - ); - - useHotkeys( - ']', - () => { - if (activeTab === 'inpainting') { - handleChangeBrushSize(brushSize + 5); - } - }, - [brushSize] - ); - - useHotkeys('e', () => { - if (activeTab === 'inpainting') { - handleSelectEraserTool(); - } - }); - - useHotkeys('b', () => { - if (activeTab === 'inpainting') { - handleSelectBrushTool(); - } - }); - - useHotkeys( - 'cmd+z', - () => { - if (activeTab === 'inpainting' && canUndo) { - handleUndo(); - } - }, - [canUndo] - ); - - useHotkeys( - 'control+z', - () => { - if (activeTab === 'inpainting' && canUndo) { - handleUndo(); - } - }, - [canUndo] - ); - - useHotkeys( - 'cmd+shift+z', - () => { - if (activeTab === 'inpainting' && canRedo) { - handleRedo(); - } - }, - [canRedo] - ); - - useHotkeys( - 'control+shift+z', - () => { - if (activeTab === 'inpainting' && canRedo) { - handleRedo(); - } - }, - [canRedo] - ); - - useHotkeys( - 'control+y', - () => { - if (activeTab === 'inpainting' && canRedo) { - handleRedo(); - } - }, - [canRedo] - ); - - useHotkeys( - 'cmd+y', - () => { - if (activeTab === 'inpainting' && canRedo) { - handleRedo(); - } - }, - [canRedo] - ); - - useHotkeys( - 'c', - () => { - if (activeTab === 'inpainting' && canClearMask) { - handleClearMask(); - toast({ - title: 'Mask Cleared', - status: 'success', - duration: 2500, - isClosable: true, - }); - } - }, - [canClearMask] - ); -}; - -export default useInpaintingHotkeys; diff --git a/frontend/src/features/tabs/Inpainting/index.tsx b/frontend/src/features/tabs/Inpainting/index.tsx deleted file mode 100644 index 4b63c43412..0000000000 --- a/frontend/src/features/tabs/Inpainting/index.tsx +++ /dev/null @@ -1,14 +0,0 @@ -import InpaintingPanel from './InpaintingPanel'; -import InpaintingDisplay from './InpaintingDisplay'; -import InvokeWorkarea from '../InvokeWorkarea'; - -export default function InpaintingWorkarea() { - return ( - } - styleClass="inpainting-workarea-overrides" - > - - - ); -} diff --git a/frontend/src/features/tabs/Inpainting/inpaintingSlice.ts b/frontend/src/features/tabs/Inpainting/inpaintingSlice.ts deleted file mode 100644 index dee72de7d9..0000000000 --- a/frontend/src/features/tabs/Inpainting/inpaintingSlice.ts +++ /dev/null @@ -1,383 +0,0 @@ -import { createSlice } from '@reduxjs/toolkit'; -import type { PayloadAction } from '@reduxjs/toolkit'; -import { Vector2d } from 'konva/lib/types'; -import { RgbaColor } from 'react-colorful'; -import * as InvokeAI from '../../../app/invokeai'; -import _ from 'lodash'; -import { roundDownToMultiple } from '../../../common/util/roundDownToMultiple'; - -export type InpaintingTool = 'brush' | 'eraser'; - -export type MaskLine = { - tool: InpaintingTool; - strokeWidth: number; - points: number[]; -}; - -export type MaskCircle = { - tool: InpaintingTool; - radius: number; - x: number; - y: number; -}; - -export type Dimensions = { - width: number; - height: number; -}; - -export type BoundingBoxPreviewType = 'overlay' | 'ants' | 'marchingAnts'; - -export interface InpaintingState { - tool: 'brush' | 'eraser'; - brushSize: number; - maskColor: RgbaColor; - cursorPosition: Vector2d | null; - canvasDimensions: Dimensions; - boundingBoxDimensions: Dimensions; - boundingBoxCoordinate: Vector2d; - boundingBoxPreviewFill: RgbaColor; - shouldShowBoundingBox: boolean; - shouldShowBoundingBoxFill: boolean; - lines: MaskLine[]; - pastLines: MaskLine[][]; - futureLines: MaskLine[][]; - shouldShowMask: boolean; - shouldInvertMask: boolean; - shouldShowCheckboardTransparency: boolean; - shouldShowBrush: boolean; - shouldShowBrushPreview: boolean; - imageToInpaint?: InvokeAI.Image; - needsCache: boolean; - stageScale: number; - isDrawing: boolean; - isTransformingBoundingBox: boolean; - isMouseOverBoundingBox: boolean; - isMovingBoundingBox: boolean; - shouldUseInpaintReplace: boolean; - inpaintReplace: number; - shouldLockBoundingBox: boolean; - isSpacebarHeld: boolean; -} - -const initialInpaintingState: InpaintingState = { - tool: 'brush', - brushSize: 50, - maskColor: { r: 255, g: 90, b: 90, a: 0.5 }, - canvasDimensions: { width: 0, height: 0 }, - boundingBoxDimensions: { width: 512, height: 512 }, - boundingBoxCoordinate: { x: 0, y: 0 }, - boundingBoxPreviewFill: { r: 0, g: 0, b: 0, a: 0.5 }, - shouldShowBoundingBox: true, - shouldShowBoundingBoxFill: true, - cursorPosition: null, - lines: [], - pastLines: [], - futureLines: [], - shouldShowMask: true, - shouldInvertMask: false, - shouldShowCheckboardTransparency: false, - shouldShowBrush: true, - shouldShowBrushPreview: false, - needsCache: false, - isDrawing: false, - isTransformingBoundingBox: false, - isMouseOverBoundingBox: false, - isMovingBoundingBox: false, - stageScale: 1, - shouldUseInpaintReplace: false, - inpaintReplace: 0.1, - shouldLockBoundingBox: true, - isSpacebarHeld: false, -}; - -const initialState: InpaintingState = initialInpaintingState; - -export const inpaintingSlice = createSlice({ - name: 'inpainting', - initialState, - reducers: { - setTool: (state, action: PayloadAction) => { - state.tool = action.payload; - }, - toggleTool: (state) => { - state.tool = state.tool === 'brush' ? 'eraser' : 'brush'; - }, - setBrushSize: (state, action: PayloadAction) => { - state.brushSize = action.payload; - }, - addLine: (state, action: PayloadAction) => { - state.pastLines.push(state.lines); - state.lines.push(action.payload); - state.futureLines = []; - }, - addPointToCurrentLine: (state, action: PayloadAction) => { - state.lines[state.lines.length - 1].points.push(...action.payload); - }, - undo: (state) => { - if (state.pastLines.length === 0) return; - const newLines = state.pastLines.pop(); - if (!newLines) return; - state.futureLines.unshift(state.lines); - state.lines = newLines; - }, - redo: (state) => { - if (state.futureLines.length === 0) return; - const newLines = state.futureLines.shift(); - if (!newLines) return; - state.pastLines.push(state.lines); - state.lines = newLines; - }, - clearMask: (state) => { - state.pastLines.push(state.lines); - state.lines = []; - state.futureLines = []; - state.shouldInvertMask = false; - }, - toggleShouldInvertMask: (state) => { - state.shouldInvertMask = !state.shouldInvertMask; - }, - toggleShouldShowMask: (state) => { - state.shouldShowMask = !state.shouldShowMask; - }, - setShouldInvertMask: (state, action: PayloadAction) => { - state.shouldInvertMask = action.payload; - }, - setShouldShowMask: (state, action: PayloadAction) => { - state.shouldShowMask = action.payload; - if (!action.payload) { - state.shouldInvertMask = false; - } - }, - setShouldShowCheckboardTransparency: ( - state, - action: PayloadAction - ) => { - state.shouldShowCheckboardTransparency = action.payload; - }, - setShouldShowBrushPreview: (state, action: PayloadAction) => { - state.shouldShowBrushPreview = action.payload; - }, - setShouldShowBrush: (state, action: PayloadAction) => { - state.shouldShowBrush = action.payload; - }, - setMaskColor: (state, action: PayloadAction) => { - state.maskColor = action.payload; - }, - setCursorPosition: (state, action: PayloadAction) => { - state.cursorPosition = action.payload; - }, - clearImageToInpaint: (state) => { - state.imageToInpaint = undefined; - }, - setImageToInpaint: (state, action: PayloadAction) => { - const { width: imageWidth, height: imageHeight } = action.payload; - const { width, height } = state.boundingBoxDimensions; - const { x, y } = state.boundingBoxCoordinate; - - const newCoordinates: Vector2d = { x, y }; - const newDimensions: Dimensions = { width, height }; - - if (width + x > imageWidth) { - // Bounding box at least needs to be translated - if (width > imageWidth) { - // Bounding box also needs to be resized - newDimensions.width = roundDownToMultiple(imageWidth, 64); - } - newCoordinates.x = imageWidth - newDimensions.width; - } - - if (height + y > imageHeight) { - // Bounding box at least needs to be translated - if (height > imageHeight) { - // Bounding box also needs to be resized - newDimensions.height = roundDownToMultiple(imageHeight, 64); - } - newCoordinates.y = imageHeight - newDimensions.height; - } - - state.boundingBoxDimensions = newDimensions; - state.boundingBoxCoordinate = newCoordinates; - - state.canvasDimensions = { - width: imageWidth, - height: imageHeight, - }; - - state.imageToInpaint = action.payload; - state.needsCache = true; - }, - setCanvasDimensions: (state, action: PayloadAction) => { - state.canvasDimensions = action.payload; - - const { width: canvasWidth, height: canvasHeight } = action.payload; - - const { width: boundingBoxWidth, height: boundingBoxHeight } = - state.boundingBoxDimensions; - - const newBoundingBoxWidth = roundDownToMultiple( - _.clamp(boundingBoxWidth, 64, canvasWidth), - 64 - ); - const newBoundingBoxHeight = roundDownToMultiple( - _.clamp(boundingBoxHeight, 64, canvasHeight), - 64 - ); - - state.boundingBoxDimensions = { - width: newBoundingBoxWidth, - height: newBoundingBoxHeight, - }; - }, - setBoundingBoxDimensions: (state, action: PayloadAction) => { - state.boundingBoxDimensions = action.payload; - const { width: boundingBoxWidth, height: boundingBoxHeight } = - action.payload; - const { x: boundingBoxX, y: boundingBoxY } = state.boundingBoxCoordinate; - const { width: canvasWidth, height: canvasHeight } = - state.canvasDimensions; - - const roundedCanvasWidth = roundDownToMultiple(canvasWidth, 64); - const roundedCanvasHeight = roundDownToMultiple(canvasHeight, 64); - - const roundedBoundingBoxWidth = roundDownToMultiple(boundingBoxWidth, 64); - const roundedBoundingBoxHeight = roundDownToMultiple( - boundingBoxHeight, - 64 - ); - - const overflowX = boundingBoxX + boundingBoxWidth - canvasWidth; - const overflowY = boundingBoxY + boundingBoxHeight - canvasHeight; - - const newBoundingBoxWidth = _.clamp( - roundedBoundingBoxWidth, - 64, - roundedCanvasWidth - ); - - const newBoundingBoxHeight = _.clamp( - roundedBoundingBoxHeight, - 64, - roundedCanvasHeight - ); - - const overflowCorrectedX = - overflowX > 0 ? boundingBoxX - overflowX : boundingBoxX; - - const overflowCorrectedY = - overflowY > 0 ? boundingBoxY - overflowY : boundingBoxY; - - const clampedX = _.clamp( - overflowCorrectedX, - 0, - roundedCanvasWidth - newBoundingBoxWidth - ); - - const clampedY = _.clamp( - overflowCorrectedY, - 0, - roundedCanvasHeight - newBoundingBoxHeight - ); - - state.boundingBoxDimensions = { - width: newBoundingBoxWidth, - height: newBoundingBoxHeight, - }; - - state.boundingBoxCoordinate = { - x: clampedX, - y: clampedY, - }; - }, - setBoundingBoxCoordinate: (state, action: PayloadAction) => { - state.boundingBoxCoordinate = action.payload; - }, - setBoundingBoxPreviewFill: (state, action: PayloadAction) => { - state.boundingBoxPreviewFill = action.payload; - }, - setNeedsCache: (state, action: PayloadAction) => { - state.needsCache = action.payload; - }, - setStageScale: (state, action: PayloadAction) => { - state.stageScale = action.payload; - state.needsCache = false; - }, - setShouldShowBoundingBoxFill: (state, action: PayloadAction) => { - state.shouldShowBoundingBoxFill = action.payload; - }, - setIsDrawing: (state, action: PayloadAction) => { - state.isDrawing = action.payload; - }, - setClearBrushHistory: (state) => { - state.pastLines = []; - state.futureLines = []; - }, - setShouldUseInpaintReplace: (state, action: PayloadAction) => { - state.shouldUseInpaintReplace = action.payload; - }, - setInpaintReplace: (state, action: PayloadAction) => { - state.inpaintReplace = action.payload; - }, - setShouldLockBoundingBox: (state, action: PayloadAction) => { - state.shouldLockBoundingBox = action.payload; - }, - toggleShouldLockBoundingBox: (state) => { - state.shouldLockBoundingBox = !state.shouldLockBoundingBox; - }, - setShouldShowBoundingBox: (state, action: PayloadAction) => { - state.shouldShowBoundingBox = action.payload; - }, - setIsTransformingBoundingBox: (state, action: PayloadAction) => { - state.isTransformingBoundingBox = action.payload; - }, - setIsMovingBoundingBox: (state, action: PayloadAction) => { - state.isMovingBoundingBox = action.payload; - }, - setIsMouseOverBoundingBox: (state, action: PayloadAction) => { - state.isMouseOverBoundingBox = action.payload; - }, - setIsSpacebarHeld: (state, action: PayloadAction) => { - state.isSpacebarHeld = action.payload; - }, - }, -}); - -export const { - setTool, - setBrushSize, - addLine, - addPointToCurrentLine, - setShouldInvertMask, - setShouldShowMask, - setShouldShowCheckboardTransparency, - setShouldShowBrushPreview, - setMaskColor, - clearMask, - clearImageToInpaint, - undo, - redo, - setCursorPosition, - setCanvasDimensions, - setImageToInpaint, - setBoundingBoxDimensions, - setBoundingBoxCoordinate, - setBoundingBoxPreviewFill, - setNeedsCache, - setStageScale, - toggleTool, - setShouldShowBoundingBox, - setShouldShowBoundingBoxFill, - setIsDrawing, - setShouldShowBrush, - setClearBrushHistory, - setShouldUseInpaintReplace, - setInpaintReplace, - setShouldLockBoundingBox, - toggleShouldLockBoundingBox, - setIsMovingBoundingBox, - setIsTransformingBoundingBox, - setIsMouseOverBoundingBox, - setIsSpacebarHeld, -} = inpaintingSlice.actions; - -export default inpaintingSlice.reducer; diff --git a/frontend/src/features/tabs/Inpainting/inpaintingSliceSelectors.ts b/frontend/src/features/tabs/Inpainting/inpaintingSliceSelectors.ts deleted file mode 100644 index 3d7022d018..0000000000 --- a/frontend/src/features/tabs/Inpainting/inpaintingSliceSelectors.ts +++ /dev/null @@ -1,129 +0,0 @@ -import { createSelector } from '@reduxjs/toolkit'; -import _ from 'lodash'; -import { RootState } from '../../../app/store'; -import { activeTabNameSelector } from '../../options/optionsSelectors'; -import { OptionsState } from '../../options/optionsSlice'; -import { InpaintingState } from './inpaintingSlice'; -import { rgbaColorToRgbString } from './util/colorToString'; - -export const inpaintingCanvasLinesSelector = createSelector( - (state: RootState) => state.inpainting, - (inpainting: InpaintingState) => { - const { lines, maskColor } = inpainting; - return { - lines, - maskColorString: rgbaColorToRgbString(maskColor), - }; - } -); - -export const inpaintingControlsSelector = createSelector( - [ - (state: RootState) => state.inpainting, - (state: RootState) => state.options, - activeTabNameSelector, - ], - (inpainting: InpaintingState, options: OptionsState, activeTabName) => { - const { - tool, - brushSize, - maskColor, - shouldInvertMask, - shouldShowMask, - shouldShowCheckboardTransparency, - lines, - pastLines, - futureLines, - shouldShowBoundingBoxFill, - } = inpainting; - - const { showDualDisplay } = options; - - return { - tool, - brushSize, - maskColor, - shouldInvertMask, - shouldShowMask, - shouldShowCheckboardTransparency, - canUndo: pastLines.length > 0, - canRedo: futureLines.length > 0, - isMaskEmpty: lines.length === 0, - activeTabName, - showDualDisplay, - shouldShowBoundingBoxFill, - }; - }, - { - memoizeOptions: { - resultEqualityCheck: _.isEqual, - }, - } -); - -export const inpaintingCanvasSelector = createSelector( - (state: RootState) => state.inpainting, - (inpainting: InpaintingState) => { - const { - tool, - brushSize, - maskColor, - shouldInvertMask, - shouldShowMask, - shouldShowCheckboardTransparency, - imageToInpaint, - stageScale, - shouldShowBoundingBox, - shouldShowBoundingBoxFill, - isDrawing, - shouldLockBoundingBox, - boundingBoxDimensions, - isTransformingBoundingBox, - isMouseOverBoundingBox, - isMovingBoundingBox, - } = inpainting; - - let stageCursor: string | undefined = ''; - - if (isTransformingBoundingBox) { - stageCursor = undefined; - } else if (isMovingBoundingBox || isMouseOverBoundingBox) { - stageCursor = 'move'; - } else if (shouldShowMask) { - stageCursor = 'none'; - } else { - stageCursor = 'default'; - } - - return { - tool, - brushSize, - shouldInvertMask, - shouldShowMask, - shouldShowCheckboardTransparency, - maskColor, - imageToInpaint, - stageScale, - shouldShowBoundingBox, - shouldShowBoundingBoxFill, - isDrawing, - shouldLockBoundingBox, - boundingBoxDimensions, - isTransformingBoundingBox, - isModifyingBoundingBox: isTransformingBoundingBox || isMovingBoundingBox, - stageCursor, - isMouseOverBoundingBox, - }; - }, - { - memoizeOptions: { - resultEqualityCheck: (a, b) => { - const { imageToInpaint: a_imageToInpaint, ...a_rest } = a; - const { imageToInpaint: b_imageToInpaint, ...b_rest } = b; - return ( - _.isEqual(a_rest, b_rest) && a_imageToInpaint == b_imageToInpaint - ); - }, - }, - } -); diff --git a/frontend/src/features/tabs/Inpainting/util/generateMask.ts b/frontend/src/features/tabs/Inpainting/util/generateMask.ts deleted file mode 100644 index 11e4cc2f00..0000000000 --- a/frontend/src/features/tabs/Inpainting/util/generateMask.ts +++ /dev/null @@ -1,109 +0,0 @@ -import Konva from 'konva'; -import { IRect } from 'konva/lib/types'; -import { MaskLine } from '../inpaintingSlice'; - -/** - * Re-draws the mask canvas onto a new Konva stage. - */ -export const generateMaskCanvas = ( - image: HTMLImageElement, - lines: MaskLine[] -): { - stage: Konva.Stage; - layer: Konva.Layer; -} => { - const { width, height } = image; - - const offscreenContainer = document.createElement('div'); - - const stage = new Konva.Stage({ - container: offscreenContainer, - width: width, - height: height, - }); - - const layer = new Konva.Layer(); - - stage.add(layer); - - lines.forEach((line) => - layer.add( - new Konva.Line({ - points: line.points, - stroke: 'rgb(0,0,0)', - strokeWidth: line.strokeWidth * 2, - tension: 0, - lineCap: 'round', - lineJoin: 'round', - shadowForStrokeEnabled: false, - globalCompositeOperation: - line.tool === 'brush' ? 'source-over' : 'destination-out', - }) - ) - ); - - layer.draw(); - - offscreenContainer.remove(); - - return { stage, layer }; -}; - -/** - * Check if the bounding box region has only fully transparent pixels. - */ -export const checkIsRegionEmpty = ( - stage: Konva.Stage, - boundingBox: IRect -): boolean => { - const imageData = stage - .toCanvas() - .getContext('2d') - ?.getImageData( - boundingBox.x, - boundingBox.y, - boundingBox.width, - boundingBox.height - ); - - if (!imageData) { - throw new Error('Unable to get image data from generated canvas'); - } - - const pixelBuffer = new Uint32Array(imageData.data.buffer); - - return !pixelBuffer.some((color) => color !== 0); -}; - -/** - * Generating a mask image from InpaintingCanvas.tsx is not as simple - * as calling toDataURL() on the canvas, because the mask may be represented - * by colored lines or transparency, or the user may have inverted the mask - * display. - * - * So we need to regenerate the mask image by creating an offscreen canvas, - * drawing the mask and compositing everything correctly to output a valid - * mask image. - */ -const generateMask = ( - image: HTMLImageElement, - lines: MaskLine[], - boundingBox: IRect -): { maskDataURL: string; isMaskEmpty: boolean } => { - // create an offscreen canvas and add the mask to it - const { stage, layer } = generateMaskCanvas(image, lines); - - // check if the mask layer is empty - const isMaskEmpty = checkIsRegionEmpty(stage, boundingBox); - - // composite the image onto the mask layer - layer.add( - new Konva.Image({ image: image, globalCompositeOperation: 'source-out' }) - ); - - const maskDataURL = stage.toDataURL({ ...boundingBox }); - - return { maskDataURL, isMaskEmpty }; -}; - -export default generateMask; diff --git a/frontend/src/features/tabs/InvokeOptionsPanel.scss b/frontend/src/features/tabs/InvokeOptionsPanel.scss index 5a50c5f79d..c11b86511e 100644 --- a/frontend/src/features/tabs/InvokeOptionsPanel.scss +++ b/frontend/src/features/tabs/InvokeOptionsPanel.scss @@ -35,7 +35,7 @@ row-gap: 1rem; height: 100%; @include HideScrollbar; - background-color: var(--background-color) !important; + background-color: var(--background-color); } &[data-pinned='false'] { diff --git a/frontend/src/features/tabs/InvokeOptionsPanel.tsx b/frontend/src/features/tabs/InvokeOptionsPanel.tsx index 5a60a93e18..9f24e377ec 100644 --- a/frontend/src/features/tabs/InvokeOptionsPanel.tsx +++ b/frontend/src/features/tabs/InvokeOptionsPanel.tsx @@ -5,17 +5,17 @@ import { MouseEvent, ReactNode, useCallback, useRef } from 'react'; import { useHotkeys } from 'react-hotkeys-hook'; import { BsPinAngle, BsPinAngleFill } from 'react-icons/bs'; import { CSSTransition } from 'react-transition-group'; -import { RootState, useAppDispatch, useAppSelector } from '../../app/store'; -import useClickOutsideWatcher from '../../common/hooks/useClickOutsideWatcher'; +import { RootState, useAppDispatch, useAppSelector } from 'app/store'; +import useClickOutsideWatcher from 'common/hooks/useClickOutsideWatcher'; import { OptionsState, setOptionsPanelScrollPosition, setShouldHoldOptionsPanelOpen, setShouldPinOptionsPanel, setShouldShowOptionsPanel, -} from '../options/optionsSlice'; -import { setNeedsCache } from './Inpainting/inpaintingSlice'; -import InvokeAILogo from '../../assets/images/logo.png'; +} from 'features/options/optionsSlice'; +import { setDoesCanvasNeedScaling } from 'features/canvas/canvasSlice'; +import InvokeAILogo from 'assets/images/logo.png'; type Props = { children: ReactNode }; @@ -63,8 +63,10 @@ const InvokeOptionsPanel = (props: Props) => { 'o', () => { dispatch(setShouldShowOptionsPanel(!shouldShowOptionsPanel)); + shouldPinOptionsPanel && + setTimeout(() => dispatch(setDoesCanvasNeedScaling(true)), 400); }, - [shouldShowOptionsPanel] + [shouldShowOptionsPanel, shouldPinOptionsPanel] ); useHotkeys( @@ -72,6 +74,7 @@ const InvokeOptionsPanel = (props: Props) => { () => { if (shouldPinOptionsPanel) return; dispatch(setShouldShowOptionsPanel(false)); + dispatch(setDoesCanvasNeedScaling(true)); }, [shouldPinOptionsPanel] ); @@ -80,6 +83,7 @@ const InvokeOptionsPanel = (props: Props) => { 'shift+o', () => { handleClickPinOptionsPanel(); + dispatch(setDoesCanvasNeedScaling(true)); }, [shouldPinOptionsPanel] ); @@ -95,7 +99,7 @@ const InvokeOptionsPanel = (props: Props) => { ); dispatch(setShouldShowOptionsPanel(false)); dispatch(setShouldHoldOptionsPanelOpen(false)); - // dispatch(setNeedsCache(true)); + // dispatch(setDoesCanvasNeedScaling(true)); }, [dispatch, shouldPinOptionsPanel]); useClickOutsideWatcher( @@ -117,7 +121,7 @@ const InvokeOptionsPanel = (props: Props) => { const handleClickPinOptionsPanel = () => { dispatch(setShouldPinOptionsPanel(!shouldPinOptionsPanel)); - dispatch(setNeedsCache(true)); + dispatch(setDoesCanvasNeedScaling(true)); }; return ( diff --git a/frontend/src/features/tabs/InvokeTabs.scss b/frontend/src/features/tabs/InvokeTabs.scss index da837a20ee..77bfeae581 100644 --- a/frontend/src/features/tabs/InvokeTabs.scss +++ b/frontend/src/features/tabs/InvokeTabs.scss @@ -1,7 +1,7 @@ @use '../../styles/Mixins/' as *; .app-tabs { - display: grid !important; + display: grid; grid-template-columns: min-content auto; column-gap: 1rem; // height: 100%; diff --git a/frontend/src/features/tabs/InvokeTabs.tsx b/frontend/src/features/tabs/InvokeTabs.tsx index 8cbd0df124..33dcd10b1e 100644 --- a/frontend/src/features/tabs/InvokeTabs.tsx +++ b/frontend/src/features/tabs/InvokeTabs.tsx @@ -2,21 +2,32 @@ import { Tab, TabPanel, TabPanels, Tabs, Tooltip } from '@chakra-ui/react'; import _ from 'lodash'; import React, { ReactElement } from 'react'; import { useHotkeys } from 'react-hotkeys-hook'; -import { RootState, useAppDispatch, useAppSelector } from '../../app/store'; -import NodesWIP from '../../common/components/WorkInProgress/NodesWIP'; -import OutpaintingWIP from '../../common/components/WorkInProgress/OutpaintingWIP'; -import { PostProcessingWIP } from '../../common/components/WorkInProgress/PostProcessingWIP'; -import ImageToImageIcon from '../../common/icons/ImageToImageIcon'; -import InpaintIcon from '../../common/icons/InpaintIcon'; -import NodesIcon from '../../common/icons/NodesIcon'; -import OutpaintIcon from '../../common/icons/OutpaintIcon'; -import PostprocessingIcon from '../../common/icons/PostprocessingIcon'; -import TextToImageIcon from '../../common/icons/TextToImageIcon'; -import { setActiveTab } from '../options/optionsSlice'; +import { RootState, useAppDispatch, useAppSelector } from 'app/store'; +import NodesWIP from 'common/components/WorkInProgress/NodesWIP'; +import OutpaintingWIP from 'common/components/WorkInProgress/OutpaintingWIP'; +import { PostProcessingWIP } from 'common/components/WorkInProgress/PostProcessingWIP'; +import ImageToImageIcon from 'common/icons/ImageToImageIcon'; +import InpaintIcon from 'common/icons/InpaintIcon'; +import NodesIcon from 'common/icons/NodesIcon'; +import OutpaintIcon from 'common/icons/OutpaintIcon'; +import PostprocessingIcon from 'common/icons/PostprocessingIcon'; +import TextToImageIcon from 'common/icons/TextToImageIcon'; +import { + setActiveTab, + setIsLightBoxOpen, + setShouldShowOptionsPanel, +} from 'features/options/optionsSlice'; import ImageToImageWorkarea from './ImageToImage'; -import InpaintingWorkarea from './Inpainting'; -import { setNeedsCache } from './Inpainting/inpaintingSlice'; +import InpaintingWorkarea from './Inpainting/InpaintingWorkarea'; +// import { setDoesCanvasNeedScaling } from './Inpainting/inpaintingSlice'; import TextToImageWorkarea from './TextToImage'; +import Lightbox from 'features/lightbox/Lightbox'; +import { + setCurrentCanvas, + setDoesCanvasNeedScaling, +} from 'features/canvas/canvasSlice'; +import OutpaintingWorkarea from './Outpainting/OutpaintingWorkarea'; +import { setShouldShowGallery } from 'features/gallery/gallerySlice'; export const tabDict = { txt2img: { @@ -36,7 +47,7 @@ export const tabDict = { }, outpainting: { title: , - workarea: , + workarea: , tooltip: 'Outpainting', }, nodes: { @@ -62,6 +73,15 @@ export default function InvokeTabs() { const activeTab = useAppSelector( (state: RootState) => state.options.activeTab ); + const isLightBoxOpen = useAppSelector( + (state: RootState) => state.options.isLightBoxOpen + ); + const shouldShowGallery = useAppSelector( + (state: RootState) => state.gallery.shouldShowGallery + ); + const shouldShowOptionsPanel = useAppSelector( + (state: RootState) => state.options.shouldShowOptionsPanel + ); const dispatch = useAppDispatch(); useHotkeys('1', () => { @@ -74,7 +94,6 @@ export default function InvokeTabs() { useHotkeys('3', () => { dispatch(setActiveTab(2)); - dispatch(setNeedsCache(true)); }); useHotkeys('4', () => { @@ -89,6 +108,30 @@ export default function InvokeTabs() { dispatch(setActiveTab(5)); }); + // Lightbox Hotkey + useHotkeys( + 'v', + () => { + dispatch(setIsLightBoxOpen(!isLightBoxOpen)); + }, + [isLightBoxOpen] + ); + + useHotkeys( + 'f', + () => { + if (shouldShowGallery || shouldShowOptionsPanel) { + dispatch(setShouldShowOptionsPanel(false)); + dispatch(setShouldShowGallery(false)); + } else { + dispatch(setShouldShowOptionsPanel(true)); + dispatch(setShouldShowGallery(true)); + } + setTimeout(() => dispatch(setDoesCanvasNeedScaling(true)), 400); + }, + [shouldShowGallery, shouldShowOptionsPanel] + ); + const renderTabs = () => { const tabsToRender: ReactElement[] = []; Object.keys(tabDict).forEach((key) => { @@ -127,11 +170,13 @@ export default function InvokeTabs() { index={activeTab} onChange={(index: number) => { dispatch(setActiveTab(index)); - dispatch(setNeedsCache(true)); + dispatch(setDoesCanvasNeedScaling(true)); }} >
{renderTabs()}
- {renderTabPanels()} + + {isLightBoxOpen ? : renderTabPanels()} + ); } diff --git a/frontend/src/features/tabs/InvokeWorkarea.scss b/frontend/src/features/tabs/InvokeWorkarea.scss index 38ccdc34f8..83df214a1c 100644 --- a/frontend/src/features/tabs/InvokeWorkarea.scss +++ b/frontend/src/features/tabs/InvokeWorkarea.scss @@ -22,6 +22,12 @@ grid-template-columns: 1fr 1fr; background-color: var(--background-color-secondary); border-radius: 0.5rem; + .workarea-split-view-left { + padding-right: 0.5rem; + } + .workarea-split-view-right { + padding-left: 0.5rem; + } } .workarea-single-view { @@ -42,12 +48,6 @@ border-radius: 0.5rem; padding: 1rem; } - .workarea-split-view-left { - padding-right: 0.5rem; - } - .workarea-split-view-right { - padding-left: 0.5rem; - } } } .workarea-split-button { @@ -56,7 +56,7 @@ padding: 0.5rem; top: 0; right: 0; - z-index: 20; + // z-index: 20; &[data-selected='true'] { top: 0; diff --git a/frontend/src/features/tabs/InvokeWorkarea.tsx b/frontend/src/features/tabs/InvokeWorkarea.tsx index d79f413720..96552a6eef 100644 --- a/frontend/src/features/tabs/InvokeWorkarea.tsx +++ b/frontend/src/features/tabs/InvokeWorkarea.tsx @@ -3,16 +3,26 @@ import { createSelector } from '@reduxjs/toolkit'; import { ReactNode } from 'react'; import { useHotkeys } from 'react-hotkeys-hook'; import { VscSplitHorizontal } from 'react-icons/vsc'; -import { RootState, useAppDispatch, useAppSelector } from '../../app/store'; -import ImageGallery from '../gallery/ImageGallery'; -import { activeTabNameSelector } from '../options/optionsSelectors'; -import { OptionsState, setShowDualDisplay } from '../options/optionsSlice'; +import { RootState, useAppDispatch, useAppSelector } from 'app/store'; +import ImageGallery from 'features/gallery/ImageGallery'; +import { activeTabNameSelector } from 'features/options/optionsSelectors'; +import { + OptionsState, + setShowDualDisplay, +} from 'features/options/optionsSlice'; +import { setDoesCanvasNeedScaling } from 'features/canvas/canvasSlice'; const workareaSelector = createSelector( [(state: RootState) => state.options, activeTabNameSelector], (options: OptionsState, activeTabName) => { - const { showDualDisplay, shouldPinOptionsPanel } = options; - return { showDualDisplay, shouldPinOptionsPanel, activeTabName }; + const { showDualDisplay, shouldPinOptionsPanel, isLightBoxOpen } = options; + return { + showDualDisplay, + shouldPinOptionsPanel, + activeTabName, + isLightBoxOpen, + shouldShowDualDisplayButton: ['inpainting'].includes(activeTabName), + }; } ); @@ -25,10 +35,16 @@ type InvokeWorkareaProps = { const InvokeWorkarea = (props: InvokeWorkareaProps) => { const dispatch = useAppDispatch(); const { optionsPanel, children, styleClass } = props; - const { showDualDisplay, activeTabName } = useAppSelector(workareaSelector); + const { + showDualDisplay, + activeTabName, + isLightBoxOpen, + shouldShowDualDisplayButton, + } = useAppSelector(workareaSelector); const handleDualDisplay = () => { dispatch(setShowDualDisplay(!showDualDisplay)); + dispatch(setDoesCanvasNeedScaling(true)); }; // Hotkeys @@ -39,7 +55,7 @@ const InvokeWorkarea = (props: InvokeWorkareaProps) => { handleDualDisplay(); }, { - enabled: activeTabName === 'inpainting', + enabled: shouldShowDualDisplayButton, }, [showDualDisplay] ); @@ -54,7 +70,7 @@ const InvokeWorkarea = (props: InvokeWorkareaProps) => { {optionsPanel}
{children} - {activeTabName === 'inpainting' && ( + {shouldShowDualDisplayButton && (
{ )}
- + {!isLightBoxOpen && }
); diff --git a/frontend/src/features/tabs/Outpainting/OutpaintingDisplay.tsx b/frontend/src/features/tabs/Outpainting/OutpaintingDisplay.tsx new file mode 100644 index 0000000000..2799e612c5 --- /dev/null +++ b/frontend/src/features/tabs/Outpainting/OutpaintingDisplay.tsx @@ -0,0 +1,74 @@ +import { createSelector } from '@reduxjs/toolkit'; +// import IAICanvas from 'features/canvas/IAICanvas'; +import IAICanvasControls from 'features/canvas/IAICanvasControls'; +import IAICanvasResizer from 'features/canvas/IAICanvasResizer'; +import _ from 'lodash'; +import { useLayoutEffect } from 'react'; +import { RootState, useAppDispatch, useAppSelector } from 'app/store'; +import ImageUploadButton from 'common/components/ImageUploaderButton'; +import CurrentImageDisplay from 'features/gallery/CurrentImageDisplay'; +import { OptionsState } from 'features/options/optionsSlice'; +import { + CanvasState, + currentCanvasSelector, + GenericCanvasState, + OutpaintingCanvasState, + setDoesCanvasNeedScaling, +} from 'features/canvas/canvasSlice'; +import IAICanvas from 'features/canvas/IAICanvas'; +import IAICanvasOutpaintingControls from 'features/canvas/IAICanvasOutpaintingControls'; + +const outpaintingDisplaySelector = createSelector( + [(state: RootState) => state.canvas, (state: RootState) => state.options], + (canvas: CanvasState, options: OptionsState) => { + const { + doesCanvasNeedScaling, + outpainting: { objects }, + } = canvas; + const { showDualDisplay } = options; + return { + doesCanvasNeedScaling, + showDualDisplay, + doesOutpaintingHaveObjects: objects.length > 0, + }; + }, + { + memoizeOptions: { + resultEqualityCheck: _.isEqual, + }, + } +); + +const OutpaintingDisplay = () => { + const dispatch = useAppDispatch(); + const { showDualDisplay, doesCanvasNeedScaling, doesOutpaintingHaveObjects } = + useAppSelector(outpaintingDisplaySelector); + + useLayoutEffect(() => { + const resizeCallback = _.debounce( + () => dispatch(setDoesCanvasNeedScaling(true)), + 250 + ); + window.addEventListener('resize', resizeCallback); + return () => window.removeEventListener('resize', resizeCallback); + }, [dispatch]); + + const outpaintingComponent = doesOutpaintingHaveObjects ? ( +
+ +
+ {doesCanvasNeedScaling ? : } +
+
+ ) : ( + + ); + + return ( +
+
{outpaintingComponent}
+
+ ); +}; + +export default OutpaintingDisplay; diff --git a/frontend/src/features/tabs/Outpainting/OutpaintingPanel.tsx b/frontend/src/features/tabs/Outpainting/OutpaintingPanel.tsx new file mode 100644 index 0000000000..5428a923f2 --- /dev/null +++ b/frontend/src/features/tabs/Outpainting/OutpaintingPanel.tsx @@ -0,0 +1,65 @@ +// import { Feature } from 'app/features'; +import { Feature } from 'app/features'; +import { RootState, useAppSelector } from 'app/store'; +import FaceRestoreHeader from 'features/options/AdvancedOptions/FaceRestore/FaceRestoreHeader'; +import FaceRestoreOptions from 'features/options/AdvancedOptions/FaceRestore/FaceRestoreOptions'; +import ImageToImageStrength from 'features/options/AdvancedOptions/ImageToImage/ImageToImageStrength'; +import InpaintingSettings from 'features/options/AdvancedOptions/Inpainting/InpaintingSettings'; +import SeedHeader from 'features/options/AdvancedOptions/Seed/SeedHeader'; +import SeedOptions from 'features/options/AdvancedOptions/Seed/SeedOptions'; +import UpscaleHeader from 'features/options/AdvancedOptions/Upscale/UpscaleHeader'; +import UpscaleOptions from 'features/options/AdvancedOptions/Upscale/UpscaleOptions'; +import VariationsHeader from 'features/options/AdvancedOptions/Variations/VariationsHeader'; +import VariationsOptions from 'features/options/AdvancedOptions/Variations/VariationsOptions'; +import MainAdvancedOptionsCheckbox from 'features/options/MainOptions/MainAdvancedOptionsCheckbox'; +import MainOptions from 'features/options/MainOptions/MainOptions'; +import OptionsAccordion from 'features/options/OptionsAccordion'; +import ProcessButtons from 'features/options/ProcessButtons/ProcessButtons'; +import PromptInput from 'features/options/PromptInput/PromptInput'; +import InvokeOptionsPanel from 'features/tabs/InvokeOptionsPanel'; + +export default function OutpaintingPanel() { + const showAdvancedOptions = useAppSelector( + (state: RootState) => state.options.showAdvancedOptions + ); + + const imageToImageAccordions = { + seed: { + header: , + feature: Feature.SEED, + options: , + }, + variations: { + header: , + feature: Feature.VARIATIONS, + options: , + }, + face_restore: { + header: , + feature: Feature.FACE_CORRECTION, + options: , + }, + upscale: { + header: , + feature: Feature.UPSCALE, + options: , + }, + }; + + return ( + + + + + + + + {showAdvancedOptions && ( + + )} + + ); +} diff --git a/frontend/src/features/tabs/Outpainting/OutpaintingWorkarea.scss b/frontend/src/features/tabs/Outpainting/OutpaintingWorkarea.scss new file mode 100644 index 0000000000..426db917d0 --- /dev/null +++ b/frontend/src/features/tabs/Outpainting/OutpaintingWorkarea.scss @@ -0,0 +1,98 @@ +@use '../../../styles/Mixins/' as *; + +.inpainting-main-area { + display: flex; + flex-direction: column; + align-items: center; + row-gap: 1rem; + width: 100%; + height: 100%; + + .inpainting-settings { + display: flex; + align-items: center; + column-gap: 0.5rem; + + svg { + transform: scale(0.9); + } + + .inpainting-buttons-group { + display: flex; + align-items: center; + column-gap: 0.5rem; + } + + .inpainting-button-dropdown { + display: flex; + flex-direction: column; + row-gap: 0.5rem; + } + + .inpainting-color-picker { + margin-left: 1rem !important; + } + + .inpainting-brush-options { + display: flex; + align-items: center; + column-gap: 1rem; + } + } + + .inpainting-canvas-area { + display: flex; + flex-direction: column; + align-items: center; + row-gap: 1rem; + width: 100%; + height: 100%; + } + + .inpainting-canvas-spiner { + display: flex; + align-items: center; + width: 100%; + height: 100%; + } + + .inpainting-canvas-container { + display: flex; + align-items: center; + justify-content: center; + height: 100%; + width: 100%; + border-radius: 0.5rem; + + .inpainting-canvas-wrapper { + position: relative; + } + + .inpainting-canvas-stage { + border-radius: 0.5rem; + canvas { + border-radius: 0.5rem; + } + } + } +} + +.inpainting-options-btn { + min-height: 2rem; +} + +.canvas-status-text { + position: absolute; + top: 0; + left: 0; + background-color: var(--background-color); + opacity: 0.5; + display: flex; + flex-direction: column; + font-size: 0.8rem; + padding: 0.25rem; + width: 12rem; + border-radius: 0.25rem; + margin: 0.25rem; + pointer-events: none; +} diff --git a/frontend/src/features/tabs/Outpainting/OutpaintingWorkarea.tsx b/frontend/src/features/tabs/Outpainting/OutpaintingWorkarea.tsx new file mode 100644 index 0000000000..692ba324ed --- /dev/null +++ b/frontend/src/features/tabs/Outpainting/OutpaintingWorkarea.tsx @@ -0,0 +1,22 @@ +import OutpaintingPanel from './OutpaintingPanel'; +import OutpaintingDisplay from './OutpaintingDisplay'; +import InvokeWorkarea from 'features/tabs/InvokeWorkarea'; +import { useAppDispatch } from 'app/store'; +import { useEffect } from 'react'; +import { setCurrentCanvas, setDoesCanvasNeedScaling } from 'features/canvas/canvasSlice'; + +export default function OutpaintingWorkarea() { + const dispatch = useAppDispatch(); + useEffect(() => { + dispatch(setCurrentCanvas('outpainting')); + dispatch(setDoesCanvasNeedScaling(true)); + }, [dispatch]); + return ( + } + styleClass="inpainting-workarea-overrides" + > + + + ); +} diff --git a/frontend/src/features/tabs/TextToImage/TextToImageDisplay.tsx b/frontend/src/features/tabs/TextToImage/TextToImageDisplay.tsx index 4ea9736f35..6b68f80665 100644 --- a/frontend/src/features/tabs/TextToImage/TextToImageDisplay.tsx +++ b/frontend/src/features/tabs/TextToImage/TextToImageDisplay.tsx @@ -1,4 +1,4 @@ -import CurrentImageDisplay from '../../gallery/CurrentImageDisplay'; +import CurrentImageDisplay from 'features/gallery/CurrentImageDisplay'; const TextToImageDisplay = () => { return ( diff --git a/frontend/src/features/tabs/TextToImage/TextToImagePanel.tsx b/frontend/src/features/tabs/TextToImage/TextToImagePanel.tsx index 58ed61525c..0792f71d52 100644 --- a/frontend/src/features/tabs/TextToImage/TextToImagePanel.tsx +++ b/frontend/src/features/tabs/TextToImage/TextToImagePanel.tsx @@ -1,21 +1,21 @@ -import { Feature } from '../../../app/features'; -import { RootState, useAppSelector } from '../../../app/store'; -import FaceRestoreHeader from '../../options/AdvancedOptions/FaceRestore/FaceRestoreHeader'; -import FaceRestoreOptions from '../../options/AdvancedOptions/FaceRestore/FaceRestoreOptions'; -import OutputHeader from '../../options/AdvancedOptions/Output/OutputHeader'; -import OutputOptions from '../../options/AdvancedOptions/Output/OutputOptions'; -import SeedHeader from '../../options/AdvancedOptions/Seed/SeedHeader'; -import SeedOptions from '../../options/AdvancedOptions/Seed/SeedOptions'; -import UpscaleHeader from '../../options/AdvancedOptions/Upscale/UpscaleHeader'; -import UpscaleOptions from '../../options/AdvancedOptions/Upscale/UpscaleOptions'; -import VariationsHeader from '../../options/AdvancedOptions/Variations/VariationsHeader'; -import VariationsOptions from '../../options/AdvancedOptions/Variations/VariationsOptions'; -import MainAdvancedOptionsCheckbox from '../../options/MainOptions/MainAdvancedOptionsCheckbox'; -import MainOptions from '../../options/MainOptions/MainOptions'; -import OptionsAccordion from '../../options/OptionsAccordion'; -import ProcessButtons from '../../options/ProcessButtons/ProcessButtons'; -import PromptInput from '../../options/PromptInput/PromptInput'; -import InvokeOptionsPanel from '../InvokeOptionsPanel'; +import { Feature } from 'app/features'; +import { RootState, useAppSelector } from 'app/store'; +import FaceRestoreHeader from 'features/options/AdvancedOptions/FaceRestore/FaceRestoreHeader'; +import FaceRestoreOptions from 'features/options/AdvancedOptions/FaceRestore/FaceRestoreOptions'; +import OutputHeader from 'features/options/AdvancedOptions/Output/OutputHeader'; +import OutputOptions from 'features/options/AdvancedOptions/Output/OutputOptions'; +import SeedHeader from 'features/options/AdvancedOptions/Seed/SeedHeader'; +import SeedOptions from 'features/options/AdvancedOptions/Seed/SeedOptions'; +import UpscaleHeader from 'features/options/AdvancedOptions/Upscale/UpscaleHeader'; +import UpscaleOptions from 'features/options/AdvancedOptions/Upscale/UpscaleOptions'; +import VariationsHeader from 'features/options/AdvancedOptions/Variations/VariationsHeader'; +import VariationsOptions from 'features/options/AdvancedOptions/Variations/VariationsOptions'; +import MainAdvancedOptionsCheckbox from 'features/options/MainOptions/MainAdvancedOptionsCheckbox'; +import MainOptions from 'features/options/MainOptions/MainOptions'; +import OptionsAccordion from 'features/options/OptionsAccordion'; +import ProcessButtons from 'features/options/ProcessButtons/ProcessButtons'; +import PromptInput from 'features/options/PromptInput/PromptInput'; +import InvokeOptionsPanel from 'features/tabs/InvokeOptionsPanel'; export default function TextToImagePanel() { const showAdvancedOptions = useAppSelector( diff --git a/frontend/src/features/tabs/TextToImage/index.tsx b/frontend/src/features/tabs/TextToImage/index.tsx index 7aaceca833..5f88215e56 100644 --- a/frontend/src/features/tabs/TextToImage/index.tsx +++ b/frontend/src/features/tabs/TextToImage/index.tsx @@ -1,5 +1,5 @@ import TextToImagePanel from './TextToImagePanel'; -import InvokeWorkarea from '../InvokeWorkarea'; +import InvokeWorkarea from 'features/tabs/InvokeWorkarea'; import TextToImageDisplay from './TextToImageDisplay'; export default function TextToImageWorkarea() { diff --git a/frontend/src/global.d.ts b/frontend/src/global.d.ts new file mode 100644 index 0000000000..a0b48d49bb --- /dev/null +++ b/frontend/src/global.d.ts @@ -0,0 +1,39 @@ +export {}; + +declare global { + // Manual implementation of https://github.com/microsoft/TypeScript/issues/48829 + + interface Array { + /** + * Returns the value of the last element in the array where predicate is true, and undefined + * otherwise. + * @param predicate findLast calls predicate once for each element of the array, in descending + * order, until it finds one where predicate returns true. If such an element is found, findLast + * immediately returns that element value. Otherwise, findLast returns undefined. + * @param thisArg If provided, it will be used as the this value for each invocation of + * predicate. If it is not provided, undefined is used instead. + */ + findLast( + predicate: (this: void, value: T, index: number, obj: T[]) => value is S, + thisArg?: any + ): S | undefined; + findLast( + predicate: (value: T, index: number, obj: T[]) => unknown, + thisArg?: any + ): T | undefined; + + /** + * Returns the index of the last element in the array where predicate is true, and -1 + * otherwise. + * @param predicate findLastIndex calls predicate once for each element of the array, in descending + * order, until it finds one where predicate returns true. If such an element is found, + * findLastIndex immediately returns that element index. Otherwise, findLastIndex returns -1. + * @param thisArg If provided, it will be used as the this value for each invocation of + * predicate. If it is not provided, undefined is used instead. + */ + findLastIndex( + predicate: (value: T, index: number, obj: T[]) => unknown, + thisArg?: any + ): number; + } +} diff --git a/frontend/src/main.tsx b/frontend/src/main.tsx index 2036ed99bc..18ab6a62e2 100644 --- a/frontend/src/main.tsx +++ b/frontend/src/main.tsx @@ -1,6 +1,8 @@ import React from 'react'; import ReactDOM from 'react-dom/client'; -import { ChakraProvider, ColorModeScript } from '@chakra-ui/react'; +import { ChakraProvider } from '@chakra-ui/react'; +import { CacheProvider } from '@emotion/react'; +import createCache from '@emotion/cache'; import { store } from './app/store'; import { Provider } from 'react-redux'; import { PersistGate } from 'redux-persist/integration/react'; @@ -8,10 +10,14 @@ import { persistStore } from 'redux-persist'; export const persistor = persistStore(store); -import { theme } from './app/theme'; import Loading from './Loading'; import App from './app/App'; +const emotionCache = createCache({ + key: 'invokeai-style-cache', + prepend: true, +}); + // Custom Styling import './styles/index.scss'; @@ -19,10 +25,11 @@ ReactDOM.createRoot(document.getElementById('root') as HTMLElement).render( } persistor={persistor}> - - - - + + + + + diff --git a/frontend/src/styles/Mixins/Buttons.scss b/frontend/src/styles/Mixins/Buttons.scss index 511937d0af..f60bf8a3ac 100644 --- a/frontend/src/styles/Mixins/Buttons.scss +++ b/frontend/src/styles/Mixins/Buttons.scss @@ -1,6 +1,6 @@ @mixin Button( - $btn-color: rgb(45, 45, 55), - $btn-color-hover: rgb(65, 65, 75), + $btn-color: rgb(45, 49, 53), + $btn-color-hover: rgb(65, 69, 73), $btn-width: 100%, $btn-height: 100%, $icon-size: 20px @@ -10,13 +10,13 @@ background-color: $btn-color !important; &:hover { - background-color: $btn-color-hover !important; + background-color: $btn-color-hover; } &:disabled { - background-color: rgb(45, 45, 55) !important; + background-color: rgb(45, 49, 53) !important; &:hover { - background-color: rgb(45, 45, 55) !important; + background-color: rgb(45, 49, 53) !important; } } @@ -26,3 +26,15 @@ color: var(--btn-svg-color); } } + +@mixin BaseButton { + background-color: var(--btn-base-color); + &:hover { + background-color: var(--btn-base-color-hover); + } + &:disabled { + &:hover { + background-color: var(--btn-base-color); + } + } +} diff --git a/frontend/src/styles/_Colors_Dark.scss b/frontend/src/styles/Themes/_Colors_Dark.scss similarity index 77% rename from frontend/src/styles/_Colors_Dark.scss rename to frontend/src/styles/Themes/_Colors_Dark.scss index fdecb027bb..c3d673d053 100644 --- a/frontend/src/styles/_Colors_Dark.scss +++ b/frontend/src/styles/Themes/_Colors_Dark.scss @@ -2,27 +2,31 @@ // General Colors --white: rgb(255, 255, 255); + // Accent Colors + --accent-color-dim: rgb(57, 25, 153); + --accent-color: rgb(80, 40, 200); + --accent-color-bright: rgb(104, 60, 230); + --accent-color-hover: var(--accent-color-bright); + // App Colors --root-bg-color: rgb(10, 10, 10); --background-color: rgb(20, 20, 26); + --background-color-light: rgb(40, 44, 48); --background-color-secondary: rgb(16, 16, 22); --text-color: rgb(255, 255, 255); --text-color-secondary: rgb(160, 162, 188); - --subtext-color: rgb(24, 24, 34); --subtext-color-bright: rgb(48, 48, 64); --border-color: rgb(30, 30, 46); --border-color-light: rgb(60, 60, 76); + --svg-color: rgb(255, 255, 255); + --invalid: rgb(255, 75, 75); --invalid-secondary: rgb(120, 5, 5); - --accent-color-dim: rgb(57, 25, 153); - --accent-color: rgb(80, 40, 200); - --accent-color-hover: rgb(104, 60, 230); - --destructive-color: rgb(185, 55, 55); --destructive-color-hover: rgb(255, 75, 75); @@ -33,42 +37,45 @@ --border-color-invalid: rgb(255, 80, 50); --box-shadow-color-invalid: rgb(210, 30, 10); - --svg-color: rgb(24, 24, 34); - - // Progress Bar Color - --progress-bar-color: rgb(100, 50, 245); - - // Prompt Box Colors - --prompt-bg-color: rgb(10, 10, 10); + // Tabs + --tab-color: rgb(30, 32, 42); + --tab-hover-color: rgb(36, 38, 48); + --tab-panel-bg: rgb(20, 22, 28); + --tab-list-bg: var(--accent-color); + --tab-list-text: rgb(202, 204, 216); + --tab-list-text-inactive: rgb(92, 94, 114); // Button Colors - --btn-svg-color: rgb(255, 255, 255); - - --btn-grey: rgb(30, 32, 42); - --btn-grey-hover: rgb(46, 48, 68); + --btn-base-color: rgb(30, 32, 42); + --btn-base-color-hover: rgb(46, 48, 68); --btn-load-more: rgb(30, 32, 42); --btn-load-more-hover: rgb(54, 56, 66); + --btn-svg-color: rgb(255, 255, 255); --btn-delete-image: rgb(238, 107, 107); // IAI Button Colors --btn-checkbox-border-hover: rgb(46, 48, 68); + // Progress Bar Color + --progress-bar-color: var(--accent-color); + + // Prompt Box Colors + --prompt-bg-color: rgb(10, 10, 10); + // Switch --switch-bg-color: rgb(100, 102, 110); - --switch-bg-active-color: rgb(80, 40, 200); + --switch-bg-active-color: var(--accent-color); + + // Slider + --slider-color: var(--accent-color-bright); + + // Slider + --slider-color: rgb(151, 113, 255); // Resizable - --resizeable-handle-border-color: rgb(80, 82, 112); - - // Tabs - --tab-color: rgb(30, 32, 42); - --tab-hover-color: rgb(36, 38, 48); - --tab-list-bg: var(--accent-color); - --tab-list-text: rgb(202, 204, 216); - --tab-list-text-inactive: rgb(92, 94, 114); - --tab-panel-bg: rgb(20, 22, 28); + --resizeable-handle-border-color: var(--accent-color); // Metadata Viewer --metadata-bg-color: rgba(0, 0, 0, 0.7); @@ -86,11 +93,12 @@ --settings-modal-bg: rgb(30, 32, 42); // Input - --input-checkbox-bg: rgb(90, 90, 120); - --input-checkbox-checked-bg: rgb(80, 40, 200); + --input-checkbox-bg: rgb(60, 64, 68); + --input-checkbox-checked-bg: var(--accent-color); --input-checkbox-checked-tick: rgb(0, 0, 0); - --input-border-color: rgb(140, 110, 255); - --input-box-shadow-color: rgb(80, 30, 210); + + --input-border-color: var(--accent-color-bright); + --input-box-shadow-color: var(--accent-color); // Console --error-level-info: rgb(200, 202, 224); @@ -116,8 +124,11 @@ // Canvas --inpainting-alerts-bg: rgba(20, 20, 26, 0.75); --inpainting-alerts-icon-color: rgb(255, 255, 255); - --inpainting-alerts-bg-active: rgb(80, 40, 200); + --inpainting-alerts-bg-active: var(--accent-color); --inpainting-alerts-icon-active: rgb(255, 255, 255); --inpainting-alerts-bg-alert: var(--invalid); --inpainting-alerts-icon-alert: rgb(255, 255, 255); + + // Checkerboard + --checkboard-dots-color: rgb(35, 35, 39); } diff --git a/frontend/src/styles/Themes/_Colors_Green.scss b/frontend/src/styles/Themes/_Colors_Green.scss new file mode 100644 index 0000000000..a6e2110404 --- /dev/null +++ b/frontend/src/styles/Themes/_Colors_Green.scss @@ -0,0 +1,132 @@ +[data-theme='green'] { + // General Colors + --white: rgb(255, 255, 255); + + // Accent Colors + --accent-color-dim: rgb(10, 60, 40); + --accent-color: rgb(20, 110, 70); + --accent-color-bright: rgb(30, 180, 100); + --accent-color-hover: var(--accent-color-bright); + + // App Colors + --root-bg-color: rgb(10, 10, 14); + --background-color: rgb(30, 32, 37); + --background-color-light: rgb(40, 44, 48); + --background-color-secondary: rgb(22, 24, 28); + + --text-color: rgb(255, 255, 255); + --text-color-secondary: rgb(160, 164, 168); + --subtext-color: rgb(24, 24, 28); + --subtext-color-bright: rgb(68, 72, 76); + + --border-color: rgb(40, 44, 48); + --border-color-light: rgb(60, 60, 64); + + --svg-color: rgb(220, 224, 228); + + --invalid: rgb(255, 75, 75); + --invalid-secondary: rgb(120, 5, 5); + + --destructive-color: rgb(185, 55, 55); + --destructive-color-hover: rgb(255, 75, 75); + + --warning-color: rgb(200, 88, 40); + --warning-color-hover: rgb(230, 117, 60); + + // Error status colors + --border-color-invalid: rgb(255, 80, 50); + --box-shadow-color-invalid: rgb(210, 30, 10); + + // Tabs + --tab-color: rgb(40, 44, 48); + --tab-hover-color: rgb(48, 52, 56); //done + --tab-panel-bg: var(--background-color-secondary); + --tab-list-bg: var(--accent-color); + --tab-list-text: rgb(202, 204, 206); + --tab-list-text-inactive: rgb(92, 94, 96); //done + + // Button Colors + --btn-base-color: rgb(40, 44, 48); + --btn-base-color-hover: rgb(56, 60, 64); + + --btn-load-more: rgb(30, 32, 42); + --btn-load-more-hover: rgb(54, 56, 66); + + --btn-svg-color: rgb(255, 255, 255); + + --btn-delete-image: rgb(238, 107, 107); + + // IAI Button Colors + --btn-checkbox-border-hover: rgb(46, 48, 68); + + // Progress Bar Color + --progress-bar-color: var(--accent-color); + + // Prompt Box Colors + --prompt-bg-color: rgb(10, 10, 14); + + // Switch + --switch-bg-color: rgb(100, 102, 110); + --switch-bg-active-color: var(--accent-color); + + // Slider + --slider-color: var(--accent-color-bright); + + // Resizable + --resizeable-handle-border-color: var(--accent-color); + + // Metadata Viewer + --metadata-bg-color: rgba(0, 0, 0, 0.7); + --metadata-json-bg-color: rgba(255, 255, 255, 0.1); + + // Status Message + --status-good-color: rgb(125, 255, 100); + --status-good-glow: rgb(40, 215, 40); + --status-working-color: rgb(255, 175, 55); + --status-working-glow: rgb(255, 160, 55); + --status-bad-color: rgb(255, 90, 90); + --status-bad-glow: rgb(255, 40, 40); + + // Settings Modal + --settings-modal-bg: rgb(30, 32, 42); + + // Input + --input-checkbox-bg: rgb(60, 64, 68); + --input-checkbox-checked-bg: var(--accent-color); + --input-checkbox-checked-tick: rgb(0, 0, 0); + + --input-border-color: var(--accent-color-bright); + --input-box-shadow-color: var(--accent-color); + + // Console + --error-level-info: rgb(200, 202, 224); + --error-level-warning: rgb(255, 225, 105); + --error-level-error: rgb(255, 81, 46); + --console-bg-color: rgb(30, 30, 36); + --console-icon-button-bg-color: rgb(50, 53, 64); + --console-icon-button-bg-color-hover: rgb(70, 73, 84); + + // Img2Img + --img2img-img-bg-color: rgb(30, 32, 42); + + // Gallery + + // Context Menus + --context-menu-bg-color: rgb(46, 48, 58); + --context-menu-box-shadow: none; + --context-menu-bg-color-hover: rgb(30, 32, 42); + + // Shadows + --floating-button-drop-shadow: drop-shadow(0 0 1rem rgba(140, 101, 255, 0.5)); + + // Canvas + --inpainting-alerts-bg: rgba(20, 20, 26, 0.75); + --inpainting-alerts-icon-color: rgb(255, 255, 255); + --inpainting-alerts-bg-active: var(--accent-color); + --inpainting-alerts-icon-active: rgb(255, 255, 255); + --inpainting-alerts-bg-alert: var(--invalid); + --inpainting-alerts-icon-alert: rgb(255, 255, 255); + + //Checkerboard + --checkboard-dots-color: rgb(35, 35, 39); +} diff --git a/frontend/src/styles/_Colors_Light.scss b/frontend/src/styles/Themes/_Colors_Light.scss similarity index 89% rename from frontend/src/styles/_Colors_Light.scss rename to frontend/src/styles/Themes/_Colors_Light.scss index f46513a297..5138704c79 100644 --- a/frontend/src/styles/_Colors_Light.scss +++ b/frontend/src/styles/Themes/_Colors_Light.scss @@ -2,27 +2,31 @@ // General Colors --white: rgb(255, 255, 255); + // Accent Colors + --accent-color-dim: rgb(186, 146, 0); + --accent-color: rgb(235, 185, 5); + --accent-color-bright: rgb(255, 200, 0); + --accent-color-hover: var(--accent-color-bright); + // App Colors --root-bg-color: rgb(255, 255, 255); --background-color: rgb(220, 222, 224); + --background-color-light: rgb(250, 252, 254); --background-color-secondary: rgb(204, 206, 208); --text-color: rgb(0, 0, 0); --text-color-secondary: rgb(40, 40, 40); - --subtext-color: rgb(24, 24, 34); --subtext-color-bright: rgb(142, 144, 146); --border-color: rgb(200, 200, 200); --border-color-light: rgb(147, 147, 147); + --svg-color: rgb(50, 50, 50); + --invalid: rgb(255, 75, 75); --invalid-secondary: rgb(120, 5, 5); - --accent-color-dim: rgb(186, 146, 0); - --accent-color: rgb(235, 185, 5); - --accent-color-hover: rgb(255, 200, 0); - --destructive-color: rgb(237, 51, 51); --destructive-color-hover: rgb(255, 55, 55); @@ -33,43 +37,41 @@ --border-color-invalid: rgb(255, 80, 50); --box-shadow-color-invalid: none; - --svg-color: rgb(186, 188, 190); - - // Progress Bar Color - --progress-bar-color: rgb(235, 185, 5); - - // Prompt Box Colors - --prompt-bg-color: rgb(225, 227, 229); + // Tabs + --tab-color: rgb(202, 204, 206); + --tab-hover-color: rgb(206, 208, 210); + --tab-panel-bg: rgb(214, 216, 218); + --tab-list-bg: rgb(235, 185, 5); + --tab-list-text: rgb(0, 0, 0); + --tab-list-text-inactive: rgb(106, 108, 110); // Button Colors - --btn-svg-color: rgb(0, 0, 0); - - --btn-grey: rgb(220, 222, 224); - --btn-grey-hover: rgb(230, 232, 234); + --btn-base-color: rgb(184, 186, 188); + --btn-base-color-hover: rgb(230, 232, 234); --btn-load-more: rgb(202, 204, 206); --btn-load-more-hover: rgb(178, 180, 182); + --btn-svg-color: rgb(0, 0, 0); --btn-delete-image: rgb(213, 49, 49); // IAI Button Colors --btn-checkbox-border-hover: rgb(176, 178, 182); + // Progress Bar Color + --progress-bar-color: rgb(235, 185, 5); + // Prompt Box Colors + --prompt-bg-color: rgb(225, 227, 229); // Switch --switch-bg-color: rgb(178, 180, 182); --switch-bg-active-color: rgb(235, 185, 5); + // Slider + --slider-color: rgb(0, 0, 0); + // Resizable --resizeable-handle-border-color: rgb(160, 162, 164); - // Tabs - --tab-color: rgb(202, 204, 206); - --tab-hover-color: rgb(206, 208, 210); - --tab-list-bg: rgb(235, 185, 5); - --tab-list-text: rgb(0, 0, 0); - --tab-list-text-inactive: rgb(106, 108, 110); - --tab-panel-bg: rgb(214, 216, 218); - // Metadata Viewer --metadata-bg-color: rgba(230, 230, 230, 0.9); --metadata-json-bg-color: rgba(0, 0, 0, 0.1); @@ -121,4 +123,7 @@ --inpainting-alerts-icon-active: rgb(0, 0, 0); --inpainting-alerts-bg-alert: var(--invalid); --inpainting-alerts-icon-alert: rgb(0, 0, 0); + + // Checkerboard + --checkboard-dots-color: rgb(160, 160, 172); } diff --git a/frontend/src/styles/_Misc.scss b/frontend/src/styles/_Misc.scss index d75046d008..4c09d8d73c 100644 --- a/frontend/src/styles/_Misc.scss +++ b/frontend/src/styles/_Misc.scss @@ -1,13 +1,16 @@ -.checkerboard { - background-position: 0px 0px, 10px 10px; - background-size: 20px 20px; - background-image: linear-gradient( - 45deg, - #eee 25%, - transparent 25%, - transparent 75%, - #eee 75%, - #eee 100% - ), - linear-gradient(45deg, #eee 25%, white 25%, white 75%, #eee 75%, #eee 100%); -} +// .checkerboard { +// background-position: 0px 0px, 10px 10px; +// // background-size: 20px 20px; +// // background-image: linear-gradient( +// // 45deg, +// // #eee 25%, +// // transparent 25%, +// // transparent 75%, +// // #eee 75%, +// // #eee 100% +// // ), +// // linear-gradient(45deg, #eee 25%, white 25%, white 75%, #eee 75%, #eee 100%); +// background: radial-gradient(var(--checkboard-dots-color) 3px, transparent 1px), +// var(--background-color-secondary); +// background-size: 64px 64px; +// } diff --git a/frontend/src/styles/index.scss b/frontend/src/styles/index.scss index de0f57020d..eacc765901 100644 --- a/frontend/src/styles/index.scss +++ b/frontend/src/styles/index.scss @@ -1,10 +1,13 @@ // General Imports -@use 'Colors_Dark'; -@use 'Colors_Light'; @use 'Fonts'; @use 'Animations'; @use 'Misc'; +// Themes +@use './Themes/Colors_Dark'; +@use './Themes/Colors_Light'; +@use './Themes/Colors_Green'; + // Component Styles //app @use '../app/App.scss'; @@ -33,6 +36,9 @@ @use '../features/gallery/HoverableImage.scss'; @use '../features/gallery/ImageMetaDataViewer/ImageMetadataViewer.scss'; +// Lightbox +@use '../features/lightbox//Lightbox.scss'; + // Tabs @use '../features/tabs/InvokeTabs.scss'; @use '../features/tabs/InvokeWorkarea.scss'; @@ -40,8 +46,8 @@ @use '../features/tabs/TextToImage/TextToImage.scss'; @use '../features/tabs/ImageToImage/ImageToImage.scss'; @use '../features/tabs/FloatingButton.scss'; -@use '../features/tabs/Inpainting/Inpainting.scss'; -@use '../features/tabs/Inpainting/InpaintingCanvasStatusIcons.scss'; +@use '../features/tabs/Inpainting/InpaintingWorkarea.scss'; +@use '../features/tabs/Outpainting/OutpaintingWorkarea.scss'; // Component Shared @use '../common/components/IAINumberInput.scss'; @@ -59,11 +65,12 @@ @use '../common/components/GuidePopover.scss'; // Component Shared - Radix UI -// @use '../common/components/radix-ui/IAISlider.scss'; -// @use '../common/components/radix-ui/IAITooltip.scss'; +// @use 'common/components/radix-ui/IAISlider.scss'; +// @use 'common/components/radix-ui/IAITooltip.scss'; // Shared Styles @use './Mixins/' as *; +@use '../features/system/Modal.scss'; *, *::before, diff --git a/frontend/tsconfig.json b/frontend/tsconfig.json index a9619a8f91..2a75e16e88 100644 --- a/frontend/tsconfig.json +++ b/frontend/tsconfig.json @@ -14,6 +14,7 @@ "resolveJsonModule": true, "isolatedModules": true, "noEmit": true, + "baseUrl": "src", "jsx": "react-jsx" }, "include": ["src", "index.d.ts"], diff --git a/frontend/tsconfig.node.json b/frontend/tsconfig.node.json index 9d31e2aed9..a375708f74 100644 --- a/frontend/tsconfig.node.json +++ b/frontend/tsconfig.node.json @@ -3,7 +3,8 @@ "composite": true, "module": "ESNext", "moduleResolution": "Node", - "allowSyntheticDefaultImports": true + "allowSyntheticDefaultImports": true, + "baseUrl": "src" }, "include": ["vite.config.ts"] } diff --git a/frontend/vite.config.ts b/frontend/vite.config.ts index d8a8dcca62..548ba17314 100644 --- a/frontend/vite.config.ts +++ b/frontend/vite.config.ts @@ -1,12 +1,13 @@ import { defineConfig } from 'vite'; import react from '@vitejs/plugin-react'; import eslint from 'vite-plugin-eslint'; +import tsconfigPaths from 'vite-tsconfig-paths'; // https://vitejs.dev/config/ export default defineConfig(({ mode }) => { const common = { base: '', - plugins: [react(), eslint()], + plugins: [react(), eslint(), tsconfigPaths()], server: { // Proxy HTTP requests to the flask server proxy: { @@ -15,6 +16,11 @@ export default defineConfig(({ mode }) => { changeOrigin: true, rewrite: (path) => path.replace(/^\/outputs/, ''), }, + '/upload': { + target: 'http://127.0.0.1:9090/upload', + changeOrigin: true, + rewrite: (path) => path.replace(/^\/upload/, ''), + }, '/flaskwebgui-keep-server-alive': { target: 'http://127.0.0.1:9090/flaskwebgui-keep-server-alive', changeOrigin: true, diff --git a/frontend/yarn.lock b/frontend/yarn.lock index dae528a306..c62800507e 100644 --- a/frontend/yarn.lock +++ b/frontend/yarn.lock @@ -4,7 +4,7 @@ "@ampproject/remapping@^2.1.0": version "2.2.0" - resolved "https://registry.npmjs.org/@ampproject/remapping/-/remapping-2.2.0.tgz" + resolved "https://registry.yarnpkg.com/@ampproject/remapping/-/remapping-2.2.0.tgz#56c133824780de3174aed5ab6834f3026790154d" integrity sha512-qRmjj8nj9qmLTQXXmaR1cck3UXSRMPrbsLJAasZpF+t3riI71BXed5ebIOYwQntykeZuhjsdweEc9BxH5Jc26w== dependencies: "@jridgewell/gen-mapping" "^0.1.0" @@ -12,54 +12,54 @@ "@babel/code-frame@^7.0.0", "@babel/code-frame@^7.18.6": version "7.18.6" - resolved "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.18.6.tgz" + resolved "https://registry.yarnpkg.com/@babel/code-frame/-/code-frame-7.18.6.tgz#3b25d38c89600baa2dcc219edfa88a74eb2c427a" integrity sha512-TDCmlK5eOvH+eH7cdAFlNXeVJqWIQ7gW9tY1GJIpUtFb6CmjVyq2VM3u71bOyR8CRihcCgMUYoDNyLXao3+70Q== dependencies: "@babel/highlight" "^7.18.6" "@babel/compat-data@^7.20.0": - version "7.20.0" - resolved "https://registry.yarnpkg.com/@babel/compat-data/-/compat-data-7.20.0.tgz#9b61938c5f688212c7b9ae363a819df7d29d4093" - integrity sha512-Gt9jszFJYq7qzXVK4slhc6NzJXnOVmRECWcVjF/T23rNXD9NtWQ0W3qxdg+p9wWIB+VQw3GYV/U2Ha9bRTfs4w== + version "7.20.1" + resolved "https://registry.yarnpkg.com/@babel/compat-data/-/compat-data-7.20.1.tgz#f2e6ef7790d8c8dbf03d379502dcc246dcce0b30" + integrity sha512-EWZ4mE2diW3QALKvDMiXnbZpRvlj+nayZ112nK93SnhqOtpdsbVD4W+2tEoT3YNBAG9RBR0ISY758ZkOgsn6pQ== "@babel/core@^7.19.6": - version "7.19.6" - resolved "https://registry.yarnpkg.com/@babel/core/-/core-7.19.6.tgz#7122ae4f5c5a37c0946c066149abd8e75f81540f" - integrity sha512-D2Ue4KHpc6Ys2+AxpIx1BZ8+UegLLLE2p3KJEuJRKmokHOtl49jQ5ny1773KsGLZs8MQvBidAF6yWUJxRqtKtg== + version "7.20.2" + resolved "https://registry.yarnpkg.com/@babel/core/-/core-7.20.2.tgz#8dc9b1620a673f92d3624bd926dc49a52cf25b92" + integrity sha512-w7DbG8DtMrJcFOi4VrLm+8QM4az8Mo+PuLBKLp2zrYRCow8W/f9xiXm5sN53C8HksCyDQwCKha9JiDoIyPjT2g== dependencies: "@ampproject/remapping" "^2.1.0" "@babel/code-frame" "^7.18.6" - "@babel/generator" "^7.19.6" - "@babel/helper-compilation-targets" "^7.19.3" - "@babel/helper-module-transforms" "^7.19.6" - "@babel/helpers" "^7.19.4" - "@babel/parser" "^7.19.6" + "@babel/generator" "^7.20.2" + "@babel/helper-compilation-targets" "^7.20.0" + "@babel/helper-module-transforms" "^7.20.2" + "@babel/helpers" "^7.20.1" + "@babel/parser" "^7.20.2" "@babel/template" "^7.18.10" - "@babel/traverse" "^7.19.6" - "@babel/types" "^7.19.4" + "@babel/traverse" "^7.20.1" + "@babel/types" "^7.20.2" convert-source-map "^1.7.0" debug "^4.1.0" gensync "^1.0.0-beta.2" json5 "^2.2.1" semver "^6.3.0" -"@babel/generator@^7.19.6", "@babel/generator@^7.20.0": - version "7.20.0" - resolved "https://registry.yarnpkg.com/@babel/generator/-/generator-7.20.0.tgz#0bfc5379e0efb05ca6092091261fcdf7ec36249d" - integrity sha512-GUPcXxWibClgmYJuIwC2Bc2Lg+8b9VjaJ+HlNdACEVt+Wlr1eoU1OPZjZRm7Hzl0gaTsUZNQfeihvZJhG7oc3w== +"@babel/generator@^7.20.1", "@babel/generator@^7.20.2": + version "7.20.2" + resolved "https://registry.yarnpkg.com/@babel/generator/-/generator-7.20.2.tgz#c2e89e22613a039285c1e7b749e2cd0b30b9a481" + integrity sha512-SD75PMIK6i9H8G/tfGvB4KKl4Nw6Ssos9nGgYwxbgyTP0iX/Z55DveoH86rmUB/YHTQQ+ZC0F7xxaY8l2OF44Q== dependencies: - "@babel/types" "^7.20.0" + "@babel/types" "^7.20.2" "@jridgewell/gen-mapping" "^0.3.2" jsesc "^2.5.1" "@babel/helper-annotate-as-pure@^7.18.6": version "7.18.6" - resolved "https://registry.npmjs.org/@babel/helper-annotate-as-pure/-/helper-annotate-as-pure-7.18.6.tgz" + resolved "https://registry.yarnpkg.com/@babel/helper-annotate-as-pure/-/helper-annotate-as-pure-7.18.6.tgz#eaa49f6f80d5a33f9a5dd2276e6d6e451be0a6bb" integrity sha512-duORpUiYrEpzKIop6iNbjnwKLAKnJ47csTyRACyEmWj0QdUrm5aqNJGHSSEQSUAvNW0ojX0dOmK9dZduvkfeXA== dependencies: "@babel/types" "^7.18.6" -"@babel/helper-compilation-targets@^7.19.3": +"@babel/helper-compilation-targets@^7.20.0": version "7.20.0" resolved "https://registry.yarnpkg.com/@babel/helper-compilation-targets/-/helper-compilation-targets-7.20.0.tgz#6bf5374d424e1b3922822f1d9bdaa43b1a139d0a" integrity sha512-0jp//vDGp9e8hZzBc6N/KwA5ZK3Wsm/pfm4CrY7vzegkVxc65SgSn6wYOnwHe9Js9HRQ1YTCKLGPzDtaS3RoLQ== @@ -71,12 +71,12 @@ "@babel/helper-environment-visitor@^7.18.9": version "7.18.9" - resolved "https://registry.npmjs.org/@babel/helper-environment-visitor/-/helper-environment-visitor-7.18.9.tgz" + resolved "https://registry.yarnpkg.com/@babel/helper-environment-visitor/-/helper-environment-visitor-7.18.9.tgz#0c0cee9b35d2ca190478756865bb3528422f51be" integrity sha512-3r/aACDJ3fhQ/EVgFy0hpj8oHyHpQc+LPtJoY9SzTThAsStm4Ptegq92vqKoE3vD706ZVFWITnMnxucw+S9Ipg== "@babel/helper-function-name@^7.19.0": version "7.19.0" - resolved "https://registry.npmjs.org/@babel/helper-function-name/-/helper-function-name-7.19.0.tgz" + resolved "https://registry.yarnpkg.com/@babel/helper-function-name/-/helper-function-name-7.19.0.tgz#941574ed5390682e872e52d3f38ce9d1bef4648c" integrity sha512-WAwHBINyrpqywkUH0nTnNgI5ina5TFn85HKS0pbPDfxFfhyR/aNQEn4hGi1P1JyT//I0t4OgXUlofzWILRvS5w== dependencies: "@babel/template" "^7.18.10" @@ -84,47 +84,47 @@ "@babel/helper-hoist-variables@^7.18.6": version "7.18.6" - resolved "https://registry.npmjs.org/@babel/helper-hoist-variables/-/helper-hoist-variables-7.18.6.tgz" + resolved "https://registry.yarnpkg.com/@babel/helper-hoist-variables/-/helper-hoist-variables-7.18.6.tgz#d4d2c8fb4baeaa5c68b99cc8245c56554f926678" integrity sha512-UlJQPkFqFULIcyW5sbzgbkxn2FKRgwWiRexcuaR8RNJRy8+LLveqPjwZV/bwrLZCN0eUHD/x8D0heK1ozuoo6Q== dependencies: "@babel/types" "^7.18.6" "@babel/helper-module-imports@^7.16.7", "@babel/helper-module-imports@^7.18.6": version "7.18.6" - resolved "https://registry.npmjs.org/@babel/helper-module-imports/-/helper-module-imports-7.18.6.tgz" + resolved "https://registry.yarnpkg.com/@babel/helper-module-imports/-/helper-module-imports-7.18.6.tgz#1e3ebdbbd08aad1437b428c50204db13c5a3ca6e" integrity sha512-0NFvs3VkuSYbFi1x2Vd6tKrywq+z/cLeYC/RJNFrIX/30Bf5aiGYbtvGXolEktzJH8o5E5KJ3tT+nkxuuZFVlA== dependencies: "@babel/types" "^7.18.6" -"@babel/helper-module-transforms@^7.19.6": - version "7.19.6" - resolved "https://registry.yarnpkg.com/@babel/helper-module-transforms/-/helper-module-transforms-7.19.6.tgz#6c52cc3ac63b70952d33ee987cbee1c9368b533f" - integrity sha512-fCmcfQo/KYr/VXXDIyd3CBGZ6AFhPFy1TfSEJ+PilGVlQT6jcbqtHAM4C1EciRqMza7/TpOUZliuSH+U6HAhJw== +"@babel/helper-module-transforms@^7.20.2": + version "7.20.2" + resolved "https://registry.yarnpkg.com/@babel/helper-module-transforms/-/helper-module-transforms-7.20.2.tgz#ac53da669501edd37e658602a21ba14c08748712" + integrity sha512-zvBKyJXRbmK07XhMuujYoJ48B5yvvmM6+wcpv6Ivj4Yg6qO7NOZOSnvZN9CRl1zz1Z4cKf8YejmCMh8clOoOeA== dependencies: "@babel/helper-environment-visitor" "^7.18.9" "@babel/helper-module-imports" "^7.18.6" - "@babel/helper-simple-access" "^7.19.4" + "@babel/helper-simple-access" "^7.20.2" "@babel/helper-split-export-declaration" "^7.18.6" "@babel/helper-validator-identifier" "^7.19.1" "@babel/template" "^7.18.10" - "@babel/traverse" "^7.19.6" - "@babel/types" "^7.19.4" + "@babel/traverse" "^7.20.1" + "@babel/types" "^7.20.2" "@babel/helper-plugin-utils@^7.18.6", "@babel/helper-plugin-utils@^7.19.0": - version "7.19.0" - resolved "https://registry.npmjs.org/@babel/helper-plugin-utils/-/helper-plugin-utils-7.19.0.tgz" - integrity sha512-40Ryx7I8mT+0gaNxm8JGTZFUITNqdLAgdg0hXzeVZxVD6nFsdhQvip6v8dqkRHzsz1VFpFAaOCHNn0vKBL7Czw== + version "7.20.2" + resolved "https://registry.yarnpkg.com/@babel/helper-plugin-utils/-/helper-plugin-utils-7.20.2.tgz#d1b9000752b18d0877cff85a5c376ce5c3121629" + integrity sha512-8RvlJG2mj4huQ4pZ+rU9lqKi9ZKiRmuvGuM2HlWmkmgOhbs6zEAw6IEiJ5cQqGbDzGZOhwuOQNtZMi/ENLjZoQ== -"@babel/helper-simple-access@^7.19.4": - version "7.19.4" - resolved "https://registry.yarnpkg.com/@babel/helper-simple-access/-/helper-simple-access-7.19.4.tgz#be553f4951ac6352df2567f7daa19a0ee15668e7" - integrity sha512-f9Xq6WqBFqaDfbCzn2w85hwklswz5qsKlh7f08w4Y9yhJHpnNC0QemtSkK5YyOY8kPGvyiwdzZksGUhnGdaUIg== +"@babel/helper-simple-access@^7.20.2": + version "7.20.2" + resolved "https://registry.yarnpkg.com/@babel/helper-simple-access/-/helper-simple-access-7.20.2.tgz#0ab452687fe0c2cfb1e2b9e0015de07fc2d62dd9" + integrity sha512-+0woI/WPq59IrqDYbVGfshjT5Dmk/nnbdpcF8SnMhhXObpTq2KNBdLFRFrkVdbDOyUmHBCxzm5FHV1rACIkIbA== dependencies: - "@babel/types" "^7.19.4" + "@babel/types" "^7.20.2" "@babel/helper-split-export-declaration@^7.18.6": version "7.18.6" - resolved "https://registry.npmjs.org/@babel/helper-split-export-declaration/-/helper-split-export-declaration-7.18.6.tgz" + resolved "https://registry.yarnpkg.com/@babel/helper-split-export-declaration/-/helper-split-export-declaration-7.18.6.tgz#7367949bc75b20c6d5a5d4a97bba2824ae8ef075" integrity sha512-bde1etTx6ZyTmobl9LLMMQsaizFVZrquTEHOqKeQESMKo4PlObf+8+JA25ZsIpZhT/WEd39+vOdLXAFG/nELpA== dependencies: "@babel/types" "^7.18.6" @@ -141,49 +141,49 @@ "@babel/helper-validator-option@^7.18.6": version "7.18.6" - resolved "https://registry.npmjs.org/@babel/helper-validator-option/-/helper-validator-option-7.18.6.tgz" + resolved "https://registry.yarnpkg.com/@babel/helper-validator-option/-/helper-validator-option-7.18.6.tgz#bf0d2b5a509b1f336099e4ff36e1a63aa5db4db8" integrity sha512-XO7gESt5ouv/LRJdrVjkShckw6STTaB7l9BrpBaAHDeF5YZT+01PCwmR0SJHnkW6i8OwW/EVWRShfi4j2x+KQw== -"@babel/helpers@^7.19.4": - version "7.20.0" - resolved "https://registry.yarnpkg.com/@babel/helpers/-/helpers-7.20.0.tgz#27c8ffa8cc32a2ed3762fba48886e7654dbcf77f" - integrity sha512-aGMjYraN0zosCEthoGLdqot1oRsmxVTQRHadsUPz5QM44Zej2PYRz7XiDE7GqnkZnNtLbOuxqoZw42vkU7+XEQ== +"@babel/helpers@^7.20.1": + version "7.20.1" + resolved "https://registry.yarnpkg.com/@babel/helpers/-/helpers-7.20.1.tgz#2ab7a0fcb0a03b5bf76629196ed63c2d7311f4c9" + integrity sha512-J77mUVaDTUJFZ5BpP6mMn6OIl3rEWymk2ZxDBQJUG3P+PbmyMcF3bYWvz0ma69Af1oobDqT/iAsvzhB58xhQUg== dependencies: "@babel/template" "^7.18.10" - "@babel/traverse" "^7.20.0" + "@babel/traverse" "^7.20.1" "@babel/types" "^7.20.0" "@babel/highlight@^7.18.6": version "7.18.6" - resolved "https://registry.npmjs.org/@babel/highlight/-/highlight-7.18.6.tgz" + resolved "https://registry.yarnpkg.com/@babel/highlight/-/highlight-7.18.6.tgz#81158601e93e2563795adcbfbdf5d64be3f2ecdf" integrity sha512-u7stbOuYjaPezCuLj29hNW1v64M2Md2qupEKP1fHc7WdOA3DgLh37suiSrZYY7haUB7iBeQZ9P1uiRF359do3g== dependencies: "@babel/helper-validator-identifier" "^7.18.6" chalk "^2.0.0" js-tokens "^4.0.0" -"@babel/parser@^7.18.10", "@babel/parser@^7.19.6", "@babel/parser@^7.20.0": - version "7.20.0" - resolved "https://registry.yarnpkg.com/@babel/parser/-/parser-7.20.0.tgz#b26133c888da4d79b0d3edcf42677bcadc783046" - integrity sha512-G9VgAhEaICnz8iiJeGJQyVl6J2nTjbW0xeisva0PK6XcKsga7BIaqm4ZF8Rg1Wbaqmy6znspNqhPaPkyukujzg== +"@babel/parser@^7.18.10", "@babel/parser@^7.20.1", "@babel/parser@^7.20.2": + version "7.20.2" + resolved "https://registry.yarnpkg.com/@babel/parser/-/parser-7.20.2.tgz#9aeb9b92f64412b5f81064d46f6a1ac0881337f4" + integrity sha512-afk318kh2uKbo7BEj2QtEi8HVCGrwHUffrYDy7dgVcSa2j9lY3LDjPzcyGdpX7xgm35aWqvciZJ4WKmdF/SxYg== "@babel/plugin-syntax-jsx@^7.17.12", "@babel/plugin-syntax-jsx@^7.18.6": version "7.18.6" - resolved "https://registry.npmjs.org/@babel/plugin-syntax-jsx/-/plugin-syntax-jsx-7.18.6.tgz" + resolved "https://registry.yarnpkg.com/@babel/plugin-syntax-jsx/-/plugin-syntax-jsx-7.18.6.tgz#a8feef63b010150abd97f1649ec296e849943ca0" integrity sha512-6mmljtAedFGTWu2p/8WIORGwy+61PLgOMPOdazc7YoJ9ZCWUyFy3A6CpPkRKLKD1ToAesxX8KGEViAiLo9N+7Q== dependencies: "@babel/helper-plugin-utils" "^7.18.6" "@babel/plugin-transform-react-jsx-development@^7.18.6": version "7.18.6" - resolved "https://registry.npmjs.org/@babel/plugin-transform-react-jsx-development/-/plugin-transform-react-jsx-development-7.18.6.tgz" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-react-jsx-development/-/plugin-transform-react-jsx-development-7.18.6.tgz#dbe5c972811e49c7405b630e4d0d2e1380c0ddc5" integrity sha512-SA6HEjwYFKF7WDjWcMcMGUimmw/nhNRDWxr+KaLSCrkD/LMDBvWRmHAYgE1HDeF8KUuI8OAu+RT6EOtKxSW2qA== dependencies: "@babel/plugin-transform-react-jsx" "^7.18.6" "@babel/plugin-transform-react-jsx-self@^7.18.6": version "7.18.6" - resolved "https://registry.npmjs.org/@babel/plugin-transform-react-jsx-self/-/plugin-transform-react-jsx-self-7.18.6.tgz" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-react-jsx-self/-/plugin-transform-react-jsx-self-7.18.6.tgz#3849401bab7ae8ffa1e3e5687c94a753fc75bda7" integrity sha512-A0LQGx4+4Jv7u/tWzoJF7alZwnBDQd6cGLh9P+Ttk4dpiL+J5p7NSNv/9tlEFFJDq3kjxOavWmbm6t0Gk+A3Ig== dependencies: "@babel/helper-plugin-utils" "^7.18.6" @@ -207,41 +207,41 @@ "@babel/types" "^7.19.0" "@babel/runtime@^7.0.0", "@babel/runtime@^7.12.1", "@babel/runtime@^7.12.13", "@babel/runtime@^7.12.5", "@babel/runtime@^7.13.10", "@babel/runtime@^7.18.3", "@babel/runtime@^7.5.5", "@babel/runtime@^7.8.7", "@babel/runtime@^7.9.2": - version "7.20.0" - resolved "https://registry.yarnpkg.com/@babel/runtime/-/runtime-7.20.0.tgz#824a9ef325ffde6f78056059db3168c08785e24a" - integrity sha512-NDYdls71fTXoU8TZHfbBWg7DiZfNzClcKui/+kyi6ppD2L1qnWW3VV6CjtaBXSUGGhiTWJ6ereOIkUvenif66Q== + version "7.20.1" + resolved "https://registry.yarnpkg.com/@babel/runtime/-/runtime-7.20.1.tgz#1148bb33ab252b165a06698fde7576092a78b4a9" + integrity sha512-mrzLkl6U9YLF8qpqI7TB82PESyEGjm/0Ly91jG575eVxMMlb8fYfOXFZIJ8XfLrJZQbm7dlKry2bJmXBUEkdFg== dependencies: regenerator-runtime "^0.13.10" "@babel/template@^7.18.10": version "7.18.10" - resolved "https://registry.npmjs.org/@babel/template/-/template-7.18.10.tgz" + resolved "https://registry.yarnpkg.com/@babel/template/-/template-7.18.10.tgz#6f9134835970d1dbf0835c0d100c9f38de0c5e71" integrity sha512-TI+rCtooWHr3QJ27kJxfjutghu44DLnasDMwpDqCXVTal9RLp3RSYNh4NdBrRP2cQAoG9A8juOQl6P6oZG4JxA== dependencies: "@babel/code-frame" "^7.18.6" "@babel/parser" "^7.18.10" "@babel/types" "^7.18.10" -"@babel/traverse@^7.19.6", "@babel/traverse@^7.20.0": - version "7.20.0" - resolved "https://registry.yarnpkg.com/@babel/traverse/-/traverse-7.20.0.tgz#538c4c6ce6255f5666eba02252a7b59fc2d5ed98" - integrity sha512-5+cAXQNARgjRUK0JWu2UBwja4JLSO/rBMPJzpsKb+oBF5xlUuCfljQepS4XypBQoiigL0VQjTZy6WiONtUdScQ== +"@babel/traverse@^7.20.1": + version "7.20.1" + resolved "https://registry.yarnpkg.com/@babel/traverse/-/traverse-7.20.1.tgz#9b15ccbf882f6d107eeeecf263fbcdd208777ec8" + integrity sha512-d3tN8fkVJwFLkHkBN479SOsw4DMZnz8cdbL/gvuDuzy3TS6Nfw80HuQqhw1pITbIruHyh7d1fMA47kWzmcUEGA== dependencies: "@babel/code-frame" "^7.18.6" - "@babel/generator" "^7.20.0" + "@babel/generator" "^7.20.1" "@babel/helper-environment-visitor" "^7.18.9" "@babel/helper-function-name" "^7.19.0" "@babel/helper-hoist-variables" "^7.18.6" "@babel/helper-split-export-declaration" "^7.18.6" - "@babel/parser" "^7.20.0" + "@babel/parser" "^7.20.1" "@babel/types" "^7.20.0" debug "^4.1.0" globals "^11.1.0" -"@babel/types@^7.18.10", "@babel/types@^7.18.6", "@babel/types@^7.19.0", "@babel/types@^7.19.4", "@babel/types@^7.20.0": - version "7.20.0" - resolved "https://registry.yarnpkg.com/@babel/types/-/types-7.20.0.tgz#52c94cf8a7e24e89d2a194c25c35b17a64871479" - integrity sha512-Jlgt3H0TajCW164wkTOTzHkZb075tMQMULzrLUoUeKmO7eFL96GgDxf7/Axhc5CAuKE3KFyVW1p6ysKsi2oXAg== +"@babel/types@^7.18.10", "@babel/types@^7.18.6", "@babel/types@^7.19.0", "@babel/types@^7.20.0", "@babel/types@^7.20.2": + version "7.20.2" + resolved "https://registry.yarnpkg.com/@babel/types/-/types-7.20.2.tgz#67ac09266606190f496322dbaff360fdaa5e7842" + integrity sha512-FnnvsNWgZCr232sqtXggapvlkk/tuwR/qhGzcmxI0GXLCjmPYQPzio2FbdlWuY6y1sHFfQKk+rRbUZ9VStQMog== dependencies: "@babel/helper-string-parser" "^7.19.4" "@babel/helper-validator-identifier" "^7.19.1" @@ -304,10 +304,10 @@ "@chakra-ui/react-use-merge-refs" "2.0.4" "@chakra-ui/spinner" "2.0.10" -"@chakra-ui/checkbox@2.2.2": - version "2.2.2" - resolved "https://registry.yarnpkg.com/@chakra-ui/checkbox/-/checkbox-2.2.2.tgz#494d7090ac11a0a43d05b7849aff6085f7a91045" - integrity sha512-Y6Zbkkk5VNoe0RzqU6F+rKlFVPlubz1KIgYcb7CCNHGOM97dLtRm78eAvJ+7Xmpitr+7zZ4hJLLjfAz+e1X7rA== +"@chakra-ui/checkbox@2.2.3": + version "2.2.3" + resolved "https://registry.yarnpkg.com/@chakra-ui/checkbox/-/checkbox-2.2.3.tgz#ae4f7728defd8c5c080ff56cc4243a9c47e0d092" + integrity sha512-ScPIoBbdAbRV+Pdy3B4UqYtf+IxPpm+FHMVPELi2rJUe3k5UcyZcs9DxzKsBS+5e3QBD+H82a6ui0mx9Pyfq1A== dependencies: "@chakra-ui/form-control" "2.0.11" "@chakra-ui/react-context" "2.0.4" @@ -317,7 +317,7 @@ "@chakra-ui/react-use-merge-refs" "2.0.4" "@chakra-ui/react-use-safe-layout-effect" "2.0.2" "@chakra-ui/react-use-update-effect" "2.0.4" - "@chakra-ui/visually-hidden" "2.0.11" + "@chakra-ui/visually-hidden" "2.0.12" "@zag-js/focus-visible" "0.1.0" "@chakra-ui/clickable@2.0.10": @@ -354,10 +354,10 @@ "@chakra-ui/number-utils" "2.0.4" "@chakra-ui/react-use-callback-ref" "2.0.4" -"@chakra-ui/css-reset@2.0.8": - version "2.0.8" - resolved "https://registry.yarnpkg.com/@chakra-ui/css-reset/-/css-reset-2.0.8.tgz#093ce6b166b37f2dd14e63f246635c463a59c106" - integrity sha512-VuDD1rk1pFc+dItk4yUcstyoC9D2B35hatHDBtlPMqTczFAzpbgVJJYgEHANatXGfulM5SdckmYEIJ3Tac1Rtg== +"@chakra-ui/css-reset@2.0.9": + version "2.0.9" + resolved "https://registry.yarnpkg.com/@chakra-ui/css-reset/-/css-reset-2.0.9.tgz#fb7ec1f145562dcda2491038af2e1e7b414d4c22" + integrity sha512-pLEhUetGJ5Dee2xiPDGAzTDBzY7e1OsuS9yEq8/vcGBBVrQ4Y+r+qTEvpf1Zqb2dOl+vUUcqhhaVk8d7uRDGFA== "@chakra-ui/descendant@3.0.10": version "3.0.10" @@ -372,10 +372,10 @@ resolved "https://registry.yarnpkg.com/@chakra-ui/dom-utils/-/dom-utils-2.0.3.tgz#8a5498b107d3a42662f3502f7b8965cb73bf6a33" integrity sha512-aeGlRmTxcv0cvW44DyeZHru1i68ZDQsXpfX2dnG1I1yBlT6GlVx1xYjCULis9mjhgvd2O3NfcYPRTkjNWTDUbA== -"@chakra-ui/editable@2.0.13": - version "2.0.13" - resolved "https://registry.yarnpkg.com/@chakra-ui/editable/-/editable-2.0.13.tgz#4e6ff480956ae2dcacf4ba2a15019336486bd613" - integrity sha512-GM3n8t3/TOFFcDOWF/tuKsnqn66isZLsU+FkMRY2o0E8XjLBGjCKuXInPW5SRBqhje7EHC+kwViLE780PfwXbw== +"@chakra-ui/editable@2.0.14": + version "2.0.14" + resolved "https://registry.yarnpkg.com/@chakra-ui/editable/-/editable-2.0.14.tgz#969b0796dc1c3c1baebb8d807f310606b5b147db" + integrity sha512-BQSLOYyfcB6vk8AFMhprcoIk1jKPi3KuXAdApqM3w15l4TVwR5j1C1RNYbJaX28HKXRlO526PS3NZPzrQSLciQ== dependencies: "@chakra-ui/react-context" "2.0.4" "@chakra-ui/react-types" "2.0.3" @@ -410,10 +410,10 @@ "@chakra-ui/react-types" "2.0.3" "@chakra-ui/react-use-merge-refs" "2.0.4" -"@chakra-ui/hooks@2.1.0": - version "2.1.0" - resolved "https://registry.yarnpkg.com/@chakra-ui/hooks/-/hooks-2.1.0.tgz#a8df3692e407c2fed8cc551c8ce7f3fcd0ea9864" - integrity sha512-4H6BDITq/YrStW99LXurgPkcz4qHSVy9V/QWXCvt1pCuiDTqNztiW4r508H3ApAOsL9NEbyXcM/zWYD7r5VDjA== +"@chakra-ui/hooks@2.1.1": + version "2.1.1" + resolved "https://registry.yarnpkg.com/@chakra-ui/hooks/-/hooks-2.1.1.tgz#2ecf6389d583a1fd7dbfcb373d447e2559d98925" + integrity sha512-HG2cSn0ds6pE0WyGzbddtVcZH76ol543RZ5aYBiU3q0WnPtU6BzQQKorCdCLR1Kq6wVNcA29RlSLDrWiuN4GSQ== dependencies: "@chakra-ui/react-utils" "2.0.8" "@chakra-ui/utils" "2.0.11" @@ -482,10 +482,10 @@ "@chakra-ui/breakpoint-utils" "2.0.4" "@chakra-ui/react-env" "2.0.10" -"@chakra-ui/menu@2.1.2": - version "2.1.2" - resolved "https://registry.yarnpkg.com/@chakra-ui/menu/-/menu-2.1.2.tgz#bbe39e1efdb408ba8e6616e0ec290417474f9454" - integrity sha512-6Z7ecXjp6BtZ1ExbFggfxsAj1hwtcathXekmCTxHpXOD+BdjAC/13+oLclwXeuBO85aoTmQrQ2ovfTkO31bzRQ== +"@chakra-ui/menu@2.1.3": + version "2.1.3" + resolved "https://registry.yarnpkg.com/@chakra-ui/menu/-/menu-2.1.3.tgz#a2e74d42655fc1d5c6598a16d27a72a064312b2b" + integrity sha512-uVS3gxl3o1b4v6Uwpgt+7DdEOuT0IgHjeM7jna5tFnOI3G2QTjIyd4DaKbYPxqZKlD8TQK+0wLA08th61paq/w== dependencies: "@chakra-ui/clickable" "2.0.10" "@chakra-ui/descendant" "3.0.10" @@ -496,7 +496,7 @@ "@chakra-ui/react-use-animation-state" "2.0.5" "@chakra-ui/react-use-controllable-state" "2.0.5" "@chakra-ui/react-use-disclosure" "2.0.5" - "@chakra-ui/react-use-focus-effect" "2.0.5" + "@chakra-ui/react-use-focus-effect" "2.0.6" "@chakra-ui/react-use-merge-refs" "2.0.4" "@chakra-ui/react-use-outside-click" "2.0.4" "@chakra-ui/react-use-update-effect" "2.0.4" @@ -555,10 +555,10 @@ "@chakra-ui/react-use-controllable-state" "2.0.5" "@chakra-ui/react-use-merge-refs" "2.0.4" -"@chakra-ui/popover@2.1.1": - version "2.1.1" - resolved "https://registry.yarnpkg.com/@chakra-ui/popover/-/popover-2.1.1.tgz#1b5e05e334ba5f9bce4bc5bcabfb92563393fc84" - integrity sha512-j09NsesfT+eaYITkITYJXDlRcPoOeQUM80neJZKOBgul2iHkVsEoii8dwS5Ip5ONeu4ane1b6zEOlYvYj2SrkA== +"@chakra-ui/popover@2.1.2": + version "2.1.2" + resolved "https://registry.yarnpkg.com/@chakra-ui/popover/-/popover-2.1.2.tgz#06c0733b0a715ed559f418aba2e7e6d70de6b8ae" + integrity sha512-ANnKH5oA5HEeouRSch370iw6wQ8r5rBhz9NflVyXjmTlJ7/rjkOyQ8pEFzvJbvzp4iFj4htejHK2qDK0b/qKLA== dependencies: "@chakra-ui/close-button" "2.0.11" "@chakra-ui/lazy-utils" "2.0.2" @@ -567,7 +567,7 @@ "@chakra-ui/react-types" "2.0.3" "@chakra-ui/react-use-animation-state" "2.0.5" "@chakra-ui/react-use-disclosure" "2.0.5" - "@chakra-ui/react-use-focus-effect" "2.0.5" + "@chakra-ui/react-use-focus-effect" "2.0.6" "@chakra-ui/react-use-focus-on-pointer-down" "2.0.3" "@chakra-ui/react-use-merge-refs" "2.0.4" @@ -588,22 +588,22 @@ "@chakra-ui/react-context" "2.0.4" "@chakra-ui/react-use-safe-layout-effect" "2.0.2" -"@chakra-ui/progress@2.0.12": - version "2.0.12" - resolved "https://registry.yarnpkg.com/@chakra-ui/progress/-/progress-2.0.12.tgz#7ce57fe2822d1741c26e82960ca02c667a265a05" - integrity sha512-9qtZimZosTliI7siAZkLeCVdCpXCTxmSETCudHcCUsC+FtcFacmA65+We8qij1nOIqmsbm+NYU6PP89TU2n4Hg== +"@chakra-ui/progress@2.1.0": + version "2.1.0" + resolved "https://registry.yarnpkg.com/@chakra-ui/progress/-/progress-2.1.0.tgz#87d03da5c6075ec6326db9d8cc412be053945784" + integrity sha512-CK4XmDrbAzR95po5L07sGCniMeOZiF148CLC/dItwgRc65NFmaHSL1OvqXQz6qiDiBOmZxPq0Qu1KovJGg/esA== dependencies: "@chakra-ui/react-context" "2.0.4" -"@chakra-ui/provider@2.0.20": - version "2.0.20" - resolved "https://registry.yarnpkg.com/@chakra-ui/provider/-/provider-2.0.20.tgz#2f3f73f6142f4d2b2a5a8ad6dbd777a3fc4390ce" - integrity sha512-mNNfsgm05G4x1VzvHVR9+PNEiuxNnn9xUKDuEwoaO7+IHCMzCRMtPbSJjwmv0xvHUGB9+JChjPpZI5RuHQziJQ== +"@chakra-ui/provider@2.0.21": + version "2.0.21" + resolved "https://registry.yarnpkg.com/@chakra-ui/provider/-/provider-2.0.21.tgz#4ffafad4991d83af4fbf88873b78b09f9f7cb8f4" + integrity sha512-P3Pm/0hz6ViuC9JsxAOFKm+sOl4w5yaZdPWFFOeztHj4rEkFd7UnyNV3SfUlFOs/ZzIFnzaGNd9xngoSi728JQ== dependencies: - "@chakra-ui/css-reset" "2.0.8" + "@chakra-ui/css-reset" "2.0.9" "@chakra-ui/portal" "2.0.10" "@chakra-ui/react-env" "2.0.10" - "@chakra-ui/system" "2.3.0" + "@chakra-ui/system" "2.3.1" "@chakra-ui/utils" "2.0.11" "@chakra-ui/radio@2.0.12": @@ -634,7 +634,7 @@ "@chakra-ui/react-types@2.0.3": version "2.0.3" - resolved "https://registry.npmjs.org/@chakra-ui/react-types/-/react-types-2.0.3.tgz" + resolved "https://registry.yarnpkg.com/@chakra-ui/react-types/-/react-types-2.0.3.tgz#dc454c4703b4de585e6461fd607304ede06fe595" integrity sha512-1mJYOQldFTALE0Wr3j6tk/MYvgQIp6CKkJulNzZrI8QN+ox/bJOh8OVP4vhwqvfigdLTui0g0k8M9h+j2ub/Mw== "@chakra-ui/react-use-animation-state@2.0.5": @@ -671,13 +671,14 @@ dependencies: "@chakra-ui/react-use-callback-ref" "2.0.4" -"@chakra-ui/react-use-focus-effect@2.0.5": - version "2.0.5" - resolved "https://registry.yarnpkg.com/@chakra-ui/react-use-focus-effect/-/react-use-focus-effect-2.0.5.tgz#b554277c38e84468b019e08a73579e9700e1003a" - integrity sha512-sbe1QnsXXfjukM+laxbKnT0UnMpHe/7kTzEPG/BYM6/ZDUUmrC1Nz+8l+3H/52iWIaruikDBdif/Xd37Yvu3Kg== +"@chakra-ui/react-use-focus-effect@2.0.6": + version "2.0.6" + resolved "https://registry.yarnpkg.com/@chakra-ui/react-use-focus-effect/-/react-use-focus-effect-2.0.6.tgz#e5a607a68ecf1240e7ab4b233403d55e3cddc4b5" + integrity sha512-J5I8pIUcros5VP8g5b3o3qAvJ8ltoYuO7w2n6V1xCVkBbY2J1dyDR5qkRjRG+cD9Ik/iCftnTiRWaUSokfDzEw== dependencies: "@chakra-ui/dom-utils" "2.0.3" "@chakra-ui/react-use-event-listener" "2.0.4" + "@chakra-ui/react-use-safe-layout-effect" "2.0.2" "@chakra-ui/react-use-update-effect" "2.0.4" "@chakra-ui/react-use-focus-on-pointer-down@2.0.3": @@ -757,38 +758,38 @@ "@chakra-ui/utils" "2.0.11" "@chakra-ui/react@^2.3.1": - version "2.3.6" - resolved "https://registry.yarnpkg.com/@chakra-ui/react/-/react-2.3.6.tgz#a6d3e092cab433fcd9cf8e9876756818c4261df6" - integrity sha512-xo43UU+yMqRGHZLU4fSgzojeRl5stlIfT+GLbT9CUVEm0HMJCt2m8RsNPBvGOMzANdC+bzwSiOm+MNzQBi9IBQ== + version "2.3.7" + resolved "https://registry.yarnpkg.com/@chakra-ui/react/-/react-2.3.7.tgz#58dfcec0bea9681957491948fd3033b2cb237b27" + integrity sha512-vnnBDwyvzhQfIgWkqhI8dAX2voVfJOZdTyOsKah0eHc5mvc2oUfoHGRzYNZPSb9bHiKd5roktaDp5tayXv/ECg== dependencies: "@chakra-ui/accordion" "2.1.2" "@chakra-ui/alert" "2.0.11" "@chakra-ui/avatar" "2.2.0" "@chakra-ui/breadcrumb" "2.1.0" "@chakra-ui/button" "2.0.11" - "@chakra-ui/checkbox" "2.2.2" + "@chakra-ui/checkbox" "2.2.3" "@chakra-ui/close-button" "2.0.11" "@chakra-ui/control-box" "2.0.10" "@chakra-ui/counter" "2.0.10" - "@chakra-ui/css-reset" "2.0.8" - "@chakra-ui/editable" "2.0.13" + "@chakra-ui/css-reset" "2.0.9" + "@chakra-ui/editable" "2.0.14" "@chakra-ui/form-control" "2.0.11" - "@chakra-ui/hooks" "2.1.0" + "@chakra-ui/hooks" "2.1.1" "@chakra-ui/icon" "3.0.11" "@chakra-ui/image" "2.0.11" "@chakra-ui/input" "2.0.12" "@chakra-ui/layout" "2.1.9" "@chakra-ui/live-region" "2.0.10" "@chakra-ui/media-query" "3.2.7" - "@chakra-ui/menu" "2.1.2" + "@chakra-ui/menu" "2.1.3" "@chakra-ui/modal" "2.2.2" "@chakra-ui/number-input" "2.0.12" "@chakra-ui/pin-input" "2.0.15" - "@chakra-ui/popover" "2.1.1" + "@chakra-ui/popover" "2.1.2" "@chakra-ui/popper" "3.0.8" "@chakra-ui/portal" "2.0.10" - "@chakra-ui/progress" "2.0.12" - "@chakra-ui/provider" "2.0.20" + "@chakra-ui/progress" "2.1.0" + "@chakra-ui/provider" "2.0.21" "@chakra-ui/radio" "2.0.12" "@chakra-ui/react-env" "2.0.10" "@chakra-ui/select" "2.0.12" @@ -797,19 +798,19 @@ "@chakra-ui/spinner" "2.0.10" "@chakra-ui/stat" "2.0.11" "@chakra-ui/styled-system" "2.3.4" - "@chakra-ui/switch" "2.0.14" - "@chakra-ui/system" "2.3.0" + "@chakra-ui/switch" "2.0.15" + "@chakra-ui/system" "2.3.1" "@chakra-ui/table" "2.0.11" "@chakra-ui/tabs" "2.1.4" "@chakra-ui/tag" "2.0.11" "@chakra-ui/textarea" "2.0.12" - "@chakra-ui/theme" "2.1.14" - "@chakra-ui/theme-utils" "2.0.1" - "@chakra-ui/toast" "4.0.0" + "@chakra-ui/theme" "2.1.15" + "@chakra-ui/theme-utils" "2.0.2" + "@chakra-ui/toast" "4.0.1" "@chakra-ui/tooltip" "2.2.0" "@chakra-ui/transition" "2.0.11" "@chakra-ui/utils" "2.0.11" - "@chakra-ui/visually-hidden" "2.0.11" + "@chakra-ui/visually-hidden" "2.0.12" "@chakra-ui/select@2.0.12": version "2.0.12" @@ -868,22 +869,22 @@ csstype "^3.0.11" lodash.mergewith "4.6.2" -"@chakra-ui/switch@2.0.14": - version "2.0.14" - resolved "https://registry.yarnpkg.com/@chakra-ui/switch/-/switch-2.0.14.tgz#62372355bf73c19896b39fb7e75c132333c5a882" - integrity sha512-6lzhCkJq7vbD3yGaorGLp0ZZU4ewdKwAu0e62qR8TfYZwbcbpkXbBKloIHbA2XKOduISzS2WYqjmoP6jSKIxrA== +"@chakra-ui/switch@2.0.15": + version "2.0.15" + resolved "https://registry.yarnpkg.com/@chakra-ui/switch/-/switch-2.0.15.tgz#7bcaf8380a3f3969685bc89d2b95b72d083b6f81" + integrity sha512-93tUSAKBnIIUddf7Bvk0uDNeZ5e5FDlWRbAmfaJNSN4YVKFZI3VYd9PCfxpmQB8Uu6Qt8Ex70v++meNhd3kpHA== dependencies: - "@chakra-ui/checkbox" "2.2.2" + "@chakra-ui/checkbox" "2.2.3" -"@chakra-ui/system@2.3.0": - version "2.3.0" - resolved "https://registry.yarnpkg.com/@chakra-ui/system/-/system-2.3.0.tgz#b7ba122872d4d48806fbf994f1187680ae2296a6" - integrity sha512-BxikahglBI0uU8FE3anEorDTU5oKTUuBIEKVcQrEVnrbNuRJEy1OVYyCNXfqW3MpruRO9ypYV2bWt02AZZWEaQ== +"@chakra-ui/system@2.3.1": + version "2.3.1" + resolved "https://registry.yarnpkg.com/@chakra-ui/system/-/system-2.3.1.tgz#1fbf18e1f19f1f3d489ce1b864be1b2eb444072d" + integrity sha512-pR8KYmqN6rQ+aZ8cT5IYfF7rVXEuh6ZWZgWIdgmt5NMseQ2DR9JlK0SRoHNFW1TnFD4Odq2T7Xh46MHiQZCm1g== dependencies: "@chakra-ui/color-mode" "2.1.9" "@chakra-ui/react-utils" "2.0.8" "@chakra-ui/styled-system" "2.3.4" - "@chakra-ui/theme-utils" "2.0.1" + "@chakra-ui/theme-utils" "2.0.2" "@chakra-ui/utils" "2.0.11" react-fast-compare "3.2.0" @@ -931,27 +932,27 @@ "@chakra-ui/anatomy" "2.0.7" "@ctrl/tinycolor" "^3.4.0" -"@chakra-ui/theme-utils@2.0.1": - version "2.0.1" - resolved "https://registry.yarnpkg.com/@chakra-ui/theme-utils/-/theme-utils-2.0.1.tgz#a3dc99331ba943e155dd683fe25ce302e3084db0" - integrity sha512-NDwzgTPxm+v3PAJlSSU1MORHLMqO9vsRJ+ObELD5wpvE9aEyRziN/AZSoK2oLwCQMPEiU7R99K5ij1E6ptMt7w== +"@chakra-ui/theme-utils@2.0.2": + version "2.0.2" + resolved "https://registry.yarnpkg.com/@chakra-ui/theme-utils/-/theme-utils-2.0.2.tgz#fae1c307fe82a4b7c824f73ef34f77fc515d970b" + integrity sha512-juGdDxTJx7deu2xgdNudRWi+qTbViPQKK0niLSOaXsZIfobVDgBn2iIgwLqFcIR0M1yPk64ERtEuvgGa2yI9iw== dependencies: "@chakra-ui/styled-system" "2.3.4" - "@chakra-ui/theme" "2.1.14" + "@chakra-ui/theme" "2.1.15" lodash.mergewith "4.6.2" -"@chakra-ui/theme@2.1.14": - version "2.1.14" - resolved "https://registry.yarnpkg.com/@chakra-ui/theme/-/theme-2.1.14.tgz#4726d65a65515f8ee96b5f2a725d0d17804ddfc9" - integrity sha512-6EYJCQlrjSjNAJvZmw1un50F8+sQDFsdwu/7UzWe+TeANpKlz4ZcHbh0gkl3PD62lGis+ehITUwqRm8htvDOjw== +"@chakra-ui/theme@2.1.15": + version "2.1.15" + resolved "https://registry.yarnpkg.com/@chakra-ui/theme/-/theme-2.1.15.tgz#caf7902435b6e09f957d376cd2dcb509e062a0fb" + integrity sha512-e+oZ0e7kXjtjWO0phUzlz9weWv0w4lv4Us/Lf8DXbstrPujgyxNYOF0LHTDRxzUNa5bYUsP9g5W+FW4e9E2UsQ== dependencies: "@chakra-ui/anatomy" "2.0.7" "@chakra-ui/theme-tools" "2.0.12" -"@chakra-ui/toast@4.0.0": - version "4.0.0" - resolved "https://registry.yarnpkg.com/@chakra-ui/toast/-/toast-4.0.0.tgz#797c34c4ecfcad7c6899c1cda221af0ff04d5d0b" - integrity sha512-abeeloJac5T9WK2IN76fEM5FSRH+erNXln2HqDf5wLBn33avSBXWyTiUL8riVSUqto0lrIn6FuK/MmKo0DH4og== +"@chakra-ui/toast@4.0.1": + version "4.0.1" + resolved "https://registry.yarnpkg.com/@chakra-ui/toast/-/toast-4.0.1.tgz#e06e868636b221aa6da9564e30716d76c5508fc5" + integrity sha512-F2Xrn+LwksgdgvkUDcMNJuGfZabBNwx9PgMq6SE0Oz5XYitgrGfEx55q6Hzl6nOyHq7IkEjmZGxv3N/nYq+P3w== dependencies: "@chakra-ui/alert" "2.0.11" "@chakra-ui/close-button" "2.0.11" @@ -959,7 +960,7 @@ "@chakra-ui/react-use-timeout" "2.0.2" "@chakra-ui/react-use-update-effect" "2.0.4" "@chakra-ui/styled-system" "2.3.4" - "@chakra-ui/theme" "2.1.14" + "@chakra-ui/theme" "2.1.15" "@chakra-ui/tooltip@2.2.0": version "2.2.0" @@ -988,16 +989,21 @@ framesync "5.3.0" lodash.mergewith "4.6.2" -"@chakra-ui/visually-hidden@2.0.11": - version "2.0.11" - resolved "https://registry.yarnpkg.com/@chakra-ui/visually-hidden/-/visually-hidden-2.0.11.tgz#b2eb236e803451b39cdfcce3c5ab52e773c066a3" - integrity sha512-e+5amYvnsmEQdiWH4XMyvrtGTdwz//+48vwj5CsNWWcselzkwqodmciy5rIrT71/SCQDOtmgnL7ZWAUOffxfsQ== +"@chakra-ui/visually-hidden@2.0.12": + version "2.0.12" + resolved "https://registry.yarnpkg.com/@chakra-ui/visually-hidden/-/visually-hidden-2.0.12.tgz#e4bb4983ed16dbdb7e8e84c29e81e3e493661284" + integrity sha512-5Vn21NpAol5tX5OKJlMh4pfTlX98CNhrbA29OGZyfPzNjXw2ZQo0iDUPG4gMNa9EdbVWpbbRmT6l6R6ObatEUw== "@ctrl/tinycolor@^3.4.0": version "3.4.1" - resolved "https://registry.npmjs.org/@ctrl/tinycolor/-/tinycolor-3.4.1.tgz" + resolved "https://registry.yarnpkg.com/@ctrl/tinycolor/-/tinycolor-3.4.1.tgz#75b4c27948c81e88ccd3a8902047bcd797f38d32" integrity sha512-ej5oVy6lykXsvieQtqZxCOaLT+xD4+QNarq78cIYISHmZXshCvROLudpQN3lfL8G0NL7plMSSK+zlyvCaIJ4Iw== +"@cush/relative@^1.0.0": + version "1.0.0" + resolved "https://registry.yarnpkg.com/@cush/relative/-/relative-1.0.0.tgz#8cd1769bf9bde3bb27dac356b1bc94af40f6cc16" + integrity sha512-RpfLEtTlyIxeNPGKcokS+p3BZII/Q3bYxryFRglh5H3A3T8q9fsLYm72VYAMEOOIBLEa8o93kFLiBDUWKrwXZA== + "@emotion/babel-plugin@^11.10.5": version "11.10.5" resolved "https://registry.yarnpkg.com/@emotion/babel-plugin/-/babel-plugin-11.10.5.tgz#65fa6e1790ddc9e23cc22658a4c5dea423c55c3c" @@ -1029,19 +1035,19 @@ "@emotion/hash@^0.9.0": version "0.9.0" - resolved "https://registry.npmjs.org/@emotion/hash/-/hash-0.9.0.tgz" + resolved "https://registry.yarnpkg.com/@emotion/hash/-/hash-0.9.0.tgz#c5153d50401ee3c027a57a177bc269b16d889cb7" integrity sha512-14FtKiHhy2QoPIzdTcvh//8OyBlknNs2nXRwIhG904opCby3l+9Xaf/wuPvICBF0rc1ZCNBd3nKe9cd2mecVkQ== "@emotion/is-prop-valid@^0.8.2": version "0.8.8" - resolved "https://registry.npmjs.org/@emotion/is-prop-valid/-/is-prop-valid-0.8.8.tgz" + resolved "https://registry.yarnpkg.com/@emotion/is-prop-valid/-/is-prop-valid-0.8.8.tgz#db28b1c4368a259b60a97311d6a952d4fd01ac1a" integrity sha512-u5WtneEAr5IDG2Wv65yhunPSMLIpuKsbuOktRojfrEiEvRyC85LgPMZI63cr7NUqT8ZIGdSVg8ZKGxIug4lXcA== dependencies: "@emotion/memoize" "0.7.4" "@emotion/is-prop-valid@^1.2.0": version "1.2.0" - resolved "https://registry.npmjs.org/@emotion/is-prop-valid/-/is-prop-valid-1.2.0.tgz" + resolved "https://registry.yarnpkg.com/@emotion/is-prop-valid/-/is-prop-valid-1.2.0.tgz#7f2d35c97891669f7e276eb71c83376a5dc44c83" integrity sha512-3aDpDprjM0AwaxGE09bOPkNxHpBd+kA6jty3RnaEXdweX1DF1U3VQpPYb0g1IStAuK7SVQ1cy+bNBBKp4W3Fjg== dependencies: "@emotion/memoize" "^0.8.0" @@ -1053,7 +1059,7 @@ "@emotion/memoize@^0.8.0": version "0.8.0" - resolved "https://registry.npmjs.org/@emotion/memoize/-/memoize-0.8.0.tgz" + resolved "https://registry.yarnpkg.com/@emotion/memoize/-/memoize-0.8.0.tgz#f580f9beb67176fa57aae70b08ed510e1b18980f" integrity sha512-G/YwXTkv7Den9mXDO7AhLWkE3q+I92B+VqAE+dYG4NGPaHZGvt3G8Q0p9vmE+sq7rTGphUbAvmQ9YpbfMQGGlA== "@emotion/react@^11.10.4": @@ -1100,33 +1106,33 @@ "@emotion/unitless@^0.8.0": version "0.8.0" - resolved "https://registry.npmjs.org/@emotion/unitless/-/unitless-0.8.0.tgz" + resolved "https://registry.yarnpkg.com/@emotion/unitless/-/unitless-0.8.0.tgz#a4a36e9cbdc6903737cd20d38033241e1b8833db" integrity sha512-VINS5vEYAscRl2ZUDiT3uMPlrFQupiKgHz5AA4bCH1miKBg4qtwkim1qPmJj/4WG6TreYMY111rEFsjupcOKHw== "@emotion/use-insertion-effect-with-fallbacks@^1.0.0": version "1.0.0" - resolved "https://registry.npmjs.org/@emotion/use-insertion-effect-with-fallbacks/-/use-insertion-effect-with-fallbacks-1.0.0.tgz" + resolved "https://registry.yarnpkg.com/@emotion/use-insertion-effect-with-fallbacks/-/use-insertion-effect-with-fallbacks-1.0.0.tgz#ffadaec35dbb7885bd54de3fa267ab2f860294df" integrity sha512-1eEgUGmkaljiBnRMTdksDV1W4kUnmwgp7X9G8B++9GYwl1lUdqSndSriIrTJ0N7LQaoauY9JJ2yhiOYK5+NI4A== "@emotion/utils@^1.2.0": version "1.2.0" - resolved "https://registry.npmjs.org/@emotion/utils/-/utils-1.2.0.tgz" + resolved "https://registry.yarnpkg.com/@emotion/utils/-/utils-1.2.0.tgz#9716eaccbc6b5ded2ea5a90d65562609aab0f561" integrity sha512-sn3WH53Kzpw8oQ5mgMmIzzyAaH2ZqFEbozVVBSYp538E06OSE6ytOp7pRAjNQR+Q/orwqdQYJSe2m3hCOeznkw== "@emotion/weak-memoize@^0.3.0": version "0.3.0" - resolved "https://registry.npmjs.org/@emotion/weak-memoize/-/weak-memoize-0.3.0.tgz" + resolved "https://registry.yarnpkg.com/@emotion/weak-memoize/-/weak-memoize-0.3.0.tgz#ea89004119dc42db2e1dba0f97d553f7372f6fcb" integrity sha512-AHPmaAx+RYfZz0eYu6Gviiagpmiyw98ySSlQvCUhVGDRtDFe4DBS0x1bSjdF3gqUDYOczB+yYvBTtEylYSdRhg== -"@esbuild/android-arm@0.15.12": - version "0.15.12" - resolved "https://registry.yarnpkg.com/@esbuild/android-arm/-/android-arm-0.15.12.tgz#e548b10a5e55b9e10537a049ebf0bc72c453b769" - integrity sha512-IC7TqIqiyE0MmvAhWkl/8AEzpOtbhRNDo7aph47We1NbE5w2bt/Q+giAhe0YYeVpYnIhGMcuZY92qDK6dQauvA== +"@esbuild/android-arm@0.15.13": + version "0.15.13" + resolved "https://registry.yarnpkg.com/@esbuild/android-arm/-/android-arm-0.15.13.tgz#ce11237a13ee76d5eae3908e47ba4ddd380af86a" + integrity sha512-RY2fVI8O0iFUNvZirXaQ1vMvK0xhCcl0gqRj74Z6yEiO1zAUa7hbsdwZM1kzqbxHK7LFyMizipfXT3JME+12Hw== -"@esbuild/linux-loong64@0.15.12": - version "0.15.12" - resolved "https://registry.yarnpkg.com/@esbuild/linux-loong64/-/linux-loong64-0.15.12.tgz#475b33a2631a3d8ca8aa95ee127f9a61d95bf9c1" - integrity sha512-tZEowDjvU7O7I04GYvWQOS4yyP9E/7YlsB0jjw1Ycukgr2ycEzKyIk5tms5WnLBymaewc6VmRKnn5IJWgK4eFw== +"@esbuild/linux-loong64@0.15.13": + version "0.15.13" + resolved "https://registry.yarnpkg.com/@esbuild/linux-loong64/-/linux-loong64-0.15.13.tgz#64e8825bf0ce769dac94ee39d92ebe6272020dfc" + integrity sha512-+BoyIm4I8uJmH/QDIH0fu7MG0AEx9OXEDXnqptXCwKOlOqZiS4iraH1Nr7/ObLMokW3sOCeBNyD68ATcV9b9Ag== "@eslint/eslintrc@^1.3.3": version "1.3.3" @@ -1145,19 +1151,19 @@ "@floating-ui/core@^0.7.3": version "0.7.3" - resolved "https://registry.npmjs.org/@floating-ui/core/-/core-0.7.3.tgz" + resolved "https://registry.yarnpkg.com/@floating-ui/core/-/core-0.7.3.tgz#d274116678ffae87f6b60e90f88cc4083eefab86" integrity sha512-buc8BXHmG9l82+OQXOFU3Kr2XQx9ys01U/Q9HMIrZ300iLc8HLMgh7dcCqgYzAzf4BkoQvDcXf5Y+CuEZ5JBYg== "@floating-ui/dom@^0.5.3": version "0.5.4" - resolved "https://registry.npmjs.org/@floating-ui/dom/-/dom-0.5.4.tgz" + resolved "https://registry.yarnpkg.com/@floating-ui/dom/-/dom-0.5.4.tgz#4eae73f78bcd4bd553ae2ade30e6f1f9c73fe3f1" integrity sha512-419BMceRLq0RrmTSDxn8hf9R3VCJv2K9PUfugh5JyEFmdjzDo+e8U5EdR8nzKq8Yj1htzLm3b6eQEEam3/rrtg== dependencies: "@floating-ui/core" "^0.7.3" "@floating-ui/react-dom@0.7.2": version "0.7.2" - resolved "https://registry.npmjs.org/@floating-ui/react-dom/-/react-dom-0.7.2.tgz" + resolved "https://registry.yarnpkg.com/@floating-ui/react-dom/-/react-dom-0.7.2.tgz#0bf4ceccb777a140fc535c87eb5d6241c8e89864" integrity sha512-1T0sJcpHgX/u4I1OzIEhlcrvkUN8ln39nz7fMoE/2HDHrPiMFoOGR7++GYyfUmIQHkkrTinaeQsO3XWubjSvGg== dependencies: "@floating-ui/dom" "^0.5.3" @@ -1174,17 +1180,17 @@ "@humanwhocodes/module-importer@^1.0.1": version "1.0.1" - resolved "https://registry.npmjs.org/@humanwhocodes/module-importer/-/module-importer-1.0.1.tgz" + resolved "https://registry.yarnpkg.com/@humanwhocodes/module-importer/-/module-importer-1.0.1.tgz#af5b2691a22b44be847b0ca81641c5fb6ad0172c" integrity sha512-bxveV4V8v5Yb4ncFTT3rPSgZBOpCkjfK0y4oVVVJwIuDVBRMDXrPyXRL988i5ap9m9bnyEEjWfm5WkBmtffLfA== "@humanwhocodes/object-schema@^1.2.1": version "1.2.1" - resolved "https://registry.npmjs.org/@humanwhocodes/object-schema/-/object-schema-1.2.1.tgz" + resolved "https://registry.yarnpkg.com/@humanwhocodes/object-schema/-/object-schema-1.2.1.tgz#b520529ec21d8e5945a1851dfd1c32e94e39ff45" integrity sha512-ZnQMnLV4e7hDlUvw8H+U8ASL02SS2Gn6+9Ac3wGGLIe7+je2AeAOxPY+izIPJDfFDb7eDjev0Us8MO1iFRN8hA== "@jridgewell/gen-mapping@^0.1.0": version "0.1.1" - resolved "https://registry.npmjs.org/@jridgewell/gen-mapping/-/gen-mapping-0.1.1.tgz" + resolved "https://registry.yarnpkg.com/@jridgewell/gen-mapping/-/gen-mapping-0.1.1.tgz#e5d2e450306a9491e3bd77e323e38d7aff315996" integrity sha512-sQXCasFk+U8lWYEe66WxRDOE9PjVz4vSM51fTu3Hw+ClTpUSQb718772vH3pyS5pShp6lvQM7SxgIDXXXmOX7w== dependencies: "@jridgewell/set-array" "^1.0.0" @@ -1192,7 +1198,7 @@ "@jridgewell/gen-mapping@^0.3.2": version "0.3.2" - resolved "https://registry.npmjs.org/@jridgewell/gen-mapping/-/gen-mapping-0.3.2.tgz" + resolved "https://registry.yarnpkg.com/@jridgewell/gen-mapping/-/gen-mapping-0.3.2.tgz#c1aedc61e853f2bb9f5dfe6d4442d3b565b253b9" integrity sha512-mh65xKQAzI6iBcFzwv28KVWSmCkdRBWoOh+bYQGW3+6OZvbbN3TqMGo5hqYxQniRcH9F2VZIoJCm4pa3BPDK/A== dependencies: "@jridgewell/set-array" "^1.0.1" @@ -1206,7 +1212,7 @@ "@jridgewell/set-array@^1.0.0", "@jridgewell/set-array@^1.0.1": version "1.1.2" - resolved "https://registry.npmjs.org/@jridgewell/set-array/-/set-array-1.1.2.tgz" + resolved "https://registry.yarnpkg.com/@jridgewell/set-array/-/set-array-1.1.2.tgz#7c6cf998d6d20b914c0a55a91ae928ff25965e72" integrity sha512-xnkseuNADM0gt2bs+BvhO0p78Mk762YnZdsuzFV018NoG1Sj1SCQvpSqa7XUaTam5vAGasABV9qXASMKnFMwMw== "@jridgewell/sourcemap-codec@1.4.14", "@jridgewell/sourcemap-codec@^1.4.10": @@ -1224,7 +1230,7 @@ "@motionone/animation@^10.13.1": version "10.14.0" - resolved "https://registry.npmjs.org/@motionone/animation/-/animation-10.14.0.tgz" + resolved "https://registry.yarnpkg.com/@motionone/animation/-/animation-10.14.0.tgz#2f2a3517183bb58d82e389aac777fe0850079de6" integrity sha512-h+1sdyBP8vbxEBW5gPFDnj+m2DCqdlAuf2g6Iafb1lcMnqjsRXWlPw1AXgvUMXmreyhqmPbJqoNfIKdytampRQ== dependencies: "@motionone/easing" "^10.14.0" @@ -1234,7 +1240,7 @@ "@motionone/dom@10.13.1": version "10.13.1" - resolved "https://registry.npmjs.org/@motionone/dom/-/dom-10.13.1.tgz" + resolved "https://registry.yarnpkg.com/@motionone/dom/-/dom-10.13.1.tgz#fc29ea5d12538f21b211b3168e502cfc07a24882" integrity sha512-zjfX+AGMIt/fIqd/SL1Lj93S6AiJsEA3oc5M9VkUr+Gz+juRmYN1vfvZd6MvEkSqEjwPQgcjN7rGZHrDB9APfQ== dependencies: "@motionone/animation" "^10.13.1" @@ -1246,7 +1252,7 @@ "@motionone/easing@^10.14.0": version "10.14.0" - resolved "https://registry.npmjs.org/@motionone/easing/-/easing-10.14.0.tgz" + resolved "https://registry.yarnpkg.com/@motionone/easing/-/easing-10.14.0.tgz#d8154b7f71491414f3cdee23bd3838d763fffd00" integrity sha512-2vUBdH9uWTlRbuErhcsMmt1jvMTTqvGmn9fHq8FleFDXBlHFs5jZzHJT9iw+4kR1h6a4SZQuCf72b9ji92qNYA== dependencies: "@motionone/utils" "^10.14.0" @@ -1254,7 +1260,7 @@ "@motionone/generators@^10.13.1": version "10.14.0" - resolved "https://registry.npmjs.org/@motionone/generators/-/generators-10.14.0.tgz" + resolved "https://registry.yarnpkg.com/@motionone/generators/-/generators-10.14.0.tgz#e05d9dd56da78a4b92db99185848a0f3db62242d" integrity sha512-6kRHezoFfIjFN7pPpaxmkdZXD36tQNcyJe3nwVqwJ+ZfC0e3rFmszR8kp9DEVFs9QL/akWjuGPSLBI1tvz+Vjg== dependencies: "@motionone/types" "^10.14.0" @@ -1263,12 +1269,12 @@ "@motionone/types@^10.13.0", "@motionone/types@^10.14.0": version "10.14.0" - resolved "https://registry.npmjs.org/@motionone/types/-/types-10.14.0.tgz" + resolved "https://registry.yarnpkg.com/@motionone/types/-/types-10.14.0.tgz#148c34f3270b175397e49c3058b33fab405c21e3" integrity sha512-3bNWyYBHtVd27KncnJLhksMFQ5o2MSdk1cA/IZqsHtA9DnRM1SYgN01CTcJ8Iw8pCXF5Ocp34tyAjY7WRpOJJQ== "@motionone/utils@^10.13.1", "@motionone/utils@^10.14.0": version "10.14.0" - resolved "https://registry.npmjs.org/@motionone/utils/-/utils-10.14.0.tgz" + resolved "https://registry.yarnpkg.com/@motionone/utils/-/utils-10.14.0.tgz#a19a3464ed35b08506747b062d035c7bc9bbe708" integrity sha512-sLWBLPzRqkxmOTRzSaD3LFQXCPHvDzyHJ1a3VP9PRzBxyVd2pv51/gMOsdAcxQ9n+MIeGJnxzXBYplUHKj4jkw== dependencies: "@motionone/types" "^10.14.0" @@ -1277,7 +1283,7 @@ "@nodelib/fs.scandir@2.1.5": version "2.1.5" - resolved "https://registry.npmjs.org/@nodelib/fs.scandir/-/fs.scandir-2.1.5.tgz" + resolved "https://registry.yarnpkg.com/@nodelib/fs.scandir/-/fs.scandir-2.1.5.tgz#7619c2eb21b25483f6d167548b4cfd5a7488c3d5" integrity sha512-vq24Bq3ym5HEQm2NKCr3yXDwjc7vTsEThRDnkp2DK9p1uqLR+DHurm/NOTo0KG7HYHU7eppKZj3MyqYuMBf62g== dependencies: "@nodelib/fs.stat" "2.0.5" @@ -1285,7 +1291,7 @@ "@nodelib/fs.stat@2.0.5", "@nodelib/fs.stat@^2.0.2": version "2.0.5" - resolved "https://registry.npmjs.org/@nodelib/fs.stat/-/fs.stat-2.0.5.tgz" + resolved "https://registry.yarnpkg.com/@nodelib/fs.stat/-/fs.stat-2.0.5.tgz#5bd262af94e9d25bd1e71b05deed44876a222e8b" integrity sha512-RkhPPp2zrqDAQA/2jNhnztcPAlv64XdhIp7a7454A5ovI7Bukxgt7MX7udwAu3zg1DcpPU0rz3VV1SeaqvY4+A== "@nodelib/fs.walk@^1.2.3", "@nodelib/fs.walk@^1.2.8": @@ -1298,26 +1304,26 @@ "@popperjs/core@^2.9.3": version "2.11.6" - resolved "https://registry.npmjs.org/@popperjs/core/-/core-2.11.6.tgz" + resolved "https://registry.yarnpkg.com/@popperjs/core/-/core-2.11.6.tgz#cee20bd55e68a1720bdab363ecf0c821ded4cd45" integrity sha512-50/17A98tWUfQ176raKiOGXuYpLyyVMkxxG6oylzL3BPOlA6ADGdK7EYunSa4I064xerltq9TGXs8HmOk5E+vw== "@radix-ui/number@1.0.0": version "1.0.0" - resolved "https://registry.npmjs.org/@radix-ui/number/-/number-1.0.0.tgz" + resolved "https://registry.yarnpkg.com/@radix-ui/number/-/number-1.0.0.tgz#4c536161d0de750b3f5d55860fc3de46264f897b" integrity sha512-Ofwh/1HX69ZfJRiRBMTy7rgjAzHmwe4kW9C9Y99HTRUcYLUuVT0KESFj15rPjRgKJs20GPq8Bm5aEDJ8DuA3vA== dependencies: "@babel/runtime" "^7.13.10" "@radix-ui/primitive@1.0.0": version "1.0.0" - resolved "https://registry.npmjs.org/@radix-ui/primitive/-/primitive-1.0.0.tgz" + resolved "https://registry.yarnpkg.com/@radix-ui/primitive/-/primitive-1.0.0.tgz#e1d8ef30b10ea10e69c76e896f608d9276352253" integrity sha512-3e7rn8FDMin4CgeL7Z/49smCA3rFYY3Ha2rUQ7HRWFadS5iCRw08ZgVT1LaNTCNqgvrUiyczLflrVrF0SRQtNA== dependencies: "@babel/runtime" "^7.13.10" "@radix-ui/react-arrow@1.0.1": version "1.0.1" - resolved "https://registry.npmjs.org/@radix-ui/react-arrow/-/react-arrow-1.0.1.tgz" + resolved "https://registry.yarnpkg.com/@radix-ui/react-arrow/-/react-arrow-1.0.1.tgz#5246adf79e97f89e819af68da51ddcf349ecf1c4" integrity sha512-1yientwXqXcErDHEv8av9ZVNEBldH8L9scVR3is20lL+jOCfcJyMFZFEY5cgIrgexsq1qggSXqiEL/d/4f+QXA== dependencies: "@babel/runtime" "^7.13.10" @@ -1325,7 +1331,7 @@ "@radix-ui/react-collection@1.0.1": version "1.0.1" - resolved "https://registry.npmjs.org/@radix-ui/react-collection/-/react-collection-1.0.1.tgz" + resolved "https://registry.yarnpkg.com/@radix-ui/react-collection/-/react-collection-1.0.1.tgz#259506f97c6703b36291826768d3c1337edd1de5" integrity sha512-uuiFbs+YCKjn3X1DTSx9G7BHApu4GHbi3kgiwsnFUbOKCrwejAJv4eE4Vc8C0Oaxt9T0aV4ox0WCOdx+39Xo+g== dependencies: "@babel/runtime" "^7.13.10" @@ -1336,14 +1342,14 @@ "@radix-ui/react-compose-refs@1.0.0": version "1.0.0" - resolved "https://registry.npmjs.org/@radix-ui/react-compose-refs/-/react-compose-refs-1.0.0.tgz" + resolved "https://registry.yarnpkg.com/@radix-ui/react-compose-refs/-/react-compose-refs-1.0.0.tgz#37595b1f16ec7f228d698590e78eeed18ff218ae" integrity sha512-0KaSv6sx787/hK3eF53iOkiSLwAGlFMx5lotrqD2pTjB18KbybKoEIgkNZTKC60YECDQTKGTRcDBILwZVqVKvA== dependencies: "@babel/runtime" "^7.13.10" "@radix-ui/react-context-menu@^2.0.1": version "2.0.1" - resolved "https://registry.npmjs.org/@radix-ui/react-context-menu/-/react-context-menu-2.0.1.tgz" + resolved "https://registry.yarnpkg.com/@radix-ui/react-context-menu/-/react-context-menu-2.0.1.tgz#aee7c81bac9983b3748284bf3925dd63796c90b4" integrity sha512-7DuhU4xDcUk3AMJUlb5tHHOvJZ1GF4+snDIpjtWGlTvO0VktNKgbvBuGLlirdkYoUSI0mJXwOUcUXQapgIyefw== dependencies: "@babel/runtime" "^7.13.10" @@ -1356,21 +1362,21 @@ "@radix-ui/react-context@1.0.0": version "1.0.0" - resolved "https://registry.npmjs.org/@radix-ui/react-context/-/react-context-1.0.0.tgz" + resolved "https://registry.yarnpkg.com/@radix-ui/react-context/-/react-context-1.0.0.tgz#f38e30c5859a9fb5e9aa9a9da452ee3ed9e0aee0" integrity sha512-1pVM9RfOQ+n/N5PJK33kRSKsr1glNxomxONs5c49MliinBY6Yw2Q995qfBUUo0/Mbg05B/sGA0gkgPI7kmSHBg== dependencies: "@babel/runtime" "^7.13.10" "@radix-ui/react-direction@1.0.0": version "1.0.0" - resolved "https://registry.npmjs.org/@radix-ui/react-direction/-/react-direction-1.0.0.tgz" + resolved "https://registry.yarnpkg.com/@radix-ui/react-direction/-/react-direction-1.0.0.tgz#a2e0b552352459ecf96342c79949dd833c1e6e45" integrity sha512-2HV05lGUgYcA6xgLQ4BKPDmtL+QbIZYH5fCOTAOOcJ5O0QbWS3i9lKaurLzliYUDhORI2Qr3pyjhJh44lKA3rQ== dependencies: "@babel/runtime" "^7.13.10" "@radix-ui/react-dismissable-layer@1.0.2": version "1.0.2" - resolved "https://registry.npmjs.org/@radix-ui/react-dismissable-layer/-/react-dismissable-layer-1.0.2.tgz" + resolved "https://registry.yarnpkg.com/@radix-ui/react-dismissable-layer/-/react-dismissable-layer-1.0.2.tgz#f04d1061bddf00b1ca304148516b9ddc62e45fb2" integrity sha512-WjJzMrTWROozDqLB0uRWYvj4UuXsM/2L19EmQ3Au+IJWqwvwq9Bwd+P8ivo0Deg9JDPArR1I6MbWNi1CmXsskg== dependencies: "@babel/runtime" "^7.13.10" @@ -1382,14 +1388,14 @@ "@radix-ui/react-focus-guards@1.0.0": version "1.0.0" - resolved "https://registry.npmjs.org/@radix-ui/react-focus-guards/-/react-focus-guards-1.0.0.tgz" + resolved "https://registry.yarnpkg.com/@radix-ui/react-focus-guards/-/react-focus-guards-1.0.0.tgz#339c1c69c41628c1a5e655f15f7020bf11aa01fa" integrity sha512-UagjDk4ijOAnGu4WMUPj9ahi7/zJJqNZ9ZAiGPp7waUWJO0O1aWXi/udPphI0IUjvrhBsZJGSN66dR2dsueLWQ== dependencies: "@babel/runtime" "^7.13.10" "@radix-ui/react-focus-scope@1.0.1": version "1.0.1" - resolved "https://registry.npmjs.org/@radix-ui/react-focus-scope/-/react-focus-scope-1.0.1.tgz" + resolved "https://registry.yarnpkg.com/@radix-ui/react-focus-scope/-/react-focus-scope-1.0.1.tgz#faea8c25f537c5a5c38c50914b63722db0e7f951" integrity sha512-Ej2MQTit8IWJiS2uuujGUmxXjF/y5xZptIIQnyd2JHLwtV0R2j9NRVoRj/1j/gJ7e3REdaBw4Hjf4a1ImhkZcQ== dependencies: "@babel/runtime" "^7.13.10" @@ -1399,7 +1405,7 @@ "@radix-ui/react-id@1.0.0": version "1.0.0" - resolved "https://registry.npmjs.org/@radix-ui/react-id/-/react-id-1.0.0.tgz" + resolved "https://registry.yarnpkg.com/@radix-ui/react-id/-/react-id-1.0.0.tgz#8d43224910741870a45a8c9d092f25887bb6d11e" integrity sha512-Q6iAB/U7Tq3NTolBBQbHTgclPmGWE3OlktGGqrClPozSw4vkQ1DfQAOtzgRPecKsMdJINE05iaoDUG8tRzCBjw== dependencies: "@babel/runtime" "^7.13.10" @@ -1407,7 +1413,7 @@ "@radix-ui/react-menu@2.0.1": version "2.0.1" - resolved "https://registry.npmjs.org/@radix-ui/react-menu/-/react-menu-2.0.1.tgz" + resolved "https://registry.yarnpkg.com/@radix-ui/react-menu/-/react-menu-2.0.1.tgz#44ebfd45d8482db678b935c0b9d1102d683372d8" integrity sha512-I5FFZQxCl2fHoJ7R0m5/oWA9EX8/ttH4AbgneoCH7DAXQioFeb0XMAYnOVSp1GgJZ1Nx/mohxNQSeTMcaF1YPw== dependencies: "@babel/runtime" "^7.13.10" @@ -1432,7 +1438,7 @@ "@radix-ui/react-popper@1.0.1": version "1.0.1" - resolved "https://registry.npmjs.org/@radix-ui/react-popper/-/react-popper-1.0.1.tgz" + resolved "https://registry.yarnpkg.com/@radix-ui/react-popper/-/react-popper-1.0.1.tgz#9fa8a6a493404afa225866a5cd75af23d141baa0" integrity sha512-J4Vj7k3k+EHNWgcKrE+BLlQfpewxA7Zd76h5I0bIa+/EqaIZ3DuwrbPj49O3wqN+STnXsBuxiHLiF0iU3yfovw== dependencies: "@babel/runtime" "^7.13.10" @@ -1448,7 +1454,7 @@ "@radix-ui/react-portal@1.0.1": version "1.0.1" - resolved "https://registry.npmjs.org/@radix-ui/react-portal/-/react-portal-1.0.1.tgz" + resolved "https://registry.yarnpkg.com/@radix-ui/react-portal/-/react-portal-1.0.1.tgz#169c5a50719c2bb0079cf4c91a27aa6d37e5dd33" integrity sha512-NY2vUWI5WENgAT1nfC6JS7RU5xRYBfjZVLq0HmgEN1Ezy3rk/UruMV4+Rd0F40PEaFC5SrLS1ixYvcYIQrb4Ig== dependencies: "@babel/runtime" "^7.13.10" @@ -1456,7 +1462,7 @@ "@radix-ui/react-presence@1.0.0": version "1.0.0" - resolved "https://registry.npmjs.org/@radix-ui/react-presence/-/react-presence-1.0.0.tgz" + resolved "https://registry.yarnpkg.com/@radix-ui/react-presence/-/react-presence-1.0.0.tgz#814fe46df11f9a468808a6010e3f3ca7e0b2e84a" integrity sha512-A+6XEvN01NfVWiKu38ybawfHsBjWum42MRPnEuqPsBZ4eV7e/7K321B5VgYMPv3Xx5An6o1/l9ZuDBgmcmWK3w== dependencies: "@babel/runtime" "^7.13.10" @@ -1465,7 +1471,7 @@ "@radix-ui/react-primitive@1.0.1": version "1.0.1" - resolved "https://registry.npmjs.org/@radix-ui/react-primitive/-/react-primitive-1.0.1.tgz" + resolved "https://registry.yarnpkg.com/@radix-ui/react-primitive/-/react-primitive-1.0.1.tgz#c1ebcce283dd2f02e4fbefdaa49d1cb13dbc990a" integrity sha512-fHbmislWVkZaIdeF6GZxF0A/NH/3BjrGIYj+Ae6eTmTCr7EB0RQAAVEiqsXK6p3/JcRqVSBQoceZroj30Jj3XA== dependencies: "@babel/runtime" "^7.13.10" @@ -1473,7 +1479,7 @@ "@radix-ui/react-roving-focus@1.0.1": version "1.0.1" - resolved "https://registry.npmjs.org/@radix-ui/react-roving-focus/-/react-roving-focus-1.0.1.tgz" + resolved "https://registry.yarnpkg.com/@radix-ui/react-roving-focus/-/react-roving-focus-1.0.1.tgz#475621f63aee43faa183a5270f35d49e530de3d7" integrity sha512-TB76u5TIxKpqMpUAuYH2VqMhHYKa+4Vs1NHygo/llLvlffN6mLVsFhz0AnSFlSBAvTBYVHYAkHAyEt7x1gPJOA== dependencies: "@babel/runtime" "^7.13.10" @@ -1489,7 +1495,7 @@ "@radix-ui/react-slider@^1.1.0": version "1.1.0" - resolved "https://registry.npmjs.org/@radix-ui/react-slider/-/react-slider-1.1.0.tgz" + resolved "https://registry.yarnpkg.com/@radix-ui/react-slider/-/react-slider-1.1.0.tgz#b3fdaca27619150e9e6067ad9f979a4535f68d5e" integrity sha512-5H/QB4xD3GF9UfoSCVLBx2JjlXamMcmTyL6gr4kkd/MiAGaYB0W7Exi4MQa0tJApBFJe+KmS5InKCI56p2kmjA== dependencies: "@babel/runtime" "^7.13.10" @@ -1507,7 +1513,7 @@ "@radix-ui/react-slot@1.0.1": version "1.0.1" - resolved "https://registry.npmjs.org/@radix-ui/react-slot/-/react-slot-1.0.1.tgz" + resolved "https://registry.yarnpkg.com/@radix-ui/react-slot/-/react-slot-1.0.1.tgz#e7868c669c974d649070e9ecbec0b367ee0b4d81" integrity sha512-avutXAFL1ehGvAXtPquu0YK5oz6ctS474iM3vNGQIkswrVhdrS52e3uoMQBzZhNRAIE0jBnUyXWNmSjGHhCFcw== dependencies: "@babel/runtime" "^7.13.10" @@ -1515,7 +1521,7 @@ "@radix-ui/react-tooltip@^1.0.2": version "1.0.2" - resolved "https://registry.npmjs.org/@radix-ui/react-tooltip/-/react-tooltip-1.0.2.tgz" + resolved "https://registry.yarnpkg.com/@radix-ui/react-tooltip/-/react-tooltip-1.0.2.tgz#8e10b075767f785bf013146fdc954ac6885efda3" integrity sha512-11gUlok2rv5mu+KBtxniOKKNKjqC/uTbgFHWoQdbF46vMV+zjDaBvCtVDK9+MTddlpmlisGPGvvojX7Qm0yr+g== dependencies: "@babel/runtime" "^7.13.10" @@ -1534,14 +1540,14 @@ "@radix-ui/react-use-callback-ref@1.0.0": version "1.0.0" - resolved "https://registry.npmjs.org/@radix-ui/react-use-callback-ref/-/react-use-callback-ref-1.0.0.tgz" + resolved "https://registry.yarnpkg.com/@radix-ui/react-use-callback-ref/-/react-use-callback-ref-1.0.0.tgz#9e7b8b6b4946fe3cbe8f748c82a2cce54e7b6a90" integrity sha512-GZtyzoHz95Rhs6S63D2t/eqvdFCm7I+yHMLVQheKM7nBD8mbZIt+ct1jz4536MDnaOGKIxynJ8eHTkVGVVkoTg== dependencies: "@babel/runtime" "^7.13.10" "@radix-ui/react-use-controllable-state@1.0.0": version "1.0.0" - resolved "https://registry.npmjs.org/@radix-ui/react-use-controllable-state/-/react-use-controllable-state-1.0.0.tgz" + resolved "https://registry.yarnpkg.com/@radix-ui/react-use-controllable-state/-/react-use-controllable-state-1.0.0.tgz#a64deaafbbc52d5d407afaa22d493d687c538b7f" integrity sha512-FohDoZvk3mEXh9AWAVyRTYR4Sq7/gavuofglmiXB2g1aKyboUD4YtgWxKj8O5n+Uak52gXQ4wKz5IFST4vtJHg== dependencies: "@babel/runtime" "^7.13.10" @@ -1549,7 +1555,7 @@ "@radix-ui/react-use-escape-keydown@1.0.2": version "1.0.2" - resolved "https://registry.npmjs.org/@radix-ui/react-use-escape-keydown/-/react-use-escape-keydown-1.0.2.tgz" + resolved "https://registry.yarnpkg.com/@radix-ui/react-use-escape-keydown/-/react-use-escape-keydown-1.0.2.tgz#09ab6455ab240b4f0a61faf06d4e5132c4d639f6" integrity sha512-DXGim3x74WgUv+iMNCF+cAo8xUHHeqvjx8zs7trKf+FkQKPQXLk2sX7Gx1ysH7Q76xCpZuxIJE7HLPxRE+Q+GA== dependencies: "@babel/runtime" "^7.13.10" @@ -1557,21 +1563,21 @@ "@radix-ui/react-use-layout-effect@1.0.0": version "1.0.0" - resolved "https://registry.npmjs.org/@radix-ui/react-use-layout-effect/-/react-use-layout-effect-1.0.0.tgz" + resolved "https://registry.yarnpkg.com/@radix-ui/react-use-layout-effect/-/react-use-layout-effect-1.0.0.tgz#2fc19e97223a81de64cd3ba1dc42ceffd82374dc" integrity sha512-6Tpkq+R6LOlmQb1R5NNETLG0B4YP0wc+klfXafpUCj6JGyaUc8il7/kUZ7m59rGbXGczE9Bs+iz2qloqsZBduQ== dependencies: "@babel/runtime" "^7.13.10" "@radix-ui/react-use-previous@1.0.0": version "1.0.0" - resolved "https://registry.npmjs.org/@radix-ui/react-use-previous/-/react-use-previous-1.0.0.tgz" + resolved "https://registry.yarnpkg.com/@radix-ui/react-use-previous/-/react-use-previous-1.0.0.tgz#e48a69c3a7d8078a967084038df66d0d181c56ac" integrity sha512-RG2K8z/K7InnOKpq6YLDmT49HGjNmrK+fr82UCVKT2sW0GYfVnYp4wZWBooT/EYfQ5faA9uIjvsuMMhH61rheg== dependencies: "@babel/runtime" "^7.13.10" "@radix-ui/react-use-rect@1.0.0": version "1.0.0" - resolved "https://registry.npmjs.org/@radix-ui/react-use-rect/-/react-use-rect-1.0.0.tgz" + resolved "https://registry.yarnpkg.com/@radix-ui/react-use-rect/-/react-use-rect-1.0.0.tgz#b040cc88a4906b78696cd3a32b075ed5b1423b3e" integrity sha512-TB7pID8NRMEHxb/qQJpvSt3hQU4sqNPM1VCTjTRjEOa7cEop/QMuq8S6fb/5Tsz64kqSvB9WnwsDHtjnrM9qew== dependencies: "@babel/runtime" "^7.13.10" @@ -1579,7 +1585,7 @@ "@radix-ui/react-use-size@1.0.0": version "1.0.0" - resolved "https://registry.npmjs.org/@radix-ui/react-use-size/-/react-use-size-1.0.0.tgz" + resolved "https://registry.yarnpkg.com/@radix-ui/react-use-size/-/react-use-size-1.0.0.tgz#a0b455ac826749419f6354dc733e2ca465054771" integrity sha512-imZ3aYcoYCKhhgNpkNDh/aTiU05qw9hX+HHI1QDBTyIlcFjgeFlKKySNGMwTp7nYFLQg/j0VA2FmCY4WPDDHMg== dependencies: "@babel/runtime" "^7.13.10" @@ -1587,7 +1593,7 @@ "@radix-ui/react-visually-hidden@1.0.1": version "1.0.1" - resolved "https://registry.npmjs.org/@radix-ui/react-visually-hidden/-/react-visually-hidden-1.0.1.tgz" + resolved "https://registry.yarnpkg.com/@radix-ui/react-visually-hidden/-/react-visually-hidden-1.0.1.tgz#9a4ac4fc97ae8d72a10e727f16b3121b5f0aa469" integrity sha512-K1hJcCMfWfiYUibRqf3V8r5Drpyf7rh44jnrwAbdvI5iCCijilBBeyQv9SKidYNZIopMdCyR9FnIjkHxHN0FcQ== dependencies: "@babel/runtime" "^7.13.10" @@ -1595,24 +1601,24 @@ "@radix-ui/rect@1.0.0": version "1.0.0" - resolved "https://registry.npmjs.org/@radix-ui/rect/-/rect-1.0.0.tgz" + resolved "https://registry.yarnpkg.com/@radix-ui/rect/-/rect-1.0.0.tgz#0dc8e6a829ea2828d53cbc94b81793ba6383bf3c" integrity sha512-d0O68AYy/9oeEy1DdC07bz1/ZXX+DqCskRd3i4JzLSTXwefzaepQrKjXC7aNM8lTHjFLDO0pDgaEiQ7jEk+HVg== dependencies: "@babel/runtime" "^7.13.10" "@reduxjs/toolkit@^1.8.5": - version "1.8.6" - resolved "https://registry.yarnpkg.com/@reduxjs/toolkit/-/toolkit-1.8.6.tgz#147fb7957befcdb75bc9c1230db63628e30e4332" - integrity sha512-4Ia/Loc6WLmdSOzi7k5ff7dLK8CgG2b8aqpLsCAJhazAzGdp//YBUSaj0ceW6a3kDBDNRrq5CRwyCS0wBiL1ig== + version "1.9.0" + resolved "https://registry.yarnpkg.com/@reduxjs/toolkit/-/toolkit-1.9.0.tgz#76b264fcea677d256b18f86cc77e00743a9e02b0" + integrity sha512-ak11IrjYcUXRqlhNPwnz6AcvA2ynJTu8PzDbbqQw4a3xR4KZtgiqbNblQD+10CRbfK4+5C79SOyxnT9dhBqFnA== dependencies: - immer "^9.0.7" - redux "^4.1.2" - redux-thunk "^2.4.1" - reselect "^4.1.5" + immer "^9.0.16" + redux "^4.2.0" + redux-thunk "^2.4.2" + reselect "^4.1.7" "@rollup/pluginutils@^4.2.1": version "4.2.1" - resolved "https://registry.npmjs.org/@rollup/pluginutils/-/pluginutils-4.2.1.tgz" + resolved "https://registry.yarnpkg.com/@rollup/pluginutils/-/pluginutils-4.2.1.tgz#e6c6c3aba0744edce3fb2074922d3776c0af2a6d" integrity sha512-iKnFXr7NkdZAIHiIWE+BX5ULi/ucVFYWD6TbAV+rZctiRTY2PL6tsIKhoIOaoskiWAkgu+VsbXgUVDNLHf+InQ== dependencies: estree-walker "^2.0.1" @@ -1620,40 +1626,40 @@ "@socket.io/component-emitter@~3.1.0": version "3.1.0" - resolved "https://registry.npmjs.org/@socket.io/component-emitter/-/component-emitter-3.1.0.tgz" + resolved "https://registry.yarnpkg.com/@socket.io/component-emitter/-/component-emitter-3.1.0.tgz#96116f2a912e0c02817345b3c10751069920d553" integrity sha512-+9jVqKhRSpsc591z5vX+X5Yyw+he/HCB4iQ/RYxw35CEPaY1gnsNE43nf9n9AaYjAQrTiI/mOwKUKdUs9vf7Xg== "@types/cookie@^0.4.1": version "0.4.1" - resolved "https://registry.npmjs.org/@types/cookie/-/cookie-0.4.1.tgz" + resolved "https://registry.yarnpkg.com/@types/cookie/-/cookie-0.4.1.tgz#bfd02c1f2224567676c1545199f87c3a861d878d" integrity sha512-XW/Aa8APYr6jSVVA1y/DEIZX0/GMKLEVekNG727R8cs56ahETkRAy/3DR7+fJyh7oUgGwNQaRfXCun0+KbWY7Q== "@types/cors@^2.8.12": version "2.8.12" - resolved "https://registry.npmjs.org/@types/cors/-/cors-2.8.12.tgz" + resolved "https://registry.yarnpkg.com/@types/cors/-/cors-2.8.12.tgz#6b2c510a7ad7039e98e7b8d3d6598f4359e5c080" integrity sha512-vt+kDhq/M2ayberEtJcIN/hxXy1Pk+59g2FV/ZQceeaTyCtCucjL2Q7FXlFjtWn4n15KCr1NE2lNNFhp0lEThw== "@types/dateformat@^5.0.0": version "5.0.0" - resolved "https://registry.npmjs.org/@types/dateformat/-/dateformat-5.0.0.tgz" + resolved "https://registry.yarnpkg.com/@types/dateformat/-/dateformat-5.0.0.tgz#17ce64b0318f3f36d1c830c58a7a915445f1f93d" integrity sha512-SZg4JdHIWHQGEokbYGZSDvo5wA4TLYPXaqhigs/wH+REDOejcJzgH+qyY+HtEUtWOZxEUkbhbdYPqQDiEgrXeA== "@types/eslint@^8.4.5": - version "8.4.9" - resolved "https://registry.yarnpkg.com/@types/eslint/-/eslint-8.4.9.tgz#f7371980148697f4b582b086630319b55324b5aa" - integrity sha512-jFCSo4wJzlHQLCpceUhUnXdrPuCNOjGFMQ8Eg6JXxlz3QaCKOb7eGi2cephQdM4XTYsNej69P9JDJ1zqNIbncQ== + version "8.4.10" + resolved "https://registry.yarnpkg.com/@types/eslint/-/eslint-8.4.10.tgz#19731b9685c19ed1552da7052b6f668ed7eb64bb" + integrity sha512-Sl/HOqN8NKPmhWo2VBEPm0nvHnu2LL3v9vKo8MEq0EtbJ4eVzGPl41VNPvn5E1i5poMk4/XD8UriLHpJvEP/Nw== dependencies: "@types/estree" "*" "@types/json-schema" "*" "@types/estree@*": version "1.0.0" - resolved "https://registry.npmjs.org/@types/estree/-/estree-1.0.0.tgz" + resolved "https://registry.yarnpkg.com/@types/estree/-/estree-1.0.0.tgz#5fb2e536c1ae9bf35366eed879e827fa59ca41c2" integrity sha512-WulqXMDUTYAXCjZnk6JtIHPigp55cVtDgDrO2gHRwhyJto21+1zbVCtOYB2L1F9w4qCQ0rOGWBnBe0FNTiEJIQ== "@types/hoist-non-react-statics@^3.3.1": version "3.3.1" - resolved "https://registry.npmjs.org/@types/hoist-non-react-statics/-/hoist-non-react-statics-3.3.1.tgz" + resolved "https://registry.yarnpkg.com/@types/hoist-non-react-statics/-/hoist-non-react-statics-3.3.1.tgz#1124aafe5118cb591977aeb1ceaaed1070eb039f" integrity sha512-iMIqiko6ooLrTh1joXodJK5X9xeEALT1kM5G3ZLhD3hszxBdIEd5C75U834D9mLcINgD4OyZf5uQXjkuYydWvA== dependencies: "@types/react" "*" @@ -1661,34 +1667,34 @@ "@types/json-schema@*", "@types/json-schema@^7.0.9": version "7.0.11" - resolved "https://registry.npmjs.org/@types/json-schema/-/json-schema-7.0.11.tgz" + resolved "https://registry.yarnpkg.com/@types/json-schema/-/json-schema-7.0.11.tgz#d421b6c527a3037f7c84433fd2c4229e016863d3" integrity sha512-wOuvG1SN4Us4rez+tylwwwCV1psiNVOkJeM3AUWUNWg/jDQY2+HE/444y5gc+jBmRqASOm2Oeh5c1axHobwRKQ== "@types/lodash.mergewith@4.6.6": version "4.6.6" - resolved "https://registry.npmjs.org/@types/lodash.mergewith/-/lodash.mergewith-4.6.6.tgz" + resolved "https://registry.yarnpkg.com/@types/lodash.mergewith/-/lodash.mergewith-4.6.6.tgz#c4698f5b214a433ff35cb2c75ee6ec7f99d79f10" integrity sha512-RY/8IaVENjG19rxTZu9Nukqh0W2UrYgmBj5sdns4hWRZaV8PqR7wIKHFKzvOTjo4zVRV7sVI+yFhAJql12Kfqg== dependencies: "@types/lodash" "*" "@types/lodash@*": - version "4.14.186" - resolved "https://registry.yarnpkg.com/@types/lodash/-/lodash-4.14.186.tgz#862e5514dd7bd66ada6c70ee5fce844b06c8ee97" - integrity sha512-eHcVlLXP0c2FlMPm56ITode2AgLMSa6aJ05JTTbYbI+7EMkCEE5qk2E41d5g2lCVTqRe0GnnRFurmlCsDODrPw== + version "4.14.188" + resolved "https://registry.yarnpkg.com/@types/lodash/-/lodash-4.14.188.tgz#e4990c4c81f7c9b00c5ff8eae389c10f27980da5" + integrity sha512-zmEmF5OIM3rb7SbLCFYoQhO4dGt2FRM9AMkxvA3LaADOF1n8in/zGJlWji9fmafLoNyz+FoL6FE0SLtGIArD7w== "@types/node@>=10.0.0": - version "18.11.8" - resolved "https://registry.yarnpkg.com/@types/node/-/node-18.11.8.tgz#16d222a58d4363a2a359656dd20b28414de5d265" - integrity sha512-uGwPWlE0Hj972KkHtCDVwZ8O39GmyjfMane1Z3GUBGGnkZ2USDq7SxLpVIiIHpweY9DS0QTDH0Nw7RNBsAAZ5A== + version "18.11.9" + resolved "https://registry.yarnpkg.com/@types/node/-/node-18.11.9.tgz#02d013de7058cea16d36168ef2fc653464cfbad4" + integrity sha512-CRpX21/kGdzjOpFsZSkcrXMGIBWMGNIHXXBVFSH+ggkftxg+XYP20TESbh+zFvFj3EQOl5byk0HTRn1IL6hbqg== "@types/parse-json@^4.0.0": version "4.0.0" - resolved "https://registry.npmjs.org/@types/parse-json/-/parse-json-4.0.0.tgz" + resolved "https://registry.yarnpkg.com/@types/parse-json/-/parse-json-4.0.0.tgz#2f8bb441434d163b35fb8ffdccd7138927ffb8c0" integrity sha512-//oorEZjL6sbPcKUaCdIGlIUeH26mgzimjBB77G6XRgnDl/L5wOnpyBGRe/Mmf5CVW3PwEBE1NjiMZ/ssFh4wA== "@types/prop-types@*": version "15.7.5" - resolved "https://registry.npmjs.org/@types/prop-types/-/prop-types-15.7.5.tgz" + resolved "https://registry.yarnpkg.com/@types/prop-types/-/prop-types-15.7.5.tgz#5f19d2b85a98e9558036f6a3cacc8819420f05cf" integrity sha512-JCB8C6SnDoQf0cNycqd/35A7MjcnK+ZTqE7judS6o7utxUCg6imJg3QK2qzHKszlTjcj2cn+NwMB2i96ubpj7w== "@types/react-dom@^18.0.6": @@ -1700,22 +1706,22 @@ "@types/react-reconciler@^0.28.0": version "0.28.0" - resolved "https://registry.npmjs.org/@types/react-reconciler/-/react-reconciler-0.28.0.tgz" + resolved "https://registry.yarnpkg.com/@types/react-reconciler/-/react-reconciler-0.28.0.tgz#513acbed173140e958c909041ca14eb40412077f" integrity sha512-5cjk9ottZAj7eaTsqzPUIlrVbh3hBAO2YaEL1rkjHKB3xNAId7oU8GhzvAX+gfmlfoxTwJnBjPxEHyxkEA1Ffg== dependencies: "@types/react" "*" "@types/react-transition-group@^4.4.5": version "4.4.5" - resolved "https://registry.npmjs.org/@types/react-transition-group/-/react-transition-group-4.4.5.tgz" + resolved "https://registry.yarnpkg.com/@types/react-transition-group/-/react-transition-group-4.4.5.tgz#aae20dcf773c5aa275d5b9f7cdbca638abc5e416" integrity sha512-juKD/eiSM3/xZYzjuzH6ZwpP+/lejltmiS3QEzV/vmb/Q8+HfDmxu+Baga8UEMGBqV88Nbg4l2hY/K2DkyaLLA== dependencies: "@types/react" "*" "@types/react@*", "@types/react@^18.0.17": - version "18.0.24" - resolved "https://registry.yarnpkg.com/@types/react/-/react-18.0.24.tgz#2f79ed5b27f08d05107aab45c17919754cc44c20" - integrity sha512-wRJWT6ouziGUy+9uX0aW4YOJxAY0bG6/AOk5AW5QSvZqI7dk6VBIbXvcVgIw/W5Jrl24f77df98GEKTJGOLx7Q== + version "18.0.25" + resolved "https://registry.yarnpkg.com/@types/react/-/react-18.0.25.tgz#8b1dcd7e56fe7315535a4af25435e0bb55c8ae44" + integrity sha512-xD6c0KDT4m7n9uD4ZHi02lzskaiqcBxf4zi+tXZY98a04wvc0hi/TcCPC2FOESZi51Nd7tlUeOJY8RofL799/g== dependencies: "@types/prop-types" "*" "@types/scheduler" "*" @@ -1723,7 +1729,7 @@ "@types/scheduler@*": version "0.16.2" - resolved "https://registry.npmjs.org/@types/scheduler/-/scheduler-0.16.2.tgz" + resolved "https://registry.yarnpkg.com/@types/scheduler/-/scheduler-0.16.2.tgz#1a62f89525723dde24ba1b01b092bf5df8ad4d39" integrity sha512-hppQEBDmlwhFAXKJX2KnWLYu5yMfi91yazPb2l+lbJiwW+wdo1gNeRA+3RgNSO39WYX2euey41KEwnqesU2Jew== "@types/semver@^7.3.12": @@ -1733,12 +1739,12 @@ "@types/use-sync-external-store@^0.0.3": version "0.0.3" - resolved "https://registry.npmjs.org/@types/use-sync-external-store/-/use-sync-external-store-0.0.3.tgz" + resolved "https://registry.yarnpkg.com/@types/use-sync-external-store/-/use-sync-external-store-0.0.3.tgz#b6725d5f4af24ace33b36fafd295136e75509f43" integrity sha512-EwmlvuaxPNej9+T4v5AuBPJa2x2UOJVdjCtDHgcDqitUeOtjnJKJ+apYjVcAoBEMjKW1VVFGZLUb5+qqa09XFA== "@types/uuid@^8.3.4": version "8.3.4" - resolved "https://registry.npmjs.org/@types/uuid/-/uuid-8.3.4.tgz" + resolved "https://registry.yarnpkg.com/@types/uuid/-/uuid-8.3.4.tgz#bd86a43617df0594787d38b735f55c805becf1bc" integrity sha512-c/I8ZRb51j+pYGAu5CrFMRxqZ2ke4y2grEBO5AUjgSkSk+qT2Ea+OdWElz/OiMf5MNpn2b17kuVBwZLQJXzihw== "@typescript-eslint/eslint-plugin@^5.36.2": @@ -1839,17 +1845,17 @@ "@zag-js/element-size@0.1.0": version "0.1.0" - resolved "https://registry.npmjs.org/@zag-js/element-size/-/element-size-0.1.0.tgz" + resolved "https://registry.yarnpkg.com/@zag-js/element-size/-/element-size-0.1.0.tgz#dfdb3f66a70328d0c3149aae29b8f99c10590c22" integrity sha512-QF8wp0+V8++z+FHXiIw93+zudtubYszOtYbNgK39fg3pi+nCZtuSm4L1jC5QZMatNZ83MfOzyNCfgUubapagJQ== "@zag-js/focus-visible@0.1.0": version "0.1.0" - resolved "https://registry.npmjs.org/@zag-js/focus-visible/-/focus-visible-0.1.0.tgz" + resolved "https://registry.yarnpkg.com/@zag-js/focus-visible/-/focus-visible-0.1.0.tgz#9777bbaff8316d0b3a14a9095631e1494f69dbc7" integrity sha512-PeaBcTmdZWcFf7n1aM+oiOdZc+sy14qi0emPIeUuGMTjbP0xLGrZu43kdpHnWSXy7/r4Ubp/vlg50MCV8+9Isg== accepts@~1.3.4: version "1.3.8" - resolved "https://registry.npmjs.org/accepts/-/accepts-1.3.8.tgz" + resolved "https://registry.yarnpkg.com/accepts/-/accepts-1.3.8.tgz#0bf0be125b67014adcb0b0921e62db7bffe16b2e" integrity sha512-PYAthTa2m2VKxuvSD3DPC/Gy+U+sOA1LAuT8mkmRuvw+NACSaeXEQ+NHcVF7rONl6qcaxV3Uuemwawk+7+SJLw== dependencies: mime-types "~2.1.34" @@ -1857,7 +1863,7 @@ accepts@~1.3.4: acorn-jsx@^5.3.2: version "5.3.2" - resolved "https://registry.npmjs.org/acorn-jsx/-/acorn-jsx-5.3.2.tgz" + resolved "https://registry.yarnpkg.com/acorn-jsx/-/acorn-jsx-5.3.2.tgz#7ed5bb55908b3b2f1bc55c6af1653bada7f07937" integrity sha512-rq9s+JNhf0IChjtDXxllJ7g41oZk5SlXtp0LHwyA5cejwn7vKmKp4pPri6YEePv2PU65sAsegbXtIinmDFDXgQ== acorn@^8.8.0: @@ -1867,12 +1873,12 @@ acorn@^8.8.0: add@^2.0.6: version "2.0.6" - resolved "https://registry.npmjs.org/add/-/add-2.0.6.tgz" + resolved "https://registry.yarnpkg.com/add/-/add-2.0.6.tgz#248f0a9f6e5a528ef2295dbeec30532130ae2235" integrity sha512-j5QzrmsokwWWp6kUcJQySpbG+xfOBqqKnup3OIk1pz+kB/80SLorZ9V8zHFLO92Lcd+hbvq8bT+zOGoPkmBV0Q== ajv@^6.10.0, ajv@^6.12.4: version "6.12.6" - resolved "https://registry.npmjs.org/ajv/-/ajv-6.12.6.tgz" + resolved "https://registry.yarnpkg.com/ajv/-/ajv-6.12.6.tgz#baf5a62e802b07d977034586f8c3baf5adf26df4" integrity sha512-j3fVLgvTo527anyYyJOGTYJbG+vnnQYvE0m5mmkc1TK+nxAppkCLMIL0aZ4dblVCNoGShhm+kzE4ZUykBoMg4g== dependencies: fast-deep-equal "^3.1.1" @@ -1882,26 +1888,31 @@ ajv@^6.10.0, ajv@^6.12.4: ansi-regex@^5.0.1: version "5.0.1" - resolved "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.1.tgz" + resolved "https://registry.yarnpkg.com/ansi-regex/-/ansi-regex-5.0.1.tgz#082cb2c89c9fe8659a311a53bd6a4dc5301db304" integrity sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ== ansi-styles@^3.2.1: version "3.2.1" - resolved "https://registry.npmjs.org/ansi-styles/-/ansi-styles-3.2.1.tgz" + resolved "https://registry.yarnpkg.com/ansi-styles/-/ansi-styles-3.2.1.tgz#41fbb20243e50b12be0f04b8dedbf07520ce841d" integrity sha512-VT0ZI6kZRdTh8YyJw3SMbYm/u+NqfsAxEpWO0Pf9sq8/e94WxxOpPKx9FR1FlyCtOVDNOQ+8ntlqFxiRc+r5qA== dependencies: color-convert "^1.9.0" ansi-styles@^4.1.0: version "4.3.0" - resolved "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz" + resolved "https://registry.yarnpkg.com/ansi-styles/-/ansi-styles-4.3.0.tgz#edd803628ae71c04c85ae7a0906edad34b648937" integrity sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg== dependencies: color-convert "^2.0.1" +any-promise@^1.0.0: + version "1.3.0" + resolved "https://registry.yarnpkg.com/any-promise/-/any-promise-1.3.0.tgz#abc6afeedcea52e809cdc0376aed3ce39635d17f" + integrity sha512-7UvmKalWRt1wgjL1RrGxoSJW/0QZFIegpeGvZG9kjp8vrRu55XTHbwnqq2GpXm9uLbcuhxm3IqX9OB4MZR1b2A== + anymatch@~3.1.2: version "3.1.2" - resolved "https://registry.npmjs.org/anymatch/-/anymatch-3.1.2.tgz" + resolved "https://registry.yarnpkg.com/anymatch/-/anymatch-3.1.2.tgz#c0557c096af32f106198f4f4e2a383537e378716" integrity sha512-P43ePfOAIupkguHUycrc4qJ9kz8ZiuOUijaETwX7THt0Y/GNK7v0aa8rY816xWjZ7rJdA5XdMcpVFTKMq+RvWg== dependencies: normalize-path "^3.0.0" @@ -1909,29 +1920,29 @@ anymatch@~3.1.2: argparse@^2.0.1: version "2.0.1" - resolved "https://registry.npmjs.org/argparse/-/argparse-2.0.1.tgz" + resolved "https://registry.yarnpkg.com/argparse/-/argparse-2.0.1.tgz#246f50f3ca78a3240f6c997e8a9bd1eac49e4b38" integrity sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q== aria-hidden@^1.1.1: version "1.2.1" - resolved "https://registry.npmjs.org/aria-hidden/-/aria-hidden-1.2.1.tgz" + resolved "https://registry.yarnpkg.com/aria-hidden/-/aria-hidden-1.2.1.tgz#ad8c1edbde360b454eb2bf717ea02da00bfee0f8" integrity sha512-PN344VAf9j1EAi+jyVHOJ8XidQdPVssGco39eNcsGdM4wcsILtxrKLkbuiMfLWYROK1FjRQasMWCBttrhjnr6A== dependencies: tslib "^2.0.0" array-union@^2.1.0: version "2.1.0" - resolved "https://registry.npmjs.org/array-union/-/array-union-2.1.0.tgz" + resolved "https://registry.yarnpkg.com/array-union/-/array-union-2.1.0.tgz#b798420adbeb1de828d84acd8a2e23d3efe85e8d" integrity sha512-HGyxoOTYUyCM6stUe6EJgnd4EoewAI7zMdfqO+kGjnlZmBDz/cR5pf8r/cR4Wq60sL/p0IkcjUEEPwS3GFrIyw== attr-accept@^2.2.2: version "2.2.2" - resolved "https://registry.npmjs.org/attr-accept/-/attr-accept-2.2.2.tgz" + resolved "https://registry.yarnpkg.com/attr-accept/-/attr-accept-2.2.2.tgz#646613809660110749e92f2c10833b70968d929b" integrity sha512-7prDjvt9HmqiZ0cl5CRjtS84sEyhsHP2coDkaZKRKVfCDo9s7iw7ChVmar78Gu9pC4SoR/28wFu/G5JJhTnqEg== babel-plugin-macros@^3.1.0: version "3.1.0" - resolved "https://registry.npmjs.org/babel-plugin-macros/-/babel-plugin-macros-3.1.0.tgz" + resolved "https://registry.yarnpkg.com/babel-plugin-macros/-/babel-plugin-macros-3.1.0.tgz#9ef6dc74deb934b4db344dc973ee851d148c50c1" integrity sha512-Cg7TFGpIr01vOQNODXOOaGz2NpCU5gl8x1qJFbb6hbZxR7XrcE2vtbAsTAbJ7/xwJtUuJEw8K8Zr/AE0LHlesg== dependencies: "@babel/runtime" "^7.12.5" @@ -1940,22 +1951,22 @@ babel-plugin-macros@^3.1.0: balanced-match@^1.0.0: version "1.0.2" - resolved "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.2.tgz" + resolved "https://registry.yarnpkg.com/balanced-match/-/balanced-match-1.0.2.tgz#e83e3a7e3f300b34cb9d87f615fa0cbf357690ee" integrity sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw== base64id@2.0.0, base64id@~2.0.0: version "2.0.0" - resolved "https://registry.npmjs.org/base64id/-/base64id-2.0.0.tgz" + resolved "https://registry.yarnpkg.com/base64id/-/base64id-2.0.0.tgz#2770ac6bc47d312af97a8bf9a634342e0cd25cb6" integrity sha512-lGe34o6EHj9y3Kts9R4ZYs/Gr+6N7MCaMlIFA3F1R2O5/m7K06AxfSeO5530PEERE6/WyEg3lsuyw4GHlPZHog== binary-extensions@^2.0.0: version "2.2.0" - resolved "https://registry.npmjs.org/binary-extensions/-/binary-extensions-2.2.0.tgz" + resolved "https://registry.yarnpkg.com/binary-extensions/-/binary-extensions-2.2.0.tgz#75f502eeaf9ffde42fc98829645be4ea76bd9e2d" integrity sha512-jDctJ/IVQbZoJykoeHbhXpOlNBqGNcwXJKJog42E5HDPUwQTSdjCHdihjj0DlnheQ7blbT6dHOafNAiS8ooQKA== brace-expansion@^1.1.7: version "1.1.11" - resolved "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz" + resolved "https://registry.yarnpkg.com/brace-expansion/-/brace-expansion-1.1.11.tgz#3c7fcbf529d87226f3d2f52b966ff5271eb441dd" integrity sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA== dependencies: balanced-match "^1.0.0" @@ -1963,14 +1974,14 @@ brace-expansion@^1.1.7: braces@^3.0.2, braces@~3.0.2: version "3.0.2" - resolved "https://registry.npmjs.org/braces/-/braces-3.0.2.tgz" + resolved "https://registry.yarnpkg.com/braces/-/braces-3.0.2.tgz#3454e1a462ee8d599e236df336cd9ea4f8afe107" integrity sha512-b8um+L1RzM3WDSzvhm6gIz1yfTbBt6YTlcEKAvsmqCZZFw46z626lVj9j1yEPW33H5H+lBQpZMP1k8l+78Ha0A== dependencies: fill-range "^7.0.1" browserslist@^4.21.3: version "4.21.4" - resolved "https://registry.npmjs.org/browserslist/-/browserslist-4.21.4.tgz" + resolved "https://registry.yarnpkg.com/browserslist/-/browserslist-4.21.4.tgz#e7496bbc67b9e39dd0f98565feccdcb0d4ff6987" integrity sha512-CBHJJdDmgjl3daYjN5Cp5kbTf1mUhZoS+beLklHIvkOWscs83YAhLlF3Wsh/lciQYAcbBJgTOD44VtG31ZM4Hw== dependencies: caniuse-lite "^1.0.30001400" @@ -1980,17 +1991,17 @@ browserslist@^4.21.3: callsites@^3.0.0: version "3.1.0" - resolved "https://registry.npmjs.org/callsites/-/callsites-3.1.0.tgz" + resolved "https://registry.yarnpkg.com/callsites/-/callsites-3.1.0.tgz#b3630abd8943432f54b3f0519238e33cd7df2f73" integrity sha512-P8BjAsXvZS+VIDUI11hHCQEv74YT67YUi5JJFNWIqL235sBmjX4+qx9Muvls5ivyNENctx46xQLQ3aTuE7ssaQ== caniuse-lite@^1.0.30001400: - version "1.0.30001427" - resolved "https://registry.yarnpkg.com/caniuse-lite/-/caniuse-lite-1.0.30001427.tgz#d3a749f74be7ae0671fbec3a4eea18576e8ad646" - integrity sha512-lfXQ73oB9c8DP5Suxaszm+Ta2sr/4tf8+381GkIm1MLj/YdLf+rEDyDSRCzeltuyTVGm+/s18gdZ0q+Wmp8VsQ== + version "1.0.30001430" + resolved "https://registry.yarnpkg.com/caniuse-lite/-/caniuse-lite-1.0.30001430.tgz#638a8ae00b5a8a97e66ff43733b2701f81b101fa" + integrity sha512-IB1BXTZKPDVPM7cnV4iaKaHxckvdr/3xtctB3f7Hmenx3qYBhGtTZ//7EllK66aKXW98Lx0+7Yr0kxBtIt3tzg== chalk@^2.0.0: version "2.4.2" - resolved "https://registry.npmjs.org/chalk/-/chalk-2.4.2.tgz" + resolved "https://registry.yarnpkg.com/chalk/-/chalk-2.4.2.tgz#cd42541677a54333cf541a49108c1432b44c9424" integrity sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ== dependencies: ansi-styles "^3.2.1" @@ -1999,7 +2010,7 @@ chalk@^2.0.0: chalk@^4.0.0: version "4.1.2" - resolved "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz" + resolved "https://registry.yarnpkg.com/chalk/-/chalk-4.1.2.tgz#aac4e2b7734a740867aeb16bf02aad556a1e7a01" integrity sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA== dependencies: ansi-styles "^4.1.0" @@ -2007,7 +2018,7 @@ chalk@^4.0.0: "chokidar@>=3.0.0 <4.0.0": version "3.5.3" - resolved "https://registry.npmjs.org/chokidar/-/chokidar-3.5.3.tgz" + resolved "https://registry.yarnpkg.com/chokidar/-/chokidar-3.5.3.tgz#1cf37c8707b932bd1af1ae22c0432e2acd1903bd" integrity sha512-Dr3sfKRP6oTcjf2JmUmFJfeVMvXBdegxB0iVQ5eb2V10uFJUCAS8OByZdVAyVb8xXNz3GjjTgj9kLWsZTqE6kw== dependencies: anymatch "~3.1.2" @@ -2022,36 +2033,41 @@ chalk@^4.0.0: color-convert@^1.9.0: version "1.9.3" - resolved "https://registry.npmjs.org/color-convert/-/color-convert-1.9.3.tgz" + resolved "https://registry.yarnpkg.com/color-convert/-/color-convert-1.9.3.tgz#bb71850690e1f136567de629d2d5471deda4c1e8" integrity sha512-QfAUtd+vFdAtFQcC8CCyYt1fYWxSqAiK2cSD6zDB8N3cpsEBAvRxp9zOGg6G/SHHJYAT88/az/IuDGALsNVbGg== dependencies: color-name "1.1.3" color-convert@^2.0.1: version "2.0.1" - resolved "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz" + resolved "https://registry.yarnpkg.com/color-convert/-/color-convert-2.0.1.tgz#72d3a68d598c9bdb3af2ad1e84f21d896abd4de3" integrity sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ== dependencies: color-name "~1.1.4" color-name@1.1.3: version "1.1.3" - resolved "https://registry.npmjs.org/color-name/-/color-name-1.1.3.tgz" + resolved "https://registry.yarnpkg.com/color-name/-/color-name-1.1.3.tgz#a7d0558bd89c42f795dd42328f740831ca53bc25" integrity sha512-72fSenhMw2HZMTVHeCA9KCmpEIbzWiQsjN+BHcBbS9vr1mtt+vJjPdksIBNUmKAW8TFUDPJK5SUU3QhE9NEXDw== color-name@~1.1.4: version "1.1.4" - resolved "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz" + resolved "https://registry.yarnpkg.com/color-name/-/color-name-1.1.4.tgz#c2a09a87acbde69543de6f63fa3995c826c536a2" integrity sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA== +commander@^4.0.0: + version "4.1.1" + resolved "https://registry.yarnpkg.com/commander/-/commander-4.1.1.tgz#9fd602bd936294e9e9ef46a3f4d6964044b18068" + integrity sha512-NOKm8xhkzAjzFx8B2v5OAHT+u5pRQc2UCa2Vq9jYL/31o2wi9mxBA7LIFs3sV5VSC49z6pEhfbMULvShKj26WA== + compute-scroll-into-view@1.0.14: version "1.0.14" - resolved "https://registry.npmjs.org/compute-scroll-into-view/-/compute-scroll-into-view-1.0.14.tgz" + resolved "https://registry.yarnpkg.com/compute-scroll-into-view/-/compute-scroll-into-view-1.0.14.tgz#80e3ebb25d6aa89f42e533956cb4b16a04cfe759" integrity sha512-mKDjINe3tc6hGelUMNDzuhorIUZ7kS7BwyY0r2wQd2HOH2tRuJykiC06iSEX8y1TuhNzvz4GcJnK16mM2J1NMQ== concat-map@0.0.1: version "0.0.1" - resolved "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz" + resolved "https://registry.yarnpkg.com/concat-map/-/concat-map-0.0.1.tgz#d8a96bd77fd68df7793a73036a3ba0d5405d477b" integrity sha512-/Srv4dswyQNBfohGpz9o6Yb3Gz3SrUDqBH5rTuhGR7ahtlbYKnVxw2bCFMRljaA7EXHaXZ8wsHdodFvbkhKmqg== convert-source-map@^1.5.0, convert-source-map@^1.7.0: @@ -2061,19 +2077,19 @@ convert-source-map@^1.5.0, convert-source-map@^1.7.0: cookie@~0.4.1: version "0.4.2" - resolved "https://registry.npmjs.org/cookie/-/cookie-0.4.2.tgz" + resolved "https://registry.yarnpkg.com/cookie/-/cookie-0.4.2.tgz#0e41f24de5ecf317947c82fc789e06a884824432" integrity sha512-aSWTXFzaKWkvHO1Ny/s+ePFpvKsPnjc551iI41v3ny/ow6tBG5Vd+FuqGNhh1LxOmVzOlGUriIlOaokOvhaStA== copy-to-clipboard@3.3.1: version "3.3.1" - resolved "https://registry.npmjs.org/copy-to-clipboard/-/copy-to-clipboard-3.3.1.tgz" + resolved "https://registry.yarnpkg.com/copy-to-clipboard/-/copy-to-clipboard-3.3.1.tgz#115aa1a9998ffab6196f93076ad6da3b913662ae" integrity sha512-i13qo6kIHTTpCm8/Wup+0b1mVWETvu2kIMzKoK8FpkLkFxlt0znUAHcMzox+T8sPlqtZXq3CulEjQHsYiGFJUw== dependencies: toggle-selection "^1.0.6" cors@~2.8.5: version "2.8.5" - resolved "https://registry.npmjs.org/cors/-/cors-2.8.5.tgz" + resolved "https://registry.yarnpkg.com/cors/-/cors-2.8.5.tgz#eac11da51592dd86b9f06f6e7ac293b3df875d29" integrity sha512-KIHbLJqu73RGr/hnbrO9uBeixNGuvSQjul/jdFvS/KFSIH1hWVd1ng7zOHx+YrEfInLG7q4n6GHQ9cDtxv/P6g== dependencies: object-assign "^4" @@ -2081,7 +2097,7 @@ cors@~2.8.5: cosmiconfig@^7.0.0: version "7.0.1" - resolved "https://registry.npmjs.org/cosmiconfig/-/cosmiconfig-7.0.1.tgz" + resolved "https://registry.yarnpkg.com/cosmiconfig/-/cosmiconfig-7.0.1.tgz#714d756522cace867867ccb4474c5d01bbae5d6d" integrity sha512-a1YWNUV2HwGimB7dU2s1wUMurNKjpx60HxBB6xUM8Re+2s1g1IIfJvFR0/iCF+XHdE0GMTKTuLR32UQff4TEyQ== dependencies: "@types/parse-json" "^4.0.0" @@ -2092,7 +2108,7 @@ cosmiconfig@^7.0.0: cross-spawn@^7.0.2, cross-spawn@^7.0.3: version "7.0.3" - resolved "https://registry.npmjs.org/cross-spawn/-/cross-spawn-7.0.3.tgz" + resolved "https://registry.yarnpkg.com/cross-spawn/-/cross-spawn-7.0.3.tgz#f73a85b9d5d41d045551c177e2882d4ac85728a6" integrity sha512-iRDPJKUPVEND7dHPO8rkbOnPpyDygcDFtWjpeWNCgy8WP2rXcxXL8TskReQl6OrB2G7+UJrags1q15Fudc7G6w== dependencies: path-key "^3.1.0" @@ -2101,55 +2117,55 @@ cross-spawn@^7.0.2, cross-spawn@^7.0.3: css-box-model@1.2.1: version "1.2.1" - resolved "https://registry.npmjs.org/css-box-model/-/css-box-model-1.2.1.tgz" + resolved "https://registry.yarnpkg.com/css-box-model/-/css-box-model-1.2.1.tgz#59951d3b81fd6b2074a62d49444415b0d2b4d7c1" integrity sha512-a7Vr4Q/kd/aw96bnJG332W9V9LkJO69JRcaCYDUqjp6/z0w6VcZjgAcTbgFxEPfBgdnAwlh3iwu+hLopa+flJw== dependencies: tiny-invariant "^1.0.6" csstype@^3.0.11, csstype@^3.0.2: version "3.1.1" - resolved "https://registry.npmjs.org/csstype/-/csstype-3.1.1.tgz" + resolved "https://registry.yarnpkg.com/csstype/-/csstype-3.1.1.tgz#841b532c45c758ee546a11d5bd7b7b473c8c30b9" integrity sha512-DJR/VvkAvSZW9bTouZue2sSxDwdTN92uHjqeKVm+0dAqdfNykRzQ95tay8aXMBAAPpUiq4Qcug2L7neoRh2Egw== dateformat@^5.0.3: version "5.0.3" - resolved "https://registry.npmjs.org/dateformat/-/dateformat-5.0.3.tgz" + resolved "https://registry.yarnpkg.com/dateformat/-/dateformat-5.0.3.tgz#fe2223eff3cc70ce716931cb3038b59a9280696e" integrity sha512-Kvr6HmPXUMerlLcLF+Pwq3K7apHpYmGDVqrxcDasBg86UcKeTSNWbEzU8bwdXnxnR44FtMhJAxI4Bov6Y/KUfA== debug@^4.1.0, debug@^4.1.1, debug@^4.3.2, debug@^4.3.4, debug@~4.3.1, debug@~4.3.2: version "4.3.4" - resolved "https://registry.npmjs.org/debug/-/debug-4.3.4.tgz" + resolved "https://registry.yarnpkg.com/debug/-/debug-4.3.4.tgz#1319f6579357f2338d3337d2cdd4914bb5dcc865" integrity sha512-PRWFHuSU3eDtQJPvnNY7Jcket1j0t5OuOsFzPPzsekD52Zl8qUfFIPEiswXqIvHWGVHOgX+7G/vCNNhehwxfkQ== dependencies: ms "2.1.2" deep-is@^0.1.3: version "0.1.4" - resolved "https://registry.npmjs.org/deep-is/-/deep-is-0.1.4.tgz" + resolved "https://registry.yarnpkg.com/deep-is/-/deep-is-0.1.4.tgz#a6f2dce612fadd2ef1f519b73551f17e85199831" integrity sha512-oIPzksmTg4/MriiaYGO+okXDT7ztn/w3Eptv/+gSIdMdKsJo0u4CfYNFJPy+4SKMuCqGw2wxnA+URMg3t8a/bQ== detect-node-es@^1.1.0: version "1.1.0" - resolved "https://registry.npmjs.org/detect-node-es/-/detect-node-es-1.1.0.tgz" + resolved "https://registry.yarnpkg.com/detect-node-es/-/detect-node-es-1.1.0.tgz#163acdf643330caa0b4cd7c21e7ee7755d6fa493" integrity sha512-ypdmJU/TbBby2Dxibuv7ZLW3Bs1QEmM7nHjEANfohJLvE0XVujisn1qPJcZxg+qDucsr+bP6fLD1rPS3AhJ7EQ== dir-glob@^3.0.1: version "3.0.1" - resolved "https://registry.npmjs.org/dir-glob/-/dir-glob-3.0.1.tgz" + resolved "https://registry.yarnpkg.com/dir-glob/-/dir-glob-3.0.1.tgz#56dbf73d992a4a93ba1584f4534063fd2e41717f" integrity sha512-WkrWp9GR4KXfKGYzOLmTuGVi1UWFfws377n9cc55/tb6DuqyF6pcQ5AbiHEshaDpY9v6oaSr2XCDidGmMwdzIA== dependencies: path-type "^4.0.0" doctrine@^3.0.0: version "3.0.0" - resolved "https://registry.npmjs.org/doctrine/-/doctrine-3.0.0.tgz" + resolved "https://registry.yarnpkg.com/doctrine/-/doctrine-3.0.0.tgz#addebead72a6574db783639dc87a121773973961" integrity sha512-yS+Q5i3hBf7GBkd4KG8a7eBNNWNGLTaEwwYWUijIYM7zrlYDM0BFXHjjPWlWZ1Rg7UaddZeIDmi9jF3HmqiQ2w== dependencies: esutils "^2.0.2" dom-helpers@^5.0.1: version "5.2.1" - resolved "https://registry.npmjs.org/dom-helpers/-/dom-helpers-5.2.1.tgz" + resolved "https://registry.yarnpkg.com/dom-helpers/-/dom-helpers-5.2.1.tgz#d9400536b2bf8225ad98fe052e029451ac40e902" integrity sha512-nRCa7CK3VTrM2NmGkIy4cbK7IZlgBE/PYMn55rrXefr5xXDP0LdtfPnblFDoVdcAfslJ7or6iqAUnx0CCGIWQA== dependencies: "@babel/runtime" "^7.8.7" @@ -2157,7 +2173,7 @@ dom-helpers@^5.0.1: duplexer@~0.1.1: version "0.1.2" - resolved "https://registry.npmjs.org/duplexer/-/duplexer-0.1.2.tgz" + resolved "https://registry.yarnpkg.com/duplexer/-/duplexer-0.1.2.tgz#3abe43aef3835f8ae077d136ddce0f276b0400e6" integrity sha512-jtD6YG370ZCIi/9GTaJKQxWTZD045+4R4hTk/x1UyoqadyJ9x9CgSi1RlVDQF8U2sxLLSnFkCaMihqljHIWgMg== electron-to-chromium@^1.4.251: @@ -2178,12 +2194,12 @@ engine.io-client@~6.2.3: engine.io-parser@~5.0.3: version "5.0.4" - resolved "https://registry.npmjs.org/engine.io-parser/-/engine.io-parser-5.0.4.tgz" + resolved "https://registry.yarnpkg.com/engine.io-parser/-/engine.io-parser-5.0.4.tgz#0b13f704fa9271b3ec4f33112410d8f3f41d0fc0" integrity sha512-+nVFp+5z1E3HcToEnO7ZIj3g+3k9389DvWtvJZz0T6/eOCPIyyxehFcedoYrZQrp0LgQbD9pPXhpMBKMd5QURg== engine.io@~6.2.0: version "6.2.0" - resolved "https://registry.npmjs.org/engine.io/-/engine.io-6.2.0.tgz" + resolved "https://registry.yarnpkg.com/engine.io/-/engine.io-6.2.0.tgz#003bec48f6815926f2b1b17873e576acd54f41d0" integrity sha512-4KzwW3F3bk+KlzSOY57fj/Jx6LyRQ1nbcyIadehl+AnXjKT7gDO0ORdRi/84ixvMKTym6ZKuxvbzN62HDDU1Lg== dependencies: "@types/cookie" "^0.4.1" @@ -2199,169 +2215,169 @@ engine.io@~6.2.0: error-ex@^1.3.1: version "1.3.2" - resolved "https://registry.npmjs.org/error-ex/-/error-ex-1.3.2.tgz" + resolved "https://registry.yarnpkg.com/error-ex/-/error-ex-1.3.2.tgz#b4ac40648107fdcdcfae242f428bea8a14d4f1bf" integrity sha512-7dFHNmqeFSEt2ZBsCriorKnn3Z2pj+fd9kmI6QoWw4//DL+icEBfc0U7qJCisqrTsKTjw4fNFy2pW9OqStD84g== dependencies: is-arrayish "^0.2.1" -esbuild-android-64@0.15.12: - version "0.15.12" - resolved "https://registry.yarnpkg.com/esbuild-android-64/-/esbuild-android-64-0.15.12.tgz#5e8151d5f0a748c71a7fbea8cee844ccf008e6fc" - integrity sha512-MJKXwvPY9g0rGps0+U65HlTsM1wUs9lbjt5CU19RESqycGFDRijMDQsh68MtbzkqWSRdEtiKS1mtPzKneaAI0Q== +esbuild-android-64@0.15.13: + version "0.15.13" + resolved "https://registry.yarnpkg.com/esbuild-android-64/-/esbuild-android-64-0.15.13.tgz#5f25864055dbd62e250f360b38b4c382224063af" + integrity sha512-yRorukXBlokwTip+Sy4MYskLhJsO0Kn0/Fj43s1krVblfwP+hMD37a4Wmg139GEsMLl+vh8WXp2mq/cTA9J97g== -esbuild-android-arm64@0.15.12: - version "0.15.12" - resolved "https://registry.yarnpkg.com/esbuild-android-arm64/-/esbuild-android-arm64-0.15.12.tgz#5ee72a6baa444bc96ffcb472a3ba4aba2cc80666" - integrity sha512-Hc9SEcZbIMhhLcvhr1DH+lrrec9SFTiRzfJ7EGSBZiiw994gfkVV6vG0sLWqQQ6DD7V4+OggB+Hn0IRUdDUqvA== +esbuild-android-arm64@0.15.13: + version "0.15.13" + resolved "https://registry.yarnpkg.com/esbuild-android-arm64/-/esbuild-android-arm64-0.15.13.tgz#d8820f999314efbe8e0f050653a99ff2da632b0f" + integrity sha512-TKzyymLD6PiVeyYa4c5wdPw87BeAiTXNtK6amWUcXZxkV51gOk5u5qzmDaYSwiWeecSNHamFsaFjLoi32QR5/w== -esbuild-darwin-64@0.15.12: - version "0.15.12" - resolved "https://registry.yarnpkg.com/esbuild-darwin-64/-/esbuild-darwin-64-0.15.12.tgz#70047007e093fa1b3ba7ef86f9b3fa63db51fe25" - integrity sha512-qkmqrTVYPFiePt5qFjP8w/S+GIUMbt6k8qmiPraECUWfPptaPJUGkCKrWEfYFRWB7bY23FV95rhvPyh/KARP8Q== +esbuild-darwin-64@0.15.13: + version "0.15.13" + resolved "https://registry.yarnpkg.com/esbuild-darwin-64/-/esbuild-darwin-64-0.15.13.tgz#99ae7fdaa43947b06cd9d1a1c3c2c9f245d81fd0" + integrity sha512-WAx7c2DaOS6CrRcoYCgXgkXDliLnFv3pQLV6GeW1YcGEZq2Gnl8s9Pg7ahValZkpOa0iE/ojRVQ87sbUhF1Cbg== -esbuild-darwin-arm64@0.15.12: - version "0.15.12" - resolved "https://registry.yarnpkg.com/esbuild-darwin-arm64/-/esbuild-darwin-arm64-0.15.12.tgz#41c951f23d9a70539bcca552bae6e5196696ae04" - integrity sha512-z4zPX02tQ41kcXMyN3c/GfZpIjKoI/BzHrdKUwhC/Ki5BAhWv59A9M8H+iqaRbwpzYrYidTybBwiZAIWCLJAkw== +esbuild-darwin-arm64@0.15.13: + version "0.15.13" + resolved "https://registry.yarnpkg.com/esbuild-darwin-arm64/-/esbuild-darwin-arm64-0.15.13.tgz#bafa1814354ad1a47adcad73de416130ef7f55e3" + integrity sha512-U6jFsPfSSxC3V1CLiQqwvDuj3GGrtQNB3P3nNC3+q99EKf94UGpsG9l4CQ83zBs1NHrk1rtCSYT0+KfK5LsD8A== -esbuild-freebsd-64@0.15.12: - version "0.15.12" - resolved "https://registry.yarnpkg.com/esbuild-freebsd-64/-/esbuild-freebsd-64-0.15.12.tgz#a761b5afd12bbedb7d56c612e9cfa4d2711f33f0" - integrity sha512-XFL7gKMCKXLDiAiBjhLG0XECliXaRLTZh6hsyzqUqPUf/PY4C6EJDTKIeqqPKXaVJ8+fzNek88285krSz1QECw== +esbuild-freebsd-64@0.15.13: + version "0.15.13" + resolved "https://registry.yarnpkg.com/esbuild-freebsd-64/-/esbuild-freebsd-64-0.15.13.tgz#84ef85535c5cc38b627d1c5115623b088d1de161" + integrity sha512-whItJgDiOXaDG/idy75qqevIpZjnReZkMGCgQaBWZuKHoElDJC1rh7MpoUgupMcdfOd+PgdEwNQW9DAE6i8wyA== -esbuild-freebsd-arm64@0.15.12: - version "0.15.12" - resolved "https://registry.yarnpkg.com/esbuild-freebsd-arm64/-/esbuild-freebsd-arm64-0.15.12.tgz#6b0839d4d58deabc6cbd96276eb8cbf94f7f335e" - integrity sha512-jwEIu5UCUk6TjiG1X+KQnCGISI+ILnXzIzt9yDVrhjug2fkYzlLbl0K43q96Q3KB66v6N1UFF0r5Ks4Xo7i72g== +esbuild-freebsd-arm64@0.15.13: + version "0.15.13" + resolved "https://registry.yarnpkg.com/esbuild-freebsd-arm64/-/esbuild-freebsd-arm64-0.15.13.tgz#033f21de434ec8e0c478054b119af8056763c2d8" + integrity sha512-6pCSWt8mLUbPtygv7cufV0sZLeylaMwS5Fznj6Rsx9G2AJJsAjQ9ifA+0rQEIg7DwJmi9it+WjzNTEAzzdoM3Q== -esbuild-linux-32@0.15.12: - version "0.15.12" - resolved "https://registry.yarnpkg.com/esbuild-linux-32/-/esbuild-linux-32-0.15.12.tgz#bd50bfe22514d434d97d5150977496e2631345b4" - integrity sha512-uSQuSEyF1kVzGzuIr4XM+v7TPKxHjBnLcwv2yPyCz8riV8VUCnO/C4BF3w5dHiVpCd5Z1cebBtZJNlC4anWpwA== +esbuild-linux-32@0.15.13: + version "0.15.13" + resolved "https://registry.yarnpkg.com/esbuild-linux-32/-/esbuild-linux-32-0.15.13.tgz#54290ea8035cba0faf1791ce9ae6693005512535" + integrity sha512-VbZdWOEdrJiYApm2kkxoTOgsoCO1krBZ3quHdYk3g3ivWaMwNIVPIfEE0f0XQQ0u5pJtBsnk2/7OPiCFIPOe/w== -esbuild-linux-64@0.15.12: - version "0.15.12" - resolved "https://registry.yarnpkg.com/esbuild-linux-64/-/esbuild-linux-64-0.15.12.tgz#074bb2b194bf658245f8490f29c01ffcdfa8c931" - integrity sha512-QcgCKb7zfJxqT9o5z9ZUeGH1k8N6iX1Y7VNsEi5F9+HzN1OIx7ESxtQXDN9jbeUSPiRH1n9cw6gFT3H4qbdvcA== +esbuild-linux-64@0.15.13: + version "0.15.13" + resolved "https://registry.yarnpkg.com/esbuild-linux-64/-/esbuild-linux-64-0.15.13.tgz#4264249281ea388ead948614b57fb1ddf7779a2c" + integrity sha512-rXmnArVNio6yANSqDQlIO4WiP+Cv7+9EuAHNnag7rByAqFVuRusLbGi2697A5dFPNXoO//IiogVwi3AdcfPC6A== -esbuild-linux-arm64@0.15.12: - version "0.15.12" - resolved "https://registry.yarnpkg.com/esbuild-linux-arm64/-/esbuild-linux-arm64-0.15.12.tgz#3bf789c4396dc032875a122988efd6f3733f28f5" - integrity sha512-HtNq5xm8fUpZKwWKS2/YGwSfTF+339L4aIA8yphNKYJckd5hVdhfdl6GM2P3HwLSCORS++++7++//ApEwXEuAQ== +esbuild-linux-arm64@0.15.13: + version "0.15.13" + resolved "https://registry.yarnpkg.com/esbuild-linux-arm64/-/esbuild-linux-arm64-0.15.13.tgz#9323c333924f97a02bdd2ae8912b36298acb312d" + integrity sha512-alEMGU4Z+d17U7KQQw2IV8tQycO6T+rOrgW8OS22Ua25x6kHxoG6Ngry6Aq6uranC+pNWNMB6aHFPh7aTQdORQ== -esbuild-linux-arm@0.15.12: - version "0.15.12" - resolved "https://registry.yarnpkg.com/esbuild-linux-arm/-/esbuild-linux-arm-0.15.12.tgz#b91b5a8d470053f6c2c9c8a5e67ec10a71fe4a67" - integrity sha512-Wf7T0aNylGcLu7hBnzMvsTfEXdEdJY/hY3u36Vla21aY66xR0MS5I1Hw8nVquXjTN0A6fk/vnr32tkC/C2lb0A== +esbuild-linux-arm@0.15.13: + version "0.15.13" + resolved "https://registry.yarnpkg.com/esbuild-linux-arm/-/esbuild-linux-arm-0.15.13.tgz#b407f47b3ae721fe4e00e19e9f19289bef87a111" + integrity sha512-Ac6LpfmJO8WhCMQmO253xX2IU2B3wPDbl4IvR0hnqcPrdfCaUa2j/lLMGTjmQ4W5JsJIdHEdW12dG8lFS0MbxQ== -esbuild-linux-mips64le@0.15.12: - version "0.15.12" - resolved "https://registry.yarnpkg.com/esbuild-linux-mips64le/-/esbuild-linux-mips64le-0.15.12.tgz#2fb54099ada3c950a7536dfcba46172c61e580e2" - integrity sha512-Qol3+AvivngUZkTVFgLpb0H6DT+N5/zM3V1YgTkryPYFeUvuT5JFNDR3ZiS6LxhyF8EE+fiNtzwlPqMDqVcc6A== +esbuild-linux-mips64le@0.15.13: + version "0.15.13" + resolved "https://registry.yarnpkg.com/esbuild-linux-mips64le/-/esbuild-linux-mips64le-0.15.13.tgz#bdf905aae5c0bcaa8f83567fe4c4c1bdc1f14447" + integrity sha512-47PgmyYEu+yN5rD/MbwS6DxP2FSGPo4Uxg5LwIdxTiyGC2XKwHhHyW7YYEDlSuXLQXEdTO7mYe8zQ74czP7W8A== -esbuild-linux-ppc64le@0.15.12: - version "0.15.12" - resolved "https://registry.yarnpkg.com/esbuild-linux-ppc64le/-/esbuild-linux-ppc64le-0.15.12.tgz#9e3b8c09825fb27886249dfb3142a750df29a1b7" - integrity sha512-4D8qUCo+CFKaR0cGXtGyVsOI7w7k93Qxb3KFXWr75An0DHamYzq8lt7TNZKoOq/Gh8c40/aKaxvcZnTgQ0TJNg== +esbuild-linux-ppc64le@0.15.13: + version "0.15.13" + resolved "https://registry.yarnpkg.com/esbuild-linux-ppc64le/-/esbuild-linux-ppc64le-0.15.13.tgz#2911eae1c90ff58a3bd3259cb557235df25aa3b4" + integrity sha512-z6n28h2+PC1Ayle9DjKoBRcx/4cxHoOa2e689e2aDJSaKug3jXcQw7mM+GLg+9ydYoNzj8QxNL8ihOv/OnezhA== -esbuild-linux-riscv64@0.15.12: - version "0.15.12" - resolved "https://registry.yarnpkg.com/esbuild-linux-riscv64/-/esbuild-linux-riscv64-0.15.12.tgz#923d0f5b6e12ee0d1fe116b08e4ae4478fe40693" - integrity sha512-G9w6NcuuCI6TUUxe6ka0enjZHDnSVK8bO+1qDhMOCtl7Tr78CcZilJj8SGLN00zO5iIlwNRZKHjdMpfFgNn1VA== +esbuild-linux-riscv64@0.15.13: + version "0.15.13" + resolved "https://registry.yarnpkg.com/esbuild-linux-riscv64/-/esbuild-linux-riscv64-0.15.13.tgz#1837c660be12b1d20d2a29c7189ea703f93e9265" + integrity sha512-+Lu4zuuXuQhgLUGyZloWCqTslcCAjMZH1k3Xc9MSEJEpEFdpsSU0sRDXAnk18FKOfEjhu4YMGaykx9xjtpA6ow== -esbuild-linux-s390x@0.15.12: - version "0.15.12" - resolved "https://registry.yarnpkg.com/esbuild-linux-s390x/-/esbuild-linux-s390x-0.15.12.tgz#3b1620220482b96266a0c6d9d471d451a1eab86f" - integrity sha512-Lt6BDnuXbXeqSlVuuUM5z18GkJAZf3ERskGZbAWjrQoi9xbEIsj/hEzVnSAFLtkfLuy2DE4RwTcX02tZFunXww== +esbuild-linux-s390x@0.15.13: + version "0.15.13" + resolved "https://registry.yarnpkg.com/esbuild-linux-s390x/-/esbuild-linux-s390x-0.15.13.tgz#d52880ece229d1bd10b2d936b792914ffb07c7fc" + integrity sha512-BMeXRljruf7J0TMxD5CIXS65y7puiZkAh+s4XFV9qy16SxOuMhxhVIXYLnbdfLrsYGFzx7U9mcdpFWkkvy/Uag== -esbuild-netbsd-64@0.15.12: - version "0.15.12" - resolved "https://registry.yarnpkg.com/esbuild-netbsd-64/-/esbuild-netbsd-64-0.15.12.tgz#276730f80da646859b1af5a740e7802d8cd73e42" - integrity sha512-jlUxCiHO1dsqoURZDQts+HK100o0hXfi4t54MNRMCAqKGAV33JCVvMplLAa2FwviSojT/5ZG5HUfG3gstwAG8w== +esbuild-netbsd-64@0.15.13: + version "0.15.13" + resolved "https://registry.yarnpkg.com/esbuild-netbsd-64/-/esbuild-netbsd-64-0.15.13.tgz#de14da46f1d20352b43e15d97a80a8788275e6ed" + integrity sha512-EHj9QZOTel581JPj7UO3xYbltFTYnHy+SIqJVq6yd3KkCrsHRbapiPb0Lx3EOOtybBEE9EyqbmfW1NlSDsSzvQ== -esbuild-openbsd-64@0.15.12: - version "0.15.12" - resolved "https://registry.yarnpkg.com/esbuild-openbsd-64/-/esbuild-openbsd-64-0.15.12.tgz#bd0eea1dd2ca0722ed489d88c26714034429f8ae" - integrity sha512-1o1uAfRTMIWNOmpf8v7iudND0L6zRBYSH45sofCZywrcf7NcZA+c7aFsS1YryU+yN7aRppTqdUK1PgbZVaB1Dw== +esbuild-openbsd-64@0.15.13: + version "0.15.13" + resolved "https://registry.yarnpkg.com/esbuild-openbsd-64/-/esbuild-openbsd-64-0.15.13.tgz#45e8a5fd74d92ad8f732c43582369c7990f5a0ac" + integrity sha512-nkuDlIjF/sfUhfx8SKq0+U+Fgx5K9JcPq1mUodnxI0x4kBdCv46rOGWbuJ6eof2n3wdoCLccOoJAbg9ba/bT2w== -esbuild-sunos-64@0.15.12: - version "0.15.12" - resolved "https://registry.yarnpkg.com/esbuild-sunos-64/-/esbuild-sunos-64-0.15.12.tgz#5e56bf9eef3b2d92360d6d29dcde7722acbecc9e" - integrity sha512-nkl251DpoWoBO9Eq9aFdoIt2yYmp4I3kvQjba3jFKlMXuqQ9A4q+JaqdkCouG3DHgAGnzshzaGu6xofGcXyPXg== +esbuild-sunos-64@0.15.13: + version "0.15.13" + resolved "https://registry.yarnpkg.com/esbuild-sunos-64/-/esbuild-sunos-64-0.15.13.tgz#f646ac3da7aac521ee0fdbc192750c87da697806" + integrity sha512-jVeu2GfxZQ++6lRdY43CS0Tm/r4WuQQ0Pdsrxbw+aOrHQPHV0+LNOLnvbN28M7BSUGnJnHkHm2HozGgNGyeIRw== -esbuild-windows-32@0.15.12: - version "0.15.12" - resolved "https://registry.yarnpkg.com/esbuild-windows-32/-/esbuild-windows-32-0.15.12.tgz#a4f1a301c1a2fa7701fcd4b91ef9d2620cf293d0" - integrity sha512-WlGeBZHgPC00O08luIp5B2SP4cNCp/PcS+3Pcg31kdcJPopHxLkdCXtadLU9J82LCfw4TVls21A6lilQ9mzHrw== +esbuild-windows-32@0.15.13: + version "0.15.13" + resolved "https://registry.yarnpkg.com/esbuild-windows-32/-/esbuild-windows-32-0.15.13.tgz#fb4fe77c7591418880b3c9b5900adc4c094f2401" + integrity sha512-XoF2iBf0wnqo16SDq+aDGi/+QbaLFpkiRarPVssMh9KYbFNCqPLlGAWwDvxEVz+ywX6Si37J2AKm+AXq1kC0JA== -esbuild-windows-64@0.15.12: - version "0.15.12" - resolved "https://registry.yarnpkg.com/esbuild-windows-64/-/esbuild-windows-64-0.15.12.tgz#bc2b467541744d653be4fe64eaa9b0dbbf8e07f6" - integrity sha512-VActO3WnWZSN//xjSfbiGOSyC+wkZtI8I4KlgrTo5oHJM6z3MZZBCuFaZHd8hzf/W9KPhF0lY8OqlmWC9HO5AA== +esbuild-windows-64@0.15.13: + version "0.15.13" + resolved "https://registry.yarnpkg.com/esbuild-windows-64/-/esbuild-windows-64-0.15.13.tgz#1fca8c654392c0c31bdaaed168becfea80e20660" + integrity sha512-Et6htEfGycjDrtqb2ng6nT+baesZPYQIW+HUEHK4D1ncggNrDNk3yoboYQ5KtiVrw/JaDMNttz8rrPubV/fvPQ== -esbuild-windows-arm64@0.15.12: - version "0.15.12" - resolved "https://registry.yarnpkg.com/esbuild-windows-arm64/-/esbuild-windows-arm64-0.15.12.tgz#9a7266404334a86be800957eaee9aef94c3df328" - integrity sha512-Of3MIacva1OK/m4zCNIvBfz8VVROBmQT+gRX6pFTLPngFYcj6TFH/12VveAqq1k9VB2l28EoVMNMUCcmsfwyuA== +esbuild-windows-arm64@0.15.13: + version "0.15.13" + resolved "https://registry.yarnpkg.com/esbuild-windows-arm64/-/esbuild-windows-arm64-0.15.13.tgz#4ffd01b6b2888603f1584a2fe96b1f6a6f2b3dd8" + integrity sha512-3bv7tqntThQC9SWLRouMDmZnlOukBhOCTlkzNqzGCmrkCJI7io5LLjwJBOVY6kOUlIvdxbooNZwjtBvj+7uuVg== esbuild@^0.15.9: - version "0.15.12" - resolved "https://registry.yarnpkg.com/esbuild/-/esbuild-0.15.12.tgz#6c8e22d6d3b7430d165c33848298d3fc9a1f251c" - integrity sha512-PcT+/wyDqJQsRVhaE9uX/Oq4XLrFh0ce/bs2TJh4CSaw9xuvI+xFrH2nAYOADbhQjUgAhNWC5LKoUsakm4dxng== + version "0.15.13" + resolved "https://registry.yarnpkg.com/esbuild/-/esbuild-0.15.13.tgz#7293480038feb2bafa91d3f6a20edab3ba6c108a" + integrity sha512-Cu3SC84oyzzhrK/YyN4iEVy2jZu5t2fz66HEOShHURcjSkOSAVL8C/gfUT+lDJxkVHpg8GZ10DD0rMHRPqMFaQ== optionalDependencies: - "@esbuild/android-arm" "0.15.12" - "@esbuild/linux-loong64" "0.15.12" - esbuild-android-64 "0.15.12" - esbuild-android-arm64 "0.15.12" - esbuild-darwin-64 "0.15.12" - esbuild-darwin-arm64 "0.15.12" - esbuild-freebsd-64 "0.15.12" - esbuild-freebsd-arm64 "0.15.12" - esbuild-linux-32 "0.15.12" - esbuild-linux-64 "0.15.12" - esbuild-linux-arm "0.15.12" - esbuild-linux-arm64 "0.15.12" - esbuild-linux-mips64le "0.15.12" - esbuild-linux-ppc64le "0.15.12" - esbuild-linux-riscv64 "0.15.12" - esbuild-linux-s390x "0.15.12" - esbuild-netbsd-64 "0.15.12" - esbuild-openbsd-64 "0.15.12" - esbuild-sunos-64 "0.15.12" - esbuild-windows-32 "0.15.12" - esbuild-windows-64 "0.15.12" - esbuild-windows-arm64 "0.15.12" + "@esbuild/android-arm" "0.15.13" + "@esbuild/linux-loong64" "0.15.13" + esbuild-android-64 "0.15.13" + esbuild-android-arm64 "0.15.13" + esbuild-darwin-64 "0.15.13" + esbuild-darwin-arm64 "0.15.13" + esbuild-freebsd-64 "0.15.13" + esbuild-freebsd-arm64 "0.15.13" + esbuild-linux-32 "0.15.13" + esbuild-linux-64 "0.15.13" + esbuild-linux-arm "0.15.13" + esbuild-linux-arm64 "0.15.13" + esbuild-linux-mips64le "0.15.13" + esbuild-linux-ppc64le "0.15.13" + esbuild-linux-riscv64 "0.15.13" + esbuild-linux-s390x "0.15.13" + esbuild-netbsd-64 "0.15.13" + esbuild-openbsd-64 "0.15.13" + esbuild-sunos-64 "0.15.13" + esbuild-windows-32 "0.15.13" + esbuild-windows-64 "0.15.13" + esbuild-windows-arm64 "0.15.13" escalade@^3.1.1: version "3.1.1" - resolved "https://registry.npmjs.org/escalade/-/escalade-3.1.1.tgz" + resolved "https://registry.yarnpkg.com/escalade/-/escalade-3.1.1.tgz#d8cfdc7000965c5a0174b4a82eaa5c0552742e40" integrity sha512-k0er2gUkLf8O0zKJiAhmkTnJlTvINGv7ygDNPbeIsX/TJjGJZHuh9B2UxbsaEkmlEo9MfhrSzmhIlhRlI2GXnw== escape-string-regexp@^1.0.5: version "1.0.5" - resolved "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz" + resolved "https://registry.yarnpkg.com/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz#1b61c0562190a8dff6ae3bb2cf0200ca130b86d4" integrity sha512-vbRorB5FUQWvla16U8R/qgaFIya2qGzwDrNmCZuYKrbdSUMG6I1ZCGQRefkRVhuOkIGVne7BQ35DSfo1qvJqFg== escape-string-regexp@^4.0.0: version "4.0.0" - resolved "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-4.0.0.tgz" + resolved "https://registry.yarnpkg.com/escape-string-regexp/-/escape-string-regexp-4.0.0.tgz#14ba83a5d373e3d311e5afca29cf5bfad965bf34" integrity sha512-TtpcNJ3XAzx3Gq8sWRzJaVajRs0uVxA2YAkdb1jm2YkPz4G6egUFAyA3n5vtEIZefPk5Wa4UXbKuS5fKkJWdgA== eslint-plugin-prettier@^4.2.1: version "4.2.1" - resolved "https://registry.npmjs.org/eslint-plugin-prettier/-/eslint-plugin-prettier-4.2.1.tgz" + resolved "https://registry.yarnpkg.com/eslint-plugin-prettier/-/eslint-plugin-prettier-4.2.1.tgz#651cbb88b1dab98bfd42f017a12fa6b2d993f94b" integrity sha512-f/0rXLXUt0oFYs8ra4w49wYZBG5GKZpAYsJSm6rnYL5uVDjd+zowwMwVZHnAjf4edNrKpCDYfXDgmRE/Ak7QyQ== dependencies: prettier-linter-helpers "^1.0.0" eslint-plugin-react-hooks@^4.6.0: version "4.6.0" - resolved "https://registry.npmjs.org/eslint-plugin-react-hooks/-/eslint-plugin-react-hooks-4.6.0.tgz" + resolved "https://registry.yarnpkg.com/eslint-plugin-react-hooks/-/eslint-plugin-react-hooks-4.6.0.tgz#4c3e697ad95b77e93f8646aaa1630c1ba607edd3" integrity sha512-oFc7Itz9Qxh2x4gNHStv3BqJq54ExXmfC+a1NjAta66IAN87Wu0R/QArgIS9qKzX3dXKPI9H5crl9QchNMY9+g== eslint-scope@^5.1.1: version "5.1.1" - resolved "https://registry.npmjs.org/eslint-scope/-/eslint-scope-5.1.1.tgz" + resolved "https://registry.yarnpkg.com/eslint-scope/-/eslint-scope-5.1.1.tgz#e786e59a66cb92b3f6c1fb0d508aab174848f48c" integrity sha512-2NxwbF/hZ0KpepYN0cNbo+FN6XoK7GaHlQhgx/hIZl6Va0bF45RQOOwhLIy8lQDbuCiadSLCBnH2CFYquit5bw== dependencies: esrecurse "^4.3.0" @@ -2369,7 +2385,7 @@ eslint-scope@^5.1.1: eslint-scope@^7.1.1: version "7.1.1" - resolved "https://registry.npmjs.org/eslint-scope/-/eslint-scope-7.1.1.tgz" + resolved "https://registry.yarnpkg.com/eslint-scope/-/eslint-scope-7.1.1.tgz#fff34894c2f65e5226d3041ac480b4513a163642" integrity sha512-QKQM/UXpIiHcLqJ5AOyIW7XZmzjkzQXYE54n1++wb0u9V/abW3l9uQnxX8Z5Xd18xyKIMTUAyQ0k1e8pz6LUrw== dependencies: esrecurse "^4.3.0" @@ -2377,19 +2393,19 @@ eslint-scope@^7.1.1: eslint-utils@^3.0.0: version "3.0.0" - resolved "https://registry.npmjs.org/eslint-utils/-/eslint-utils-3.0.0.tgz" + resolved "https://registry.yarnpkg.com/eslint-utils/-/eslint-utils-3.0.0.tgz#8aebaface7345bb33559db0a1f13a1d2d48c3672" integrity sha512-uuQC43IGctw68pJA1RgbQS8/NP7rch6Cwd4j3ZBtgo4/8Flj4eGE7ZYSZRN3iq5pVUv6GPdW5Z1RFleo84uLDA== dependencies: eslint-visitor-keys "^2.0.0" eslint-visitor-keys@^2.0.0: version "2.1.0" - resolved "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-2.1.0.tgz" + resolved "https://registry.yarnpkg.com/eslint-visitor-keys/-/eslint-visitor-keys-2.1.0.tgz#f65328259305927392c938ed44eb0a5c9b2bd303" integrity sha512-0rSmRBzXgDzIsD6mGdJgevzgezI534Cer5L/vyMX0kHzT/jiB43jRhd9YUlMGYLQy2zprNmoT8qasCGtY+QaKw== eslint-visitor-keys@^3.3.0: version "3.3.0" - resolved "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-3.3.0.tgz" + resolved "https://registry.yarnpkg.com/eslint-visitor-keys/-/eslint-visitor-keys-3.3.0.tgz#f6480fa6b1f30efe2d1968aa8ac745b862469826" integrity sha512-mQ+suqKJVyeuwGYHAdjMFqjCyfl8+Ldnxuyp3ldiMBFKkvytrXUZWaiPCEav8qDHKty44bD+qV1IP4T+w+xXRA== eslint@^8.23.0: @@ -2439,7 +2455,7 @@ eslint@^8.23.0: espree@^9.4.0: version "9.4.0" - resolved "https://registry.npmjs.org/espree/-/espree-9.4.0.tgz" + resolved "https://registry.yarnpkg.com/espree/-/espree-9.4.0.tgz#cd4bc3d6e9336c433265fc0aa016fc1aaf182f8a" integrity sha512-DQmnRpLj7f6TgN/NYb0MTzJXL+vJF9h3pHy4JhCIs3zwcgez8xmGg3sXHcEO97BrmO2OSvCwMdfdlyl+E9KjOw== dependencies: acorn "^8.8.0" @@ -2448,41 +2464,41 @@ espree@^9.4.0: esquery@^1.4.0: version "1.4.0" - resolved "https://registry.npmjs.org/esquery/-/esquery-1.4.0.tgz" + resolved "https://registry.yarnpkg.com/esquery/-/esquery-1.4.0.tgz#2148ffc38b82e8c7057dfed48425b3e61f0f24a5" integrity sha512-cCDispWt5vHHtwMY2YrAQ4ibFkAL8RbH5YGBnZBc90MolvvfkkQcJro/aZiAQUlQ3qgrYS6D6v8Gc5G5CQsc9w== dependencies: estraverse "^5.1.0" esrecurse@^4.3.0: version "4.3.0" - resolved "https://registry.npmjs.org/esrecurse/-/esrecurse-4.3.0.tgz" + resolved "https://registry.yarnpkg.com/esrecurse/-/esrecurse-4.3.0.tgz#7ad7964d679abb28bee72cec63758b1c5d2c9921" integrity sha512-KmfKL3b6G+RXvP8N1vr3Tq1kL/oCFgn2NYXEtqP8/L3pKapUA4G8cFVaoF3SU323CD4XypR/ffioHmkti6/Tag== dependencies: estraverse "^5.2.0" estraverse@^4.1.1: version "4.3.0" - resolved "https://registry.npmjs.org/estraverse/-/estraverse-4.3.0.tgz" + resolved "https://registry.yarnpkg.com/estraverse/-/estraverse-4.3.0.tgz#398ad3f3c5a24948be7725e83d11a7de28cdbd1d" integrity sha512-39nnKffWz8xN1BU/2c79n9nB9HDzo0niYUqx6xyqUnyoAnQyyWpOTdZEeiCch8BBu515t4wp9ZmgVfVhn9EBpw== estraverse@^5.1.0, estraverse@^5.2.0: version "5.3.0" - resolved "https://registry.npmjs.org/estraverse/-/estraverse-5.3.0.tgz" + resolved "https://registry.yarnpkg.com/estraverse/-/estraverse-5.3.0.tgz#2eea5290702f26ab8fe5370370ff86c965d21123" integrity sha512-MMdARuVEQziNTeJD8DgMqmhwR11BRQ/cBP+pLtYdSTnf3MIO8fFeiINEbX36ZdNlfU/7A9f3gUw49B3oQsvwBA== estree-walker@^2.0.1: version "2.0.2" - resolved "https://registry.npmjs.org/estree-walker/-/estree-walker-2.0.2.tgz" + resolved "https://registry.yarnpkg.com/estree-walker/-/estree-walker-2.0.2.tgz#52f010178c2a4c117a7757cfe942adb7d2da4cac" integrity sha512-Rfkk/Mp/DL7JVje3u18FxFujQlTNR2q6QfMSMB7AvCBx91NGj/ba3kCfza0f6dVDbw7YlRf/nDrn7pQrCCyQ/w== esutils@^2.0.2: version "2.0.3" - resolved "https://registry.npmjs.org/esutils/-/esutils-2.0.3.tgz" + resolved "https://registry.yarnpkg.com/esutils/-/esutils-2.0.3.tgz#74d2eb4de0b8da1293711910d50775b9b710ef64" integrity sha512-kVscqXk4OCp68SZ0dkgEKVi6/8ij300KBWTJq32P/dYeWTSwK41WyTxalN1eRmA5Z9UU/LX9D7FWSmV9SAYx6g== event-stream@=3.3.4: version "3.3.4" - resolved "https://registry.npmjs.org/event-stream/-/event-stream-3.3.4.tgz" + resolved "https://registry.yarnpkg.com/event-stream/-/event-stream-3.3.4.tgz#4ab4c9a0f5a54db9338b4c34d86bfce8f4b35571" integrity sha512-QHpkERcGsR0T7Qm3HNJSyXKEEj8AHNxkY3PK8TS2KJvQ7NiSHe3DDpwVKKtoYprL/AreyzFBeIkBIWChAqn60g== dependencies: duplexer "~0.1.1" @@ -2495,17 +2511,17 @@ event-stream@=3.3.4: fast-deep-equal@^3.1.1, fast-deep-equal@^3.1.3: version "3.1.3" - resolved "https://registry.npmjs.org/fast-deep-equal/-/fast-deep-equal-3.1.3.tgz" + resolved "https://registry.yarnpkg.com/fast-deep-equal/-/fast-deep-equal-3.1.3.tgz#3a7d56b559d6cbc3eb512325244e619a65c6c525" integrity sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q== fast-diff@^1.1.2: version "1.2.0" - resolved "https://registry.npmjs.org/fast-diff/-/fast-diff-1.2.0.tgz" + resolved "https://registry.yarnpkg.com/fast-diff/-/fast-diff-1.2.0.tgz#73ee11982d86caaf7959828d519cfe927fac5f03" integrity sha512-xJuoT5+L99XlZ8twedaRf6Ax2TgQVxvgZOYoPKqZufmJib0tL2tegPBOZb1pVNgIhlqDlA0eO0c3wBvQcmzx4w== fast-glob@^3.2.9: version "3.2.12" - resolved "https://registry.npmjs.org/fast-glob/-/fast-glob-3.2.12.tgz" + resolved "https://registry.yarnpkg.com/fast-glob/-/fast-glob-3.2.12.tgz#7f39ec99c2e6ab030337142da9e0c18f37afae80" integrity sha512-DVj4CQIYYow0BlaelwK1pHl5n5cRSJfM60UA0zK891sVInoPri2Ekj7+e1CT3/3qxXenpI+nBBmQAcJPJgaj4w== dependencies: "@nodelib/fs.stat" "^2.0.2" @@ -2516,50 +2532,50 @@ fast-glob@^3.2.9: fast-json-stable-stringify@^2.0.0: version "2.1.0" - resolved "https://registry.npmjs.org/fast-json-stable-stringify/-/fast-json-stable-stringify-2.1.0.tgz" + resolved "https://registry.yarnpkg.com/fast-json-stable-stringify/-/fast-json-stable-stringify-2.1.0.tgz#874bf69c6f404c2b5d99c481341399fd55892633" integrity sha512-lhd/wF+Lk98HZoTCtlVraHtfh5XYijIjalXck7saUtuanSDyLMxnHhSXEDJqHxD7msR8D0uCmqlkwjCV8xvwHw== fast-levenshtein@^2.0.6: version "2.0.6" - resolved "https://registry.npmjs.org/fast-levenshtein/-/fast-levenshtein-2.0.6.tgz" + resolved "https://registry.yarnpkg.com/fast-levenshtein/-/fast-levenshtein-2.0.6.tgz#3d8a5c66883a16a30ca8643e851f19baa7797917" integrity sha512-DCXu6Ifhqcks7TZKY3Hxp3y6qphY5SJZmrWMDrKcERSOXWQdMhU9Ig/PYrzyw/ul9jOIyh0N4M0tbC5hodg8dw== fastq@^1.6.0: version "1.13.0" - resolved "https://registry.npmjs.org/fastq/-/fastq-1.13.0.tgz" + resolved "https://registry.yarnpkg.com/fastq/-/fastq-1.13.0.tgz#616760f88a7526bdfc596b7cab8c18938c36b98c" integrity sha512-YpkpUnK8od0o1hmeSc7UUs/eB/vIPWJYjKck2QKIzAf71Vm1AAQ3EbuZB3g2JIy+pg+ERD0vqI79KyZiB2e2Nw== dependencies: reusify "^1.0.4" file-entry-cache@^6.0.1: version "6.0.1" - resolved "https://registry.npmjs.org/file-entry-cache/-/file-entry-cache-6.0.1.tgz" + resolved "https://registry.yarnpkg.com/file-entry-cache/-/file-entry-cache-6.0.1.tgz#211b2dd9659cb0394b073e7323ac3c933d522027" integrity sha512-7Gps/XWymbLk2QLYK4NzpMOrYjMhdIxXuIvy2QBsLE6ljuodKvdkWs/cpyJJ3CVIVpH0Oi1Hvg1ovbMzLdFBBg== dependencies: flat-cache "^3.0.4" file-selector@^0.6.0: version "0.6.0" - resolved "https://registry.npmjs.org/file-selector/-/file-selector-0.6.0.tgz" + resolved "https://registry.yarnpkg.com/file-selector/-/file-selector-0.6.0.tgz#fa0a8d9007b829504db4d07dd4de0310b65287dc" integrity sha512-QlZ5yJC0VxHxQQsQhXvBaC7VRJ2uaxTf+Tfpu4Z/OcVQJVpZO+DGU0rkoVW5ce2SccxugvpBJoMvUs59iILYdw== dependencies: tslib "^2.4.0" fill-range@^7.0.1: version "7.0.1" - resolved "https://registry.npmjs.org/fill-range/-/fill-range-7.0.1.tgz" + resolved "https://registry.yarnpkg.com/fill-range/-/fill-range-7.0.1.tgz#1919a6a7c75fe38b2c7c77e5198535da9acdda40" integrity sha512-qOo9F+dMUmC2Lcb4BbVvnKJxTPjCm+RRpe4gDuGrzkL7mEVl/djYSu2OdQ2Pa302N4oqkSg9ir6jaLWJ2USVpQ== dependencies: to-regex-range "^5.0.1" find-root@^1.1.0: version "1.1.0" - resolved "https://registry.npmjs.org/find-root/-/find-root-1.1.0.tgz" + resolved "https://registry.yarnpkg.com/find-root/-/find-root-1.1.0.tgz#abcfc8ba76f708c42a97b3d685b7e9450bfb9ce4" integrity sha512-NKfW6bec6GfKc0SGx1e07QZY9PE99u0Bft/0rzSD5k3sO/vwkVUpDUKVm5Gpp5Ue3YfShPFTX2070tDs5kB9Ng== find-up@^5.0.0: version "5.0.0" - resolved "https://registry.npmjs.org/find-up/-/find-up-5.0.0.tgz" + resolved "https://registry.yarnpkg.com/find-up/-/find-up-5.0.0.tgz#4c92819ecb7083561e4f4a240a86be5198f536fc" integrity sha512-78/PXT1wlLLDgTzDs7sjq9hzz0vXD+zn+7wypEe4fXQxCmdmqfGsEPQxmiCSQI3ajFV91bVSsvNtrJRiW6nGng== dependencies: locate-path "^6.0.0" @@ -2567,7 +2583,7 @@ find-up@^5.0.0: flat-cache@^3.0.4: version "3.0.4" - resolved "https://registry.npmjs.org/flat-cache/-/flat-cache-3.0.4.tgz" + resolved "https://registry.yarnpkg.com/flat-cache/-/flat-cache-3.0.4.tgz#61b0338302b2fe9f957dcc32fc2a87f1c3048b11" integrity sha512-dm9s5Pw7Jc0GvMYbshN6zchCA9RgQlzzEZX3vylR9IqFfS8XciblUXOKfW6SiuJ0e13eDYZoZV5wdrev7P3Nwg== dependencies: flatted "^3.1.0" @@ -2575,7 +2591,7 @@ flat-cache@^3.0.4: flatted@^3.1.0: version "3.2.7" - resolved "https://registry.npmjs.org/flatted/-/flatted-3.2.7.tgz" + resolved "https://registry.yarnpkg.com/flatted/-/flatted-3.2.7.tgz#609f39207cb614b89d0765b477cb2d437fbf9787" integrity sha512-5nqDSxl8nn5BSNxyR3n4I6eDmbolI6WT+QqR547RwxQapgjQBmtktdP+HTBb/a/zLsbzERTONyUB5pefh5TtjQ== focus-lock@^0.11.2: @@ -2586,9 +2602,9 @@ focus-lock@^0.11.2: tslib "^2.0.3" framer-motion@^7.2.1: - version "7.6.2" - resolved "https://registry.yarnpkg.com/framer-motion/-/framer-motion-7.6.2.tgz#7fb93ebfeda27c8c2cff1895ca7a417229e81bf7" - integrity sha512-YRr+KaC+1MlLx7iArVyjZRpc0QXI7H0XIOJrdol+dF1+WLQJwS2sP04KGq808BG+byD36UAmAt4YqObE5YFLtw== + version "7.6.4" + resolved "https://registry.yarnpkg.com/framer-motion/-/framer-motion-7.6.4.tgz#e396b36f68a14e14cc95b01210feac8cd5d2824d" + integrity sha512-Ac3Bl9M45fS8A0ibOUnYMSCfjaCrFfWT0uh0/MZVm/DGWcr5IsRRinWRiVGABA9RGJgn4THehqcn235JVQkucQ== dependencies: "@motionone/dom" "10.13.1" framesync "6.1.2" @@ -2601,36 +2617,36 @@ framer-motion@^7.2.1: framesync@5.3.0: version "5.3.0" - resolved "https://registry.npmjs.org/framesync/-/framesync-5.3.0.tgz" + resolved "https://registry.yarnpkg.com/framesync/-/framesync-5.3.0.tgz#0ecfc955e8f5a6ddc8fdb0cc024070947e1a0d9b" integrity sha512-oc5m68HDO/tuK2blj7ZcdEBRx3p1PjrgHazL8GYEpvULhrtGIFbQArN6cQS2QhW8mitffaB+VYzMjDqBxxQeoA== dependencies: tslib "^2.1.0" framesync@6.1.2: version "6.1.2" - resolved "https://registry.npmjs.org/framesync/-/framesync-6.1.2.tgz" + resolved "https://registry.yarnpkg.com/framesync/-/framesync-6.1.2.tgz#755eff2fb5b8f3b4d2b266dd18121b300aefea27" integrity sha512-jBTqhX6KaQVDyus8muwZbBeGGP0XgujBRbQ7gM7BRdS3CadCZIHiawyzYLnafYcvZIh5j8WE7cxZKFn7dXhu9g== dependencies: tslib "2.4.0" from@~0: version "0.1.7" - resolved "https://registry.npmjs.org/from/-/from-0.1.7.tgz" + resolved "https://registry.yarnpkg.com/from/-/from-0.1.7.tgz#83c60afc58b9c56997007ed1a768b3ab303a44fe" integrity sha512-twe20eF1OxVxp/ML/kq2p1uc6KvFK/+vs8WjEbeKmV2He22MKm7YF2ANIt+EOqhJ5L3K/SuuPhk0hWQDjOM23g== fs.realpath@^1.0.0: version "1.0.0" - resolved "https://registry.npmjs.org/fs.realpath/-/fs.realpath-1.0.0.tgz" + resolved "https://registry.yarnpkg.com/fs.realpath/-/fs.realpath-1.0.0.tgz#1504ad2523158caa40db4a2787cb01411994ea4f" integrity sha512-OO0pH2lK6a0hZnAdau5ItzHPI6pUlvI7jMVnxUQRtw4owF2wk8lOSabtGDCTP4Ggrg2MbGnWO9X8K1t4+fGMDw== fsevents@~2.3.2: version "2.3.2" - resolved "https://registry.npmjs.org/fsevents/-/fsevents-2.3.2.tgz" + resolved "https://registry.yarnpkg.com/fsevents/-/fsevents-2.3.2.tgz#8a526f78b8fdf4623b709e0b975c52c24c02fd1a" integrity sha512-xiqMQR4xAeHTuB9uWm+fFRcIOgKBMiOBP+eXiyT7jsgVCq1bkVygt00oASowB7EdtpOHaaPgKt812P9ab+DDKA== function-bind@^1.1.1: version "1.1.1" - resolved "https://registry.npmjs.org/function-bind/-/function-bind-1.1.1.tgz" + resolved "https://registry.yarnpkg.com/function-bind/-/function-bind-1.1.1.tgz#a56899d3ea3c9bab874bb9773b7c5ede92f4895d" integrity sha512-yIovAzMX49sF8Yl58fSCWJ5svSLuaibPxXQJFLmBObTuCr0Mf1KiPopGM9NiFjiYBCbfaa2Fh6breQ6ANVTI0A== gensync@^1.0.0-beta.2: @@ -2640,12 +2656,12 @@ gensync@^1.0.0-beta.2: get-nonce@^1.0.0: version "1.0.1" - resolved "https://registry.npmjs.org/get-nonce/-/get-nonce-1.0.1.tgz" + resolved "https://registry.yarnpkg.com/get-nonce/-/get-nonce-1.0.1.tgz#fdf3f0278073820d2ce9426c18f07481b1e0cdf3" integrity sha512-FJhYRoDaiatfEkUK8HKlicmu/3SGFD51q3itKDGoSTysQJBnfOcxU5GxnhE1E6soB76MbT0MBtnKJuXyAx+96Q== glob-parent@^5.1.2, glob-parent@~5.1.2: version "5.1.2" - resolved "https://registry.npmjs.org/glob-parent/-/glob-parent-5.1.2.tgz" + resolved "https://registry.yarnpkg.com/glob-parent/-/glob-parent-5.1.2.tgz#869832c58034fe68a4093c17dc15e8340d8401c4" integrity sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow== dependencies: is-glob "^4.0.1" @@ -2657,9 +2673,26 @@ glob-parent@^6.0.2: dependencies: is-glob "^4.0.3" +glob-regex@^0.3.0: + version "0.3.2" + resolved "https://registry.yarnpkg.com/glob-regex/-/glob-regex-0.3.2.tgz#27348f2f60648ec32a4a53137090b9fb934f3425" + integrity sha512-m5blUd3/OqDTWwzBBtWBPrGlAzatRywHameHeekAZyZrskYouOGdNB8T/q6JucucvJXtOuyHIn0/Yia7iDasDw== + +glob@7.1.6: + version "7.1.6" + resolved "https://registry.yarnpkg.com/glob/-/glob-7.1.6.tgz#141f33b81a7c2492e125594307480c46679278a6" + integrity sha512-LwaxwyZ72Lk7vZINtNNrywX0ZuLyStrdDtabefZKAY5ZGJhVtgdznluResxNmPitE0SAO+O26sWTHeKSI2wMBA== + dependencies: + fs.realpath "^1.0.0" + inflight "^1.0.4" + inherits "2" + minimatch "^3.0.4" + once "^1.3.0" + path-is-absolute "^1.0.0" + glob@^7.1.3: version "7.2.3" - resolved "https://registry.npmjs.org/glob/-/glob-7.2.3.tgz" + resolved "https://registry.yarnpkg.com/glob/-/glob-7.2.3.tgz#b8df0fb802bbfa8e89bd1d938b4e16578ed44f2b" integrity sha512-nFR0zLpU2YCaRxwoCJvL6UvCH2JFyFVIvwTLsIf21AuHlMskA1hhTdk+LlYJtOlYt9v6dvszD2BGRqBL+iQK9Q== dependencies: fs.realpath "^1.0.0" @@ -2671,19 +2704,19 @@ glob@^7.1.3: globals@^11.1.0: version "11.12.0" - resolved "https://registry.npmjs.org/globals/-/globals-11.12.0.tgz" + resolved "https://registry.yarnpkg.com/globals/-/globals-11.12.0.tgz#ab8795338868a0babd8525758018c2a7eb95c42e" integrity sha512-WOBp/EEGUiIsJSp7wcv/y6MO+lV9UoncWqxuFfm8eBwzWNgyfBd6Gz+IeKQ9jCmyhoH99g15M3T+QaVHFjizVA== globals@^13.15.0: version "13.17.0" - resolved "https://registry.npmjs.org/globals/-/globals-13.17.0.tgz" + resolved "https://registry.yarnpkg.com/globals/-/globals-13.17.0.tgz#902eb1e680a41da93945adbdcb5a9f361ba69bd4" integrity sha512-1C+6nQRb1GwGMKm2dH/E7enFAMxGTmGI7/dEdhy/DNelv85w9B72t3uc5frtMNXIbzrarJJ/lTCjcaZwbLJmyw== dependencies: type-fest "^0.20.2" globby@^11.1.0: version "11.1.0" - resolved "https://registry.npmjs.org/globby/-/globby-11.1.0.tgz" + resolved "https://registry.yarnpkg.com/globby/-/globby-11.1.0.tgz#bd4be98bb042f83d796f7e3811991fbe82a0d34b" integrity sha512-jhIXaOzy1sb8IyocaruWSn1TjmnBVs8Ayhcy83rmxNJ8q2uWKCAj3CnJY+KpGSXCueAPc0i05kVvVKtP1t9S3g== dependencies: array-union "^2.1.0" @@ -2693,63 +2726,63 @@ globby@^11.1.0: merge2 "^1.4.1" slash "^3.0.0" +globrex@^0.1.2: + version "0.1.2" + resolved "https://registry.yarnpkg.com/globrex/-/globrex-0.1.2.tgz#dd5d9ec826232730cd6793a5e33a9302985e6098" + integrity sha512-uHJgbwAMwNFf5mLst7IWLNg14x1CkeqglJb/K3doi4dw6q2IvAAmM/Y81kevy83wP+Sst+nutFTYOGg3d1lsxg== + grapheme-splitter@^1.0.4: version "1.0.4" - resolved "https://registry.npmjs.org/grapheme-splitter/-/grapheme-splitter-1.0.4.tgz" + resolved "https://registry.yarnpkg.com/grapheme-splitter/-/grapheme-splitter-1.0.4.tgz#9cf3a665c6247479896834af35cf1dbb4400767e" integrity sha512-bzh50DW9kTPM00T8y4o8vQg89Di9oLJVLW/KaOGIXJWP/iqCN6WKYkbNOF04vFLJhwcpYUh9ydh/+5vpOqV4YQ== has-flag@^3.0.0: version "3.0.0" - resolved "https://registry.npmjs.org/has-flag/-/has-flag-3.0.0.tgz" + resolved "https://registry.yarnpkg.com/has-flag/-/has-flag-3.0.0.tgz#b5d454dc2199ae225699f3467e5a07f3b955bafd" integrity sha512-sKJf1+ceQBr4SMkvQnBDNDtf4TXpVhVGateu0t918bl30FnbE2m4vNLX+VWe/dpjlb+HugGYzW7uQXH98HPEYw== has-flag@^4.0.0: version "4.0.0" - resolved "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz" + resolved "https://registry.yarnpkg.com/has-flag/-/has-flag-4.0.0.tgz#944771fd9c81c81265c4d6941860da06bb59479b" integrity sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ== has@^1.0.3: version "1.0.3" - resolved "https://registry.npmjs.org/has/-/has-1.0.3.tgz" + resolved "https://registry.yarnpkg.com/has/-/has-1.0.3.tgz#722d7cbfc1f6aa8241f16dd814e011e1f41e8796" integrity sha512-f2dvO0VU6Oej7RkWJGrehjbzMAjFp5/VKPp5tTpWIV4JHHZK1/BxbFRtf/siA2SWTe09caDmVtYYzWEIbBS4zw== dependencies: function-bind "^1.1.1" hey-listen@^1.0.8: version "1.0.8" - resolved "https://registry.npmjs.org/hey-listen/-/hey-listen-1.0.8.tgz" + resolved "https://registry.yarnpkg.com/hey-listen/-/hey-listen-1.0.8.tgz#8e59561ff724908de1aa924ed6ecc84a56a9aa68" integrity sha512-COpmrF2NOg4TBWUJ5UVyaCU2A88wEMkUPK4hNqyCkqHbxT92BbvfjoSozkAIIm6XhicGlJHhFdullInrdhwU8Q== hoist-non-react-statics@^3.3.0, hoist-non-react-statics@^3.3.1, hoist-non-react-statics@^3.3.2: version "3.3.2" - resolved "https://registry.npmjs.org/hoist-non-react-statics/-/hoist-non-react-statics-3.3.2.tgz" + resolved "https://registry.yarnpkg.com/hoist-non-react-statics/-/hoist-non-react-statics-3.3.2.tgz#ece0acaf71d62c2969c2ec59feff42a4b1a85b45" integrity sha512-/gGivxi8JPKWNm/W0jSmzcMPpfpPLc3dY/6GxhX2hQ9iGj3aDfklV4ET7NjKpSinLpJ5vafa9iiGIEZg10SfBw== dependencies: react-is "^16.7.0" -hotkeys-js@3.9.4: - version "3.9.4" - resolved "https://registry.npmjs.org/hotkeys-js/-/hotkeys-js-3.9.4.tgz" - integrity sha512-2zuLt85Ta+gIyvs4N88pCYskNrxf1TFv3LR9t5mdAZIX8BcgQQ48F2opUptvHa6m8zsy5v/a0i9mWzTrlNWU0Q== - ignore@^5.2.0: version "5.2.0" - resolved "https://registry.npmjs.org/ignore/-/ignore-5.2.0.tgz" + resolved "https://registry.yarnpkg.com/ignore/-/ignore-5.2.0.tgz#6d3bac8fa7fe0d45d9f9be7bac2fc279577e345a" integrity sha512-CmxgYGiEPCLhfLnpPp1MoRmifwEIOgjcHXxOBjv7mY96c+eWScsOP9c112ZyLdWHi0FxHjI+4uVhKYp/gcdRmQ== -immer@^9.0.7: +immer@^9.0.16: version "9.0.16" resolved "https://registry.yarnpkg.com/immer/-/immer-9.0.16.tgz#8e7caab80118c2b54b37ad43e05758cdefad0198" integrity sha512-qenGE7CstVm1NrHQbMh8YaSzTZTFNP3zPqr3YU0S0UY441j4bJTg4A2Hh5KAhwgaiU6ZZ1Ar6y/2f4TblnMReQ== immutable@^4.0.0: version "4.1.0" - resolved "https://registry.npmjs.org/immutable/-/immutable-4.1.0.tgz" + resolved "https://registry.yarnpkg.com/immutable/-/immutable-4.1.0.tgz#f795787f0db780183307b9eb2091fcac1f6fafef" integrity sha512-oNkuqVTA8jqG1Q6c+UglTOD1xhC1BtjKI7XkCXRkZHrN5m18/XsnUp8Q89GkQO/z+0WjonSvl0FLhDYftp46nQ== import-fresh@^3.0.0, import-fresh@^3.2.1: version "3.3.0" - resolved "https://registry.npmjs.org/import-fresh/-/import-fresh-3.3.0.tgz" + resolved "https://registry.yarnpkg.com/import-fresh/-/import-fresh-3.3.0.tgz#37162c25fcb9ebaa2e6e53d5b4d88ce17d9e0c2b" integrity sha512-veYYhQa+D1QBKznvhUHxb8faxlrwUnxseDAbAp457E0wLNio2bOSKnjYDhMj+YiAq61xrMGhQk9iXVk5FzgQMw== dependencies: parent-module "^1.0.0" @@ -2757,12 +2790,12 @@ import-fresh@^3.0.0, import-fresh@^3.2.1: imurmurhash@^0.1.4: version "0.1.4" - resolved "https://registry.npmjs.org/imurmurhash/-/imurmurhash-0.1.4.tgz" + resolved "https://registry.yarnpkg.com/imurmurhash/-/imurmurhash-0.1.4.tgz#9218b9b2b928a238b13dc4fb6b6d576f231453ea" integrity sha512-JmXMZ6wuvDmLiHEml9ykzqO6lwFbof0GG4IkcGaENdCRDDmMVnny7s5HsIgHCbaq0w2MyPhDqkhTUgS2LU2PHA== inflight@^1.0.4: version "1.0.6" - resolved "https://registry.npmjs.org/inflight/-/inflight-1.0.6.tgz" + resolved "https://registry.yarnpkg.com/inflight/-/inflight-1.0.6.tgz#49bd6331d7d02d0c09bc910a1075ba8165b56df9" integrity sha512-k92I/b08q4wvFscXCLvqfsHCrjrF7yiXsQuIVvVE7N82W3+aqpzuUdBbfhWcy/FZR3/4IgflMgKLOsvPDrGCJA== dependencies: once "^1.3.0" @@ -2770,24 +2803,24 @@ inflight@^1.0.4: inherits@2: version "2.0.4" - resolved "https://registry.npmjs.org/inherits/-/inherits-2.0.4.tgz" + resolved "https://registry.yarnpkg.com/inherits/-/inherits-2.0.4.tgz#0fa2c64f932917c3433a0ded55363aae37416b7c" integrity sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ== invariant@^2.2.4: version "2.2.4" - resolved "https://registry.npmjs.org/invariant/-/invariant-2.2.4.tgz" + resolved "https://registry.yarnpkg.com/invariant/-/invariant-2.2.4.tgz#610f3c92c9359ce1db616e538008d23ff35158e6" integrity sha512-phJfQVBuaJM5raOpJjSfkiD6BpbCE4Ns//LaXl6wGYtUBY83nWS6Rf9tXm2e8VaK60JEjYldbPif/A2B1C2gNA== dependencies: loose-envify "^1.0.0" is-arrayish@^0.2.1: version "0.2.1" - resolved "https://registry.npmjs.org/is-arrayish/-/is-arrayish-0.2.1.tgz" + resolved "https://registry.yarnpkg.com/is-arrayish/-/is-arrayish-0.2.1.tgz#77c99840527aa8ecb1a8ba697b80645a7a926a9d" integrity sha512-zz06S8t0ozoDXMG+ube26zeCTNXcKIPJZJi8hBrF4idCLms4CG9QtK7qBl1boi5ODzFpjswb5JPmHCbMpjaYzg== is-binary-path@~2.1.0: version "2.1.0" - resolved "https://registry.npmjs.org/is-binary-path/-/is-binary-path-2.1.0.tgz" + resolved "https://registry.yarnpkg.com/is-binary-path/-/is-binary-path-2.1.0.tgz#ea1f7f3b80f064236e83470f86c09c254fb45b09" integrity sha512-ZMERYes6pDydyuGidse7OsHxtbI7WVeUEozgR/g7rd0xUimYNlvZRE/K2MgZTjWy725IfelLeVcEM97mmtRGXw== dependencies: binary-extensions "^2.0.0" @@ -2801,19 +2834,19 @@ is-core-module@^2.9.0: is-extglob@^2.1.1: version "2.1.1" - resolved "https://registry.npmjs.org/is-extglob/-/is-extglob-2.1.1.tgz" + resolved "https://registry.yarnpkg.com/is-extglob/-/is-extglob-2.1.1.tgz#a88c02535791f02ed37c76a1b9ea9773c833f8c2" integrity sha512-SbKbANkN603Vi4jEZv49LeVJMn4yGwsbzZworEoyEiutsN3nJYdbO36zfhGJ6QEDpOZIFkDtnq5JRxmvl3jsoQ== is-glob@^4.0.0, is-glob@^4.0.1, is-glob@^4.0.3, is-glob@~4.0.1: version "4.0.3" - resolved "https://registry.npmjs.org/is-glob/-/is-glob-4.0.3.tgz" + resolved "https://registry.yarnpkg.com/is-glob/-/is-glob-4.0.3.tgz#64f61e42cbbb2eec2071a9dac0b28ba1e65d5084" integrity sha512-xelSayHH36ZgE7ZWhli7pW34hNbNl8Ojv5KVmkJD4hBdD3th8Tfk9vYasLM+mXWOZhFkgZfxhLSnrwRr4elSSg== dependencies: is-extglob "^2.1.1" is-number@^7.0.0: version "7.0.0" - resolved "https://registry.npmjs.org/is-number/-/is-number-7.0.0.tgz" + resolved "https://registry.yarnpkg.com/is-number/-/is-number-7.0.0.tgz#7535345b896734d5f80c4d06c50955527a14f12b" integrity sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng== is-path-inside@^3.0.3: @@ -2828,7 +2861,7 @@ isexe@^2.0.0: its-fine@^1.0.6: version "1.0.6" - resolved "https://registry.npmjs.org/its-fine/-/its-fine-1.0.6.tgz" + resolved "https://registry.yarnpkg.com/its-fine/-/its-fine-1.0.6.tgz#087b14d71137816dab676d8b57c35a6cd5d2b021" integrity sha512-VZJZPwVT2kxe5KQv+TxCjojfLiUIut8zXDNLTxcM7gJ/xQ/bSPk5M0neZ+j3myy45KKkltY1mm1jyJgx3Fxsdg== dependencies: "@types/react-reconciler" "^0.28.0" @@ -2840,49 +2873,49 @@ js-sdsl@^4.1.4: "js-tokens@^3.0.0 || ^4.0.0", js-tokens@^4.0.0: version "4.0.0" - resolved "https://registry.npmjs.org/js-tokens/-/js-tokens-4.0.0.tgz" + resolved "https://registry.yarnpkg.com/js-tokens/-/js-tokens-4.0.0.tgz#19203fb59991df98e3a287050d4647cdeaf32499" integrity sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ== js-yaml@^4.1.0: version "4.1.0" - resolved "https://registry.npmjs.org/js-yaml/-/js-yaml-4.1.0.tgz" + resolved "https://registry.yarnpkg.com/js-yaml/-/js-yaml-4.1.0.tgz#c1fb65f8f5017901cdd2c951864ba18458a10602" integrity sha512-wpxZs9NoxZaJESJGIZTyDEaYpl0FKSA+FB9aJiyemKhMwkxQg63h4T1KJgUGHpTqPDNRcmmYLugrRjJlBtWvRA== dependencies: argparse "^2.0.1" jsesc@^2.5.1: version "2.5.2" - resolved "https://registry.npmjs.org/jsesc/-/jsesc-2.5.2.tgz" + resolved "https://registry.yarnpkg.com/jsesc/-/jsesc-2.5.2.tgz#80564d2e483dacf6e8ef209650a67df3f0c283a4" integrity sha512-OYu7XEzjkCQ3C5Ps3QIZsQfNpqoJyZZA99wd9aWd05NCtC5pWOkShK2mkL6HXQR6/Cy2lbNdPlZBpuQHXE63gA== json-parse-even-better-errors@^2.3.0: version "2.3.1" - resolved "https://registry.npmjs.org/json-parse-even-better-errors/-/json-parse-even-better-errors-2.3.1.tgz" + resolved "https://registry.yarnpkg.com/json-parse-even-better-errors/-/json-parse-even-better-errors-2.3.1.tgz#7c47805a94319928e05777405dc12e1f7a4ee02d" integrity sha512-xyFwyhro/JEof6Ghe2iz2NcXoj2sloNsWr/XsERDK/oiPCfaNhl5ONfp+jQdAZRQQ0IJWNzH9zIZF7li91kh2w== json-schema-traverse@^0.4.1: version "0.4.1" - resolved "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-0.4.1.tgz" + resolved "https://registry.yarnpkg.com/json-schema-traverse/-/json-schema-traverse-0.4.1.tgz#69f6a87d9513ab8bb8fe63bdb0979c448e684660" integrity sha512-xbbCH5dCYU5T8LcEhhuh7HJ88HXuW3qsI3Y0zOZFKfZEHcpWiHU/Jxzk629Brsab/mMiHQti9wMP+845RPe3Vg== json-stable-stringify-without-jsonify@^1.0.1: version "1.0.1" - resolved "https://registry.npmjs.org/json-stable-stringify-without-jsonify/-/json-stable-stringify-without-jsonify-1.0.1.tgz" + resolved "https://registry.yarnpkg.com/json-stable-stringify-without-jsonify/-/json-stable-stringify-without-jsonify-1.0.1.tgz#9db7b59496ad3f3cfef30a75142d2d930ad72651" integrity sha512-Bdboy+l7tA3OGW6FjyFHWkP5LuByj1Tk33Ljyq0axyzdk9//JSi2u3fP1QSmd1KNwq6VOKYGlAu87CisVir6Pw== json5@^2.2.1: version "2.2.1" - resolved "https://registry.npmjs.org/json5/-/json5-2.2.1.tgz" + resolved "https://registry.yarnpkg.com/json5/-/json5-2.2.1.tgz#655d50ed1e6f95ad1a3caababd2b0efda10b395c" integrity sha512-1hqLFMSrGHRHxav9q9gNjJ5EXznIxGVO09xQRrwplcS8qs28pZ8s8hupZAmqDwZUmVZ2Qb2jnyPOWcDH8m8dlA== konva@^8.3.13: version "8.3.13" - resolved "https://registry.npmjs.org/konva/-/konva-8.3.13.tgz" + resolved "https://registry.yarnpkg.com/konva/-/konva-8.3.13.tgz#c1adc986ddf5dde4790c0ed47eef8d40a313232e" integrity sha512-O5VxHfRfTj4PscTglQH1NimS8+CC5hQYLeB8YQstu8MN/i2L8GjA1T9d7xxzITF2TD5+xcIs5ei7en3cztbNXg== levn@^0.4.1: version "0.4.1" - resolved "https://registry.npmjs.org/levn/-/levn-0.4.1.tgz" + resolved "https://registry.yarnpkg.com/levn/-/levn-0.4.1.tgz#ae4562c007473b932a6200d403268dd2fffc6ade" integrity sha512-+bT2uH4E5LGE7h/n3evcS/sQlJXCpIp6ym8OWJ5eV6+67Dsql/LaaT7qJBAt2rzfoa/5QBGBhxDix1dMt2kQKQ== dependencies: prelude-ls "^1.2.1" @@ -2890,41 +2923,41 @@ levn@^0.4.1: lines-and-columns@^1.1.6: version "1.2.4" - resolved "https://registry.npmjs.org/lines-and-columns/-/lines-and-columns-1.2.4.tgz" + resolved "https://registry.yarnpkg.com/lines-and-columns/-/lines-and-columns-1.2.4.tgz#eca284f75d2965079309dc0ad9255abb2ebc1632" integrity sha512-7ylylesZQ/PV29jhEDl3Ufjo6ZX7gCqJr5F7PKrqc93v7fzSymt1BpwEU8nAUXs8qzzvqhbjhK5QZg6Mt/HkBg== locate-path@^6.0.0: version "6.0.0" - resolved "https://registry.npmjs.org/locate-path/-/locate-path-6.0.0.tgz" + resolved "https://registry.yarnpkg.com/locate-path/-/locate-path-6.0.0.tgz#55321eb309febbc59c4801d931a72452a681d286" integrity sha512-iPZK6eYjbxRu3uB4/WZ3EsEIMJFMqAoopl3R+zuq0UjcAm/MO6KCweDgPfP3elTztoKP3KtnVHxTn2NHBSDVUw== dependencies: p-locate "^5.0.0" lodash.merge@^4.6.2: version "4.6.2" - resolved "https://registry.npmjs.org/lodash.merge/-/lodash.merge-4.6.2.tgz" + resolved "https://registry.yarnpkg.com/lodash.merge/-/lodash.merge-4.6.2.tgz#558aa53b43b661e1925a0afdfa36a9a1085fe57a" integrity sha512-0KpjqXRVvrYyCsX1swR/XTK0va6VQkQM6MNo7PqW77ByjAhoARA8EfrP1N4+KlKj8YS0ZUCtRT/YUuhyYDujIQ== lodash.mergewith@4.6.2: version "4.6.2" - resolved "https://registry.npmjs.org/lodash.mergewith/-/lodash.mergewith-4.6.2.tgz" + resolved "https://registry.yarnpkg.com/lodash.mergewith/-/lodash.mergewith-4.6.2.tgz#617121f89ac55f59047c7aec1ccd6654c6590f55" integrity sha512-GK3g5RPZWTRSeLSpgP8Xhra+pnjBC56q9FZYe1d5RN3TJ35dbkGy3YqBSMbyCrlbi+CM9Z3Jk5yTL7RCsqboyQ== -lodash@^4.17.21: +lodash@4.17.21, lodash@^4.17.21: version "4.17.21" - resolved "https://registry.npmjs.org/lodash/-/lodash-4.17.21.tgz" + resolved "https://registry.yarnpkg.com/lodash/-/lodash-4.17.21.tgz#679591c564c3bffaae8454cf0b3df370c3d6911c" integrity sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg== loose-envify@^1.0.0, loose-envify@^1.1.0, loose-envify@^1.4.0: version "1.4.0" - resolved "https://registry.npmjs.org/loose-envify/-/loose-envify-1.4.0.tgz" + resolved "https://registry.yarnpkg.com/loose-envify/-/loose-envify-1.4.0.tgz#71ee51fa7be4caec1a63839f7e682d8132d30caf" integrity sha512-lyuxPGr/Wfhrlem2CL/UcnUc1zcqKAImBDzukY7Y5F/yQiNdko6+fRLevlw1HgMySw7f611UIY408EtxRSoK3Q== dependencies: js-tokens "^3.0.0 || ^4.0.0" lru-cache@^6.0.0: version "6.0.0" - resolved "https://registry.npmjs.org/lru-cache/-/lru-cache-6.0.0.tgz" + resolved "https://registry.yarnpkg.com/lru-cache/-/lru-cache-6.0.0.tgz#6d6fe6570ebd96aaf90fcad1dafa3b2566db3a94" integrity sha512-Jo6dJ04CmSjuznwJSS3pUeWmd/H0ffTlkXXgwZi+eq1UCmqQwCh+eLsYOYCwY991i2Fah4h1BEMCx4qThGbsiA== dependencies: yallist "^4.0.0" @@ -2938,17 +2971,17 @@ magic-string@^0.26.7: map-stream@~0.1.0: version "0.1.0" - resolved "https://registry.npmjs.org/map-stream/-/map-stream-0.1.0.tgz" + resolved "https://registry.yarnpkg.com/map-stream/-/map-stream-0.1.0.tgz#e56aa94c4c8055a16404a0674b78f215f7c8e194" integrity sha512-CkYQrPYZfWnu/DAmVCpTSX/xHpKZ80eKh2lAkyA6AJTef6bW+6JpbQZN5rofum7da+SyN1bi5ctTm+lTfcCW3g== merge2@^1.3.0, merge2@^1.4.1: version "1.4.1" - resolved "https://registry.npmjs.org/merge2/-/merge2-1.4.1.tgz" + resolved "https://registry.yarnpkg.com/merge2/-/merge2-1.4.1.tgz#4368892f885e907455a6fd7dc55c0c9d404990ae" integrity sha512-8q7VEgMJW4J8tcfVPy8g09NcQwZdbwFEqhe/WZkoIzjn/3TGDwtOCYtXGxA3O8tPzpczCCDgv+P2P5y00ZJOOg== micromatch@^4.0.4: version "4.0.5" - resolved "https://registry.npmjs.org/micromatch/-/micromatch-4.0.5.tgz" + resolved "https://registry.yarnpkg.com/micromatch/-/micromatch-4.0.5.tgz#bc8999a7cbbf77cdc89f132f6e467051b49090c6" integrity sha512-DMy+ERcEW2q8Z2Po+WNXuw3c5YaUSFjAO5GsJqfEl7UjvtIuFKO6ZrKvcItdy98dwFI2N1tg3zNIdKaQT+aNdA== dependencies: braces "^3.0.2" @@ -2956,31 +2989,45 @@ micromatch@^4.0.4: mime-db@1.52.0: version "1.52.0" - resolved "https://registry.npmjs.org/mime-db/-/mime-db-1.52.0.tgz" + resolved "https://registry.yarnpkg.com/mime-db/-/mime-db-1.52.0.tgz#bbabcdc02859f4987301c856e3387ce5ec43bf70" integrity sha512-sPU4uV7dYlvtWJxwwxHD0PuihVNiE7TyAbQ5SWxDCB9mUYvOgroQOwYQQOKPJ8CIbE+1ETVlOoK1UC2nU3gYvg== mime-types@~2.1.34: version "2.1.35" - resolved "https://registry.npmjs.org/mime-types/-/mime-types-2.1.35.tgz" + resolved "https://registry.yarnpkg.com/mime-types/-/mime-types-2.1.35.tgz#381a871b62a734450660ae3deee44813f70d959a" integrity sha512-ZDY+bPm5zTTF+YpCrAU9nK0UgICYPT0QtT1NZWFv4s++TNkcgVaT0g6+4R2uI4MjQjzysHB1zxuWL50hzaeXiw== dependencies: mime-db "1.52.0" -minimatch@^3.0.5, minimatch@^3.1.1, minimatch@^3.1.2: +minimatch@^3.0.4, minimatch@^3.0.5, minimatch@^3.1.1, minimatch@^3.1.2: version "3.1.2" resolved "https://registry.yarnpkg.com/minimatch/-/minimatch-3.1.2.tgz#19cd194bfd3e428f049a70817c038d89ab4be35b" integrity sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw== dependencies: brace-expansion "^1.1.7" +minimist@^1.2.6: + version "1.2.7" + resolved "https://registry.yarnpkg.com/minimist/-/minimist-1.2.7.tgz#daa1c4d91f507390437c6a8bc01078e7000c4d18" + integrity sha512-bzfL1YUZsP41gmu/qjrEk0Q6i2ix/cVeAhbCbqH9u3zYutS1cLg00qhrD0M2MVdCcx4Sc0UpP2eBWo9rotpq6g== + ms@2.1.2: version "2.1.2" - resolved "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz" + resolved "https://registry.yarnpkg.com/ms/-/ms-2.1.2.tgz#d09d1f357b443f493382a8eb3ccd183872ae6009" integrity sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w== +mz@^2.7.0: + version "2.7.0" + resolved "https://registry.yarnpkg.com/mz/-/mz-2.7.0.tgz#95008057a56cafadc2bc63dde7f9ff6955948e32" + integrity sha512-z81GNO7nnYMEhrGh9LeymoE4+Yr0Wn5McHIZMK5cfQCl+NDX08sCZgUc9/6MHni9IWuFLm1Z3HTCXu2z9fN62Q== + dependencies: + any-promise "^1.0.0" + object-assign "^4.0.1" + thenify-all "^1.0.0" + nanoid@^3.3.4: version "3.3.4" - resolved "https://registry.npmjs.org/nanoid/-/nanoid-3.3.4.tgz" + resolved "https://registry.yarnpkg.com/nanoid/-/nanoid-3.3.4.tgz#730b67e3cd09e2deacf03c027c81c9d9dbc5e8ab" integrity sha512-MqBkQh/OHTS2egovRtLk45wEyNXwF+cokD+1YPf9u5VfJiRdAiRwB2froX5Co9Rh20xs4siNPm8naNotSD6RBw== natural-compare-lite@^1.4.0: @@ -2995,39 +3042,39 @@ natural-compare@^1.4.0: negotiator@0.6.3: version "0.6.3" - resolved "https://registry.npmjs.org/negotiator/-/negotiator-0.6.3.tgz" + resolved "https://registry.yarnpkg.com/negotiator/-/negotiator-0.6.3.tgz#58e323a72fedc0d6f9cd4d31fe49f51479590ccd" integrity sha512-+EUsqGPLsM+j/zdChZjsnX51g4XrHFOIXwfnCVPGlQk/k5giakcKsuxCObBRu6DSm9opw/O6slWbJdghQM4bBg== node-cleanup@^2.1.2: version "2.1.2" - resolved "https://registry.npmjs.org/node-cleanup/-/node-cleanup-2.1.2.tgz" + resolved "https://registry.yarnpkg.com/node-cleanup/-/node-cleanup-2.1.2.tgz#7ac19abd297e09a7f72a71545d951b517e4dde2c" integrity sha512-qN8v/s2PAJwGUtr1/hYTpNKlD6Y9rc4p8KSmJXyGdYGZsDGKXrGThikLFP9OCHFeLeEpQzPwiAtdIvBLqm//Hw== node-releases@^2.0.6: version "2.0.6" - resolved "https://registry.npmjs.org/node-releases/-/node-releases-2.0.6.tgz" + resolved "https://registry.yarnpkg.com/node-releases/-/node-releases-2.0.6.tgz#8a7088c63a55e493845683ebf3c828d8c51c5503" integrity sha512-PiVXnNuFm5+iYkLBNeq5211hvO38y63T0i2KKh2KnUs3RpzJ+JtODFjkD8yjLwnDkTYF1eKXheUwdssR+NRZdg== normalize-path@^3.0.0, normalize-path@~3.0.0: version "3.0.0" - resolved "https://registry.npmjs.org/normalize-path/-/normalize-path-3.0.0.tgz" + resolved "https://registry.yarnpkg.com/normalize-path/-/normalize-path-3.0.0.tgz#0dcd69ff23a1c9b11fd0978316644a0388216a65" integrity sha512-6eZs5Ls3WtCisHWp9S2GUy8dqkpGi4BVSz3GaqiE6ezub0512ESztXUwUB6C6IKbQkY2Pnb/mD4WYojCRwcwLA== -object-assign@^4, object-assign@^4.1.1: +object-assign@^4, object-assign@^4.0.1, object-assign@^4.1.1: version "4.1.1" - resolved "https://registry.npmjs.org/object-assign/-/object-assign-4.1.1.tgz" + resolved "https://registry.yarnpkg.com/object-assign/-/object-assign-4.1.1.tgz#2109adc7965887cfc05cbbd442cac8bfbb360863" integrity sha512-rJgTQnkUnH1sFw8yT6VSU3zD3sWmu6sZhIseY8VX+GRu3P6F7Fu+JNDoXfklElbLJSnc3FUQHVe4cU5hj+BcUg== once@^1.3.0: version "1.4.0" - resolved "https://registry.npmjs.org/once/-/once-1.4.0.tgz" + resolved "https://registry.yarnpkg.com/once/-/once-1.4.0.tgz#583b1aa775961d4b113ac17d9c50baef9dd76bd1" integrity sha512-lNaJgI+2Q5URQBkccEKHTQOPaXdUxnZZElQTZY0MFUAuaEqe1E+Nyvgdz/aIyNi6Z9MzO5dv1H8n58/GELp3+w== dependencies: wrappy "1" optionator@^0.9.1: version "0.9.1" - resolved "https://registry.npmjs.org/optionator/-/optionator-0.9.1.tgz" + resolved "https://registry.yarnpkg.com/optionator/-/optionator-0.9.1.tgz#4f236a6373dae0566a6d43e1326674f50c291499" integrity sha512-74RlY5FCnhq4jRxVUPKDaRwrVNXMqsGsiW6AJw4XK8hmtm10wC0ypZBLw5IIp85NZMr91+qd1RvvENwg7jjRFw== dependencies: deep-is "^0.1.3" @@ -3039,28 +3086,28 @@ optionator@^0.9.1: p-limit@^3.0.2: version "3.1.0" - resolved "https://registry.npmjs.org/p-limit/-/p-limit-3.1.0.tgz" + resolved "https://registry.yarnpkg.com/p-limit/-/p-limit-3.1.0.tgz#e1daccbe78d0d1388ca18c64fea38e3e57e3706b" integrity sha512-TYOanM3wGwNGsZN2cVTYPArw454xnXj5qmWF1bEoAc4+cU/ol7GVh7odevjp1FNHduHc3KZMcFduxU5Xc6uJRQ== dependencies: yocto-queue "^0.1.0" p-locate@^5.0.0: version "5.0.0" - resolved "https://registry.npmjs.org/p-locate/-/p-locate-5.0.0.tgz" + resolved "https://registry.yarnpkg.com/p-locate/-/p-locate-5.0.0.tgz#83c8315c6785005e3bd021839411c9e110e6d834" integrity sha512-LaNjtRWUBY++zB5nE/NwcaoMylSPk+S+ZHNB1TzdbMJMny6dynpAGt7X/tl/QYq3TIeE6nxHppbo2LGymrG5Pw== dependencies: p-limit "^3.0.2" parent-module@^1.0.0: version "1.0.1" - resolved "https://registry.npmjs.org/parent-module/-/parent-module-1.0.1.tgz" + resolved "https://registry.yarnpkg.com/parent-module/-/parent-module-1.0.1.tgz#691d2709e78c79fae3a156622452d00762caaaa2" integrity sha512-GQ2EWRpQV8/o+Aw8YqtfZZPfNRWZYkbidE9k5rpl/hC3vtHHBfGm2Ifi6qWV+coDGkrUKZAxE3Lot5kcsRlh+g== dependencies: callsites "^3.0.0" parse-json@^5.0.0: version "5.2.0" - resolved "https://registry.npmjs.org/parse-json/-/parse-json-5.2.0.tgz" + resolved "https://registry.yarnpkg.com/parse-json/-/parse-json-5.2.0.tgz#c76fc66dee54231c962b22bcc8a72cf2f99753cd" integrity sha512-ayCKvm/phCGxOkYRSCM82iDwct8/EonSEgCSxWxD7ve6jHggsFl4fZVQBPRNgQoKiuV/odhFrGzQXZwbifC8Rg== dependencies: "@babel/code-frame" "^7.0.0" @@ -3070,49 +3117,54 @@ parse-json@^5.0.0: path-exists@^4.0.0: version "4.0.0" - resolved "https://registry.npmjs.org/path-exists/-/path-exists-4.0.0.tgz" + resolved "https://registry.yarnpkg.com/path-exists/-/path-exists-4.0.0.tgz#513bdbe2d3b95d7762e8c1137efa195c6c61b5b3" integrity sha512-ak9Qy5Q7jYb2Wwcey5Fpvg2KoAc/ZIhLSLOSBmRmygPsGwkVVt0fZa0qrtMz+m6tJTAHfZQ8FnmB4MG4LWy7/w== path-is-absolute@^1.0.0: version "1.0.1" - resolved "https://registry.npmjs.org/path-is-absolute/-/path-is-absolute-1.0.1.tgz" + resolved "https://registry.yarnpkg.com/path-is-absolute/-/path-is-absolute-1.0.1.tgz#174b9268735534ffbc7ace6bf53a5a9e1b5c5f5f" integrity sha512-AVbw3UJ2e9bq64vSaS9Am0fje1Pa8pbGqTTsmXfaIiMpnr5DlDhfJOuLj9Sf95ZPVDAUerDfEk88MPmPe7UCQg== path-key@^3.1.0: version "3.1.1" - resolved "https://registry.npmjs.org/path-key/-/path-key-3.1.1.tgz" + resolved "https://registry.yarnpkg.com/path-key/-/path-key-3.1.1.tgz#581f6ade658cbba65a0d3380de7753295054f375" integrity sha512-ojmeN0qd+y0jszEtoY48r0Peq5dwMEkIlCOu6Q5f41lfkswXuKtYrhgoTpLnyIcHm24Uhqx+5Tqm2InSwLhE6Q== path-parse@^1.0.7: version "1.0.7" - resolved "https://registry.npmjs.org/path-parse/-/path-parse-1.0.7.tgz" + resolved "https://registry.yarnpkg.com/path-parse/-/path-parse-1.0.7.tgz#fbc114b60ca42b30d9daf5858e4bd68bbedb6735" integrity sha512-LDJzPVEEEPR+y48z93A0Ed0yXb8pAByGWo/k5YYdYgpY2/2EsOsksJrq7lOHxryrVOn1ejG6oAp8ahvOIQD8sw== path-type@^4.0.0: version "4.0.0" - resolved "https://registry.npmjs.org/path-type/-/path-type-4.0.0.tgz" + resolved "https://registry.yarnpkg.com/path-type/-/path-type-4.0.0.tgz#84ed01c0a7ba380afe09d90a8c180dcd9d03043b" integrity sha512-gDKb8aZMDeD/tZWs9P6+q0J9Mwkdl6xMV8TjnGP3qJVJ06bdMgkbBlLU8IdfOsIsFz2BW1rNVT3XuNEl8zPAvw== pause-stream@0.0.11: version "0.0.11" - resolved "https://registry.npmjs.org/pause-stream/-/pause-stream-0.0.11.tgz" + resolved "https://registry.yarnpkg.com/pause-stream/-/pause-stream-0.0.11.tgz#fe5a34b0cbce12b5aa6a2b403ee2e73b602f1445" integrity sha512-e3FBlXLmN/D1S+zHzanP4E/4Z60oFAa3O051qt1pxa7DEJWKAyil6upYVXCWadEnuoqa4Pkc9oUx9zsxYeRv8A== dependencies: through "~2.3" picocolors@^1.0.0: version "1.0.0" - resolved "https://registry.npmjs.org/picocolors/-/picocolors-1.0.0.tgz" + resolved "https://registry.yarnpkg.com/picocolors/-/picocolors-1.0.0.tgz#cb5bdc74ff3f51892236eaf79d68bc44564ab81c" integrity sha512-1fygroTLlHu66zi26VoTDv8yRgm0Fccecssto+MhsZ0D/DGW2sm8E8AjW7NU5VVTRt5GxbeZ5qBuJr+HyLYkjQ== picomatch@^2.0.4, picomatch@^2.2.1, picomatch@^2.2.2, picomatch@^2.3.1: version "2.3.1" - resolved "https://registry.npmjs.org/picomatch/-/picomatch-2.3.1.tgz" + resolved "https://registry.yarnpkg.com/picomatch/-/picomatch-2.3.1.tgz#3ba3833733646d9d3e4995946c1365a67fb07a42" integrity sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA== +pirates@^4.0.1: + version "4.0.5" + resolved "https://registry.yarnpkg.com/pirates/-/pirates-4.0.5.tgz#feec352ea5c3268fb23a37c702ab1699f35a5f3b" + integrity sha512-8V9+HQPupnaXMA23c5hvl69zXvTwTzyAYasnkb0Tts4XvO4CliqONMOnvlq26rkhLC3nWDFBJf73LU1e1VZLaQ== + popmotion@11.0.5: version "11.0.5" - resolved "https://registry.npmjs.org/popmotion/-/popmotion-11.0.5.tgz" + resolved "https://registry.yarnpkg.com/popmotion/-/popmotion-11.0.5.tgz#8e3e014421a0ffa30ecd722564fd2558954e1f7d" integrity sha512-la8gPM1WYeFznb/JqF4GiTkRRPZsfaj2+kCxqQgr2MJylMmIKUwBfWW8Wa5fml/8gmtlD5yI01MP1QCZPWmppA== dependencies: framesync "6.1.2" @@ -3131,19 +3183,19 @@ postcss@^8.4.18: prelude-ls@^1.2.1: version "1.2.1" - resolved "https://registry.npmjs.org/prelude-ls/-/prelude-ls-1.2.1.tgz" + resolved "https://registry.yarnpkg.com/prelude-ls/-/prelude-ls-1.2.1.tgz#debc6489d7a6e6b0e7611888cec880337d316396" integrity sha512-vkcDPrRZo1QZLbn5RLGPpg/WmIQ65qoWWhcGKf/b5eplkkarX0m9z8ppCat4mlOqUsWpyNuYgO3VRyrYHSzX5g== prettier-linter-helpers@^1.0.0: version "1.0.0" - resolved "https://registry.npmjs.org/prettier-linter-helpers/-/prettier-linter-helpers-1.0.0.tgz" + resolved "https://registry.yarnpkg.com/prettier-linter-helpers/-/prettier-linter-helpers-1.0.0.tgz#d23d41fe1375646de2d0104d3454a3008802cf7b" integrity sha512-GbK2cP9nraSSUF9N2XwUwqfzlAFlMNYYl+ShE/V+H8a9uNl/oUqB1w2EL54Jh0OlyRSd8RfWYJ3coVS4TROP2w== dependencies: fast-diff "^1.1.2" prop-types@^15.6.2, prop-types@^15.8.1: version "15.8.1" - resolved "https://registry.npmjs.org/prop-types/-/prop-types-15.8.1.tgz" + resolved "https://registry.yarnpkg.com/prop-types/-/prop-types-15.8.1.tgz#67d87bf1a694f48435cf332c24af10214a3140b5" integrity sha512-oj87CgZICdulUohogVAR7AjlC0327U4el4L6eAvOqCeudMDVU0NThNaV+b9Df4dXgSP1gXMTnPdhfe/2qDH5cg== dependencies: loose-envify "^1.4.0" @@ -3152,41 +3204,41 @@ prop-types@^15.6.2, prop-types@^15.8.1: ps-tree@^1.2.0: version "1.2.0" - resolved "https://registry.npmjs.org/ps-tree/-/ps-tree-1.2.0.tgz" + resolved "https://registry.yarnpkg.com/ps-tree/-/ps-tree-1.2.0.tgz#5e7425b89508736cdd4f2224d028f7bb3f722ebd" integrity sha512-0VnamPPYHl4uaU/nSFeZZpR21QAWRz+sRv4iW9+v/GS/J5U5iZB5BNN6J0RMoOvdx2gWM2+ZFMIm58q24e4UYA== dependencies: event-stream "=3.3.4" punycode@^2.1.0: version "2.1.1" - resolved "https://registry.npmjs.org/punycode/-/punycode-2.1.1.tgz" + resolved "https://registry.yarnpkg.com/punycode/-/punycode-2.1.1.tgz#b58b010ac40c22c5657616c8d2c2c02c7bf479ec" integrity sha512-XRsRjdf+j5ml+y/6GKHPZbrF/8p2Yga0JPtdqTIY2Xe5ohJPD9saDJJLPvp9+NSBprVvevdXZybnj2cv8OEd0A== queue-microtask@^1.2.2: version "1.2.3" - resolved "https://registry.npmjs.org/queue-microtask/-/queue-microtask-1.2.3.tgz" + resolved "https://registry.yarnpkg.com/queue-microtask/-/queue-microtask-1.2.3.tgz#4929228bbc724dfac43e0efb058caf7b6cfb6243" integrity sha512-NuaNSa6flKT5JaSYQzJok04JzTL1CA6aGhv5rfLW3PgqA+M2ChpZQnAC8h8i4ZFkBS8X5RqkDBHA7r4hej3K9A== re-resizable@^6.9.9: version "6.9.9" - resolved "https://registry.npmjs.org/re-resizable/-/re-resizable-6.9.9.tgz" + resolved "https://registry.yarnpkg.com/re-resizable/-/re-resizable-6.9.9.tgz#99e8b31c67a62115dc9c5394b7e55892265be216" integrity sha512-l+MBlKZffv/SicxDySKEEh42hR6m5bAHfNu3Tvxks2c4Ah+ldnWjfnVRwxo/nxF27SsUsxDS0raAzFuJNKABXA== react-clientside-effect@^1.2.6: version "1.2.6" - resolved "https://registry.npmjs.org/react-clientside-effect/-/react-clientside-effect-1.2.6.tgz" + resolved "https://registry.yarnpkg.com/react-clientside-effect/-/react-clientside-effect-1.2.6.tgz#29f9b14e944a376b03fb650eed2a754dd128ea3a" integrity sha512-XGGGRQAKY+q25Lz9a/4EPqom7WRjz3z9R2k4jhVKA/puQFH/5Nt27vFZYql4m4NVNdUvX8PS3O7r/Zzm7cjUlg== dependencies: "@babel/runtime" "^7.12.13" react-colorful@^5.6.1: version "5.6.1" - resolved "https://registry.npmjs.org/react-colorful/-/react-colorful-5.6.1.tgz" + resolved "https://registry.yarnpkg.com/react-colorful/-/react-colorful-5.6.1.tgz#7dc2aed2d7c72fac89694e834d179e32f3da563b" integrity sha512-1exovf0uGTGyq5mXQT0zgQ80uvj2PCwvF8zY1RN9/vbJVSjSo3fsB/4L3ObbF7u70NduSiK4xu4Y6q1MHoUGEw== react-dom@^18.2.0: version "18.2.0" - resolved "https://registry.npmjs.org/react-dom/-/react-dom-18.2.0.tgz" + resolved "https://registry.yarnpkg.com/react-dom/-/react-dom-18.2.0.tgz#22aaf38708db2674ed9ada224ca4aa708d821e3d" integrity sha512-6IMTriUmvsjHUjNtEDudZfuDQUoWXVxKHhlEGSk81n4YFS+r/Kl99wXiwlVXtPBtJenozv2P+hxDsw9eA7Xo6g== dependencies: loose-envify "^1.1.0" @@ -3203,12 +3255,12 @@ react-dropzone@^14.2.2: react-fast-compare@3.2.0: version "3.2.0" - resolved "https://registry.npmjs.org/react-fast-compare/-/react-fast-compare-3.2.0.tgz" + resolved "https://registry.yarnpkg.com/react-fast-compare/-/react-fast-compare-3.2.0.tgz#641a9da81b6a6320f270e89724fb45a0b39e43bb" integrity sha512-rtGImPZ0YyLrscKI9xTpV8psd6I8VAtjKCzQDlzyDvqJA8XOW78TXYQwNRNd8g8JZnDu8q9Fu/1v4HPAVwVdHA== react-focus-lock@^2.9.1: version "2.9.1" - resolved "https://registry.npmjs.org/react-focus-lock/-/react-focus-lock-2.9.1.tgz" + resolved "https://registry.yarnpkg.com/react-focus-lock/-/react-focus-lock-2.9.1.tgz#094cfc19b4f334122c73bb0bff65d77a0c92dd16" integrity sha512-pSWOQrUmiKLkffPO6BpMXN7SNKXMsuOakl652IBuALAu1esk+IcpJyM+ALcYzPTTFz1rD0R54aB9A4HuP5t1Wg== dependencies: "@babel/runtime" "^7.0.0" @@ -3218,31 +3270,36 @@ react-focus-lock@^2.9.1: use-callback-ref "^1.3.0" use-sidecar "^1.1.2" -react-hotkeys-hook@^3.4.7: - version "3.4.7" - resolved "https://registry.npmjs.org/react-hotkeys-hook/-/react-hotkeys-hook-3.4.7.tgz" - integrity sha512-+bbPmhPAl6ns9VkXkNNyxlmCAIyDAcWbB76O4I0ntr3uWCRuIQf/aRLartUahe9chVMPj+OEzzfk3CQSjclUEQ== +react-hotkeys-hook@4: + version "4.0.3" + resolved "https://registry.yarnpkg.com/react-hotkeys-hook/-/react-hotkeys-hook-4.0.3.tgz#d5158ec6e6831f46145f779feab792257af854fd" + integrity sha512-w2wJ6Wf3yUhkMK+ouEbVaxVpWvFaEoUhRci6KMXyGUJRJuqijV8S7crOiH7597fPlg9gHErbYOV2vPou1vsyZg== dependencies: - hotkeys-js "3.9.4" + lodash "4.17.21" react-icons@^4.4.0: version "4.6.0" resolved "https://registry.yarnpkg.com/react-icons/-/react-icons-4.6.0.tgz#f83eda179af5d02c047449a20b702c858653d397" integrity sha512-rR/L9m9340yO8yv1QT1QurxWQvWpbNHqVX0fzMln2HEb9TEIrQRGsqiNFQfiv9/JEUbyHmHPlNTB2LWm2Ttz0g== +react-image-pan-zoom-rotate@^1.6.0: + version "1.6.0" + resolved "https://registry.yarnpkg.com/react-image-pan-zoom-rotate/-/react-image-pan-zoom-rotate-1.6.0.tgz#4b79dd5a160e61e1ec8d5481541e37ade4c28c6f" + integrity sha512-YpuMjhA9TlcyuC1vcKeTGnECAial0uEsjXUHcCk3GTeznwtnfpgLfMDhejCrilUud/hxueXrr9SJiQiycWjYVA== + react-is@^16.13.1, react-is@^16.7.0: version "16.13.1" - resolved "https://registry.npmjs.org/react-is/-/react-is-16.13.1.tgz" + resolved "https://registry.yarnpkg.com/react-is/-/react-is-16.13.1.tgz#789729a4dc36de2999dc156dd6c1d9c18cea56a4" integrity sha512-24e6ynE2H+OKt4kqsOvNd8kBpV65zoxbA4BVsEOB3ARVWQki/DHzaUoC5KuON/BiccDaCCTZBuOcfZs70kR8bQ== react-is@^18.0.0: version "18.2.0" - resolved "https://registry.npmjs.org/react-is/-/react-is-18.2.0.tgz" + resolved "https://registry.yarnpkg.com/react-is/-/react-is-18.2.0.tgz#199431eeaaa2e09f86427efbb4f1473edb47609b" integrity sha512-xWGDIW6x921xtzPkhiULtthJHoJvBbF3q26fzloPCK0hsvxtPVelvftw3zjbHWSkR2km9Z+4uxbDDK/6Zw9B8w== react-konva@^18.2.3: version "18.2.3" - resolved "https://registry.npmjs.org/react-konva/-/react-konva-18.2.3.tgz" + resolved "https://registry.yarnpkg.com/react-konva/-/react-konva-18.2.3.tgz#75c658fca493bdf515b38f2a8d544fa7a9c754c4" integrity sha512-OPxjBTgaEGU9pt/VJSVM7QNXYHEZ5CkulX+4fTTvbaH+Wh+vMLbXmH3yjWw4kT/5Qi6t0UQKHPPmirCv8/9sdg== dependencies: its-fine "^1.0.6" @@ -3251,16 +3308,16 @@ react-konva@^18.2.3: react-reconciler@~0.29.0: version "0.29.0" - resolved "https://registry.npmjs.org/react-reconciler/-/react-reconciler-0.29.0.tgz" + resolved "https://registry.yarnpkg.com/react-reconciler/-/react-reconciler-0.29.0.tgz#ee769bd362915076753f3845822f2d1046603de7" integrity sha512-wa0fGj7Zht1EYMRhKWwoo1H9GApxYLBuhoAuXN0TlltESAjDssB+Apf0T/DngVqaMyPypDmabL37vw/2aRM98Q== dependencies: loose-envify "^1.1.0" scheduler "^0.23.0" react-redux@^8.0.2: - version "8.0.4" - resolved "https://registry.yarnpkg.com/react-redux/-/react-redux-8.0.4.tgz#80c31dffa8af9526967c4267022ae1525ff0e36a" - integrity sha512-yMfQ7mX6bWuicz2fids6cR1YT59VTuT8MKyyE310wJQlINKENCeT1UcPdEiX6znI5tF8zXyJ/VYvDgeGuaaNwQ== + version "8.0.5" + resolved "https://registry.yarnpkg.com/react-redux/-/react-redux-8.0.5.tgz#e5fb8331993a019b8aaf2e167a93d10af469c7bd" + integrity sha512-Q2f6fCKxPFpkXt1qNRZdEDLlScsDWyrgSj0mliK59qU6W5gvBiKkdMEG2lJzhd1rCctf0hb6EtePPLZ2e0m1uw== dependencies: "@babel/runtime" "^7.12.1" "@types/hoist-non-react-statics" "^3.3.1" @@ -3271,7 +3328,7 @@ react-redux@^8.0.2: react-refresh@^0.14.0: version "0.14.0" - resolved "https://registry.npmjs.org/react-refresh/-/react-refresh-0.14.0.tgz" + resolved "https://registry.yarnpkg.com/react-refresh/-/react-refresh-0.14.0.tgz#4e02825378a5f227079554d4284889354e5f553e" integrity sha512-wViHqhAd8OHeLS/IRMJjTSDHF3U9eWi62F/MledQGPdJGDhodXJ9PBLNGr6WWL7qlH12Mt3TyTpbS+hGXMjCzQ== react-remove-scroll-bar@^2.3.3: @@ -3284,7 +3341,7 @@ react-remove-scroll-bar@^2.3.3: react-remove-scroll@2.5.5, react-remove-scroll@^2.5.4: version "2.5.5" - resolved "https://registry.npmjs.org/react-remove-scroll/-/react-remove-scroll-2.5.5.tgz" + resolved "https://registry.yarnpkg.com/react-remove-scroll/-/react-remove-scroll-2.5.5.tgz#1e31a1260df08887a8a0e46d09271b52b3a37e77" integrity sha512-ImKhrzJJsyXJfBZ4bzu8Bwpka14c/fQt0k+cyFp/PBhTfyDnU5hjOtM4AG/0AMyy8oKzOTR0lDgJIM7pYXI0kw== dependencies: react-remove-scroll-bar "^2.3.3" @@ -3295,7 +3352,7 @@ react-remove-scroll@2.5.5, react-remove-scroll@^2.5.4: react-style-singleton@^2.2.1: version "2.2.1" - resolved "https://registry.npmjs.org/react-style-singleton/-/react-style-singleton-2.2.1.tgz" + resolved "https://registry.yarnpkg.com/react-style-singleton/-/react-style-singleton-2.2.1.tgz#f99e420492b2d8f34d38308ff660b60d0b1205b4" integrity sha512-ZWj0fHEMyWkHzKYUr2Bs/4zU6XLmq9HsgBURm7g5pAVfyn49DgUiNgY2d4lXRlYSiCif9YBGpQleewkcqddc7g== dependencies: get-nonce "^1.0.0" @@ -3304,7 +3361,7 @@ react-style-singleton@^2.2.1: react-transition-group@^4.4.5: version "4.4.5" - resolved "https://registry.npmjs.org/react-transition-group/-/react-transition-group-4.4.5.tgz" + resolved "https://registry.yarnpkg.com/react-transition-group/-/react-transition-group-4.4.5.tgz#e53d4e3f3344da8521489fbef8f2581d42becdd1" integrity sha512-pZcd1MCJoiKiBR2NRxeCRg13uCXbydPnmB4EOeRrY7480qNWO8IIgQG6zlDkm6uRMsURXPuKq0GWtiM59a5Q6g== dependencies: "@babel/runtime" "^7.5.5" @@ -3314,31 +3371,47 @@ react-transition-group@^4.4.5: react@^18.2.0: version "18.2.0" - resolved "https://registry.npmjs.org/react/-/react-18.2.0.tgz" + resolved "https://registry.yarnpkg.com/react/-/react-18.2.0.tgz#555bd98592883255fa00de14f1151a917b5d77d5" integrity sha512-/3IjMdb2L9QbBdWiW5e3P2/npwMBaU9mHCSCUzNln0ZCYbcfTsGbTJrU/kGemdH2IWmB2ioZ+zkxtmq6g09fGQ== dependencies: loose-envify "^1.1.0" readdirp@~3.6.0: version "3.6.0" - resolved "https://registry.npmjs.org/readdirp/-/readdirp-3.6.0.tgz" + resolved "https://registry.yarnpkg.com/readdirp/-/readdirp-3.6.0.tgz#74a370bd857116e245b29cc97340cd431a02a6c7" integrity sha512-hOS089on8RduqdbhvQ5Z37A0ESjsqz6qnRcffsMU3495FuTdqSm+7bhJ29JvIOsBDEEnan5DPu9t3To9VRlMzA== dependencies: picomatch "^2.2.1" +recrawl-sync@^2.0.3: + version "2.2.3" + resolved "https://registry.yarnpkg.com/recrawl-sync/-/recrawl-sync-2.2.3.tgz#757adcdaae4799466dde5b8ee52122ff9636dfb1" + integrity sha512-vSaTR9t+cpxlskkdUFrsEpnf67kSmPk66yAGT1fZPrDudxQjoMzPgQhSMImQ0pAw5k0NPirefQfhopSjhdUtpQ== + dependencies: + "@cush/relative" "^1.0.0" + glob-regex "^0.3.0" + slash "^3.0.0" + sucrase "^3.20.3" + tslib "^1.9.3" + +redux-deep-persist@^1.0.6: + version "1.0.6" + resolved "https://registry.yarnpkg.com/redux-deep-persist/-/redux-deep-persist-1.0.6.tgz#f7f0d15c76463a9c9f31269ea8e612ca7c058980" + integrity sha512-WL/u8MxJGsm0fpywW4zSOWOY3caGi1xx04aYz9UP7QXcqzStVq7fKFf/9g4JYAZ3YRPvukZw0m6O+vt4hTDn9g== + redux-persist@^6.0.0: version "6.0.0" - resolved "https://registry.npmjs.org/redux-persist/-/redux-persist-6.0.0.tgz" + resolved "https://registry.yarnpkg.com/redux-persist/-/redux-persist-6.0.0.tgz#b4d2972f9859597c130d40d4b146fecdab51b3a8" integrity sha512-71LLMbUq2r02ng2We9S215LtPu3fY0KgaGE0k8WRgl6RkqxtGfl7HUozz1Dftwsb0D/5mZ8dwAaPbtnzfvbEwQ== -redux-thunk@^2.4.1: - version "2.4.1" - resolved "https://registry.npmjs.org/redux-thunk/-/redux-thunk-2.4.1.tgz" - integrity sha512-OOYGNY5Jy2TWvTL1KgAlVy6dcx3siPJ1wTq741EPyUKfn6W6nChdICjZwCd0p8AZBs5kWpZlbkXW2nE/zjUa+Q== +redux-thunk@^2.4.2: + version "2.4.2" + resolved "https://registry.yarnpkg.com/redux-thunk/-/redux-thunk-2.4.2.tgz#b9d05d11994b99f7a91ea223e8b04cf0afa5ef3b" + integrity sha512-+P3TjtnP0k/FEjcBL5FZpoovtvrTNT/UXd4/sluaSyrURlSlhLSzEdfsTBW7WsKB6yPvgd7q/iZPICFjW4o57Q== -redux@^4.1.2: +redux@^4.2.0: version "4.2.0" - resolved "https://registry.npmjs.org/redux/-/redux-4.2.0.tgz" + resolved "https://registry.yarnpkg.com/redux/-/redux-4.2.0.tgz#46f10d6e29b6666df758780437651eeb2b969f13" integrity sha512-oSBmcKKIuIR4ME29/AeNUnl5L+hvBq7OaJWzaptTQJAntaPvxIJqfnjbaEiCzzaIz+XmVILfqAM3Ob0aXLPfjA== dependencies: "@babel/runtime" "^7.9.2" @@ -3350,22 +3423,22 @@ regenerator-runtime@^0.13.10: regexpp@^3.2.0: version "3.2.0" - resolved "https://registry.npmjs.org/regexpp/-/regexpp-3.2.0.tgz" + resolved "https://registry.yarnpkg.com/regexpp/-/regexpp-3.2.0.tgz#0425a2768d8f23bad70ca4b90461fa2f1213e1b2" integrity sha512-pq2bWo9mVD43nbts2wGv17XLiNLya+GklZ8kaDLV2Z08gDCsGpnKn9BFMepvWuHCbyVvY7J5o5+BVvoQbmlJLg== -reselect@^4.1.5: - version "4.1.6" - resolved "https://registry.npmjs.org/reselect/-/reselect-4.1.6.tgz" - integrity sha512-ZovIuXqto7elwnxyXbBtCPo9YFEr3uJqj2rRbcOOog1bmu2Ag85M4hixSwFWyaBMKXNgvPaJ9OSu9SkBPIeJHQ== +reselect@^4.1.7: + version "4.1.7" + resolved "https://registry.yarnpkg.com/reselect/-/reselect-4.1.7.tgz#56480d9ff3d3188970ee2b76527bd94a95567a42" + integrity sha512-Zu1xbUt3/OPwsXL46hvOOoQrap2azE7ZQbokq61BQfiXvhewsKDwhMeZjTX9sX0nvw1t/U5Audyn1I9P/m9z0A== resolve-from@^4.0.0: version "4.0.0" - resolved "https://registry.npmjs.org/resolve-from/-/resolve-from-4.0.0.tgz" + resolved "https://registry.yarnpkg.com/resolve-from/-/resolve-from-4.0.0.tgz#4abcd852ad32dd7baabfe9b40e00a36db5f392e6" integrity sha512-pb/MYmXstAkysRFx8piNI1tGFNQIFA3vkE3Gq4EuA1dF6gHp/+vgZqsCGJapvy8N3Q+4o7FwvquPJcnZ7RYy4g== resolve@^1.19.0, resolve@^1.22.1: version "1.22.1" - resolved "https://registry.npmjs.org/resolve/-/resolve-1.22.1.tgz" + resolved "https://registry.yarnpkg.com/resolve/-/resolve-1.22.1.tgz#27cb2ebb53f91abb49470a928bba7558066ac177" integrity sha512-nBpuuYuY5jFsli/JIs1oldw6fOQCBioohqWZg/2hiaOybXOft4lonv85uDOKXdf8rhyK159cxU5cDcK/NKk8zw== dependencies: is-core-module "^2.9.0" @@ -3374,12 +3447,12 @@ resolve@^1.19.0, resolve@^1.22.1: reusify@^1.0.4: version "1.0.4" - resolved "https://registry.npmjs.org/reusify/-/reusify-1.0.4.tgz" + resolved "https://registry.yarnpkg.com/reusify/-/reusify-1.0.4.tgz#90da382b1e126efc02146e90845a88db12925d76" integrity sha512-U9nH88a3fc/ekCF1l0/UP1IosiuIjyTh7hBvXVMHYgVcfGvt897Xguj2UOLDeI5BG2m7/uwyaLVT6fbtCwTyzw== rimraf@^3.0.2: version "3.0.2" - resolved "https://registry.npmjs.org/rimraf/-/rimraf-3.0.2.tgz" + resolved "https://registry.yarnpkg.com/rimraf/-/rimraf-3.0.2.tgz#f1a5402ba6220ad52cc1282bac1ae3aa49fd061a" integrity sha512-JZkJMZkAGFFPP2YqXZXPbMlMBgsxzE8ILs4lMIX/2o0L9UBw9O/Y3o6wFw/i9YLapcUJWwqbi3kdxIPdC62TIA== dependencies: glob "^7.1.3" @@ -3399,9 +3472,9 @@ run-parallel@^1.1.9: queue-microtask "^1.2.2" sass@^1.55.0: - version "1.55.0" - resolved "https://registry.yarnpkg.com/sass/-/sass-1.55.0.tgz#0c4d3c293cfe8f8a2e8d3b666e1cf1bff8065d1c" - integrity sha512-Pk+PMy7OGLs9WaxZGJMn7S96dvlyVBwwtToX895WmCpAOr5YiJYEUJfiJidMuKb613z2xNWcXCHEuOvjZbqC6A== + version "1.56.0" + resolved "https://registry.yarnpkg.com/sass/-/sass-1.56.0.tgz#134032075a3223c8d49cb5c35e091e5ba1de8e0a" + integrity sha512-WFJ9XrpkcnqZcYuLRJh5qiV6ibQOR4AezleeEjTjMsCocYW59dEG19U3fwTTXxzi2Ed3yjPBp727hbbj53pHFw== dependencies: chokidar ">=3.0.0 <4.0.0" immutable "^4.0.0" @@ -3409,14 +3482,14 @@ sass@^1.55.0: scheduler@^0.23.0: version "0.23.0" - resolved "https://registry.npmjs.org/scheduler/-/scheduler-0.23.0.tgz" + resolved "https://registry.yarnpkg.com/scheduler/-/scheduler-0.23.0.tgz#ba8041afc3d30eb206a487b6b384002e4e61fdfe" integrity sha512-CtuThmgHNg7zIZWAXi3AsyIzA3n4xx7aNyjwC2VJldO2LMVDhFK+63xGqq6CsJH4rTAt6/M+N4GhZiDYPx9eUw== dependencies: loose-envify "^1.1.0" semver@^6.3.0: version "6.3.0" - resolved "https://registry.npmjs.org/semver/-/semver-6.3.0.tgz" + resolved "https://registry.yarnpkg.com/semver/-/semver-6.3.0.tgz#ee0a64c8af5e8ceea67687b133761e1becbd1d3d" integrity sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw== semver@^7.3.7: @@ -3428,24 +3501,24 @@ semver@^7.3.7: shebang-command@^2.0.0: version "2.0.0" - resolved "https://registry.npmjs.org/shebang-command/-/shebang-command-2.0.0.tgz" + resolved "https://registry.yarnpkg.com/shebang-command/-/shebang-command-2.0.0.tgz#ccd0af4f8835fbdc265b82461aaf0c36663f34ea" integrity sha512-kHxr2zZpYtdmrN1qDjrrX/Z1rR1kG8Dx+gkpK1G4eXmvXswmcE1hTWBWYUzlraYw1/yZp6YuDY77YtvbN0dmDA== dependencies: shebang-regex "^3.0.0" shebang-regex@^3.0.0: version "3.0.0" - resolved "https://registry.npmjs.org/shebang-regex/-/shebang-regex-3.0.0.tgz" + resolved "https://registry.yarnpkg.com/shebang-regex/-/shebang-regex-3.0.0.tgz#ae16f1644d873ecad843b0307b143362d4c42172" integrity sha512-7++dFhtcx3353uBaq8DDR4NuxBetBzC7ZQOhmTQInHEd6bSrXdiEyzCvG07Z44UYdLShWUyXt5M/yhz8ekcb1A== slash@^3.0.0: version "3.0.0" - resolved "https://registry.npmjs.org/slash/-/slash-3.0.0.tgz" + resolved "https://registry.yarnpkg.com/slash/-/slash-3.0.0.tgz#6539be870c165adbd5240220dbe361f1bc4d4634" integrity sha512-g9Q1haeby36OSStwb4ntCGGGaKsaVSjQ68fBxoQcutl5fS1vuY18H3wSt3jFyFtrkx+Kz0V1G85A4MyAdDMi2Q== socket.io-adapter@~2.4.0: version "2.4.0" - resolved "https://registry.npmjs.org/socket.io-adapter/-/socket.io-adapter-2.4.0.tgz" + resolved "https://registry.yarnpkg.com/socket.io-adapter/-/socket.io-adapter-2.4.0.tgz#b50a4a9ecdd00c34d4c8c808224daa1a786152a6" integrity sha512-W4N+o69rkMEGVuk2D/cvca3uYsvGlMwsySWV447y99gUPghxq42BxqLNMndb+a1mm/5/7NeXVQS7RLa2XyXvYg== socket.io-client@^4.5.2: @@ -3460,7 +3533,7 @@ socket.io-client@^4.5.2: socket.io-parser@~4.2.0: version "4.2.1" - resolved "https://registry.npmjs.org/socket.io-parser/-/socket.io-parser-4.2.1.tgz" + resolved "https://registry.yarnpkg.com/socket.io-parser/-/socket.io-parser-4.2.1.tgz#01c96efa11ded938dcb21cbe590c26af5eff65e5" integrity sha512-V4GrkLy+HeF1F/en3SpUaM+7XxYXpuMUWLGde1kSSh5nQMN4hLrbPIkD+otwh6q9R6NOQBN4AMaOZ2zVjui82g== dependencies: "@socket.io/component-emitter" "~3.1.0" @@ -3480,53 +3553,58 @@ socket.io@^4.5.2: "source-map-js@>=0.6.2 <2.0.0", source-map-js@^1.0.2: version "1.0.2" - resolved "https://registry.npmjs.org/source-map-js/-/source-map-js-1.0.2.tgz" + resolved "https://registry.yarnpkg.com/source-map-js/-/source-map-js-1.0.2.tgz#adbc361d9c62df380125e7f161f71c826f1e490c" integrity sha512-R0XvVJ9WusLiqTCEiGCmICCMplcCkIwwR11mOSD9CR5u+IXYdiseeEuXCVAjS54zqwkLcPNnmU4OeJ6tUrWhDw== source-map@^0.5.7: version "0.5.7" - resolved "https://registry.npmjs.org/source-map/-/source-map-0.5.7.tgz" + resolved "https://registry.yarnpkg.com/source-map/-/source-map-0.5.7.tgz#8a039d2d1021d22d1ea14c80d8ea468ba2ef3fcc" integrity sha512-LbrmJOMUSdEVxIKvdcJzQC+nQhe8FUZQTXQy6+I75skNgn3OoQ0DZA8YnFa7gp8tqtL3KPf1kmo0R5DoApeSGQ== sourcemap-codec@^1.4.8: version "1.4.8" - resolved "https://registry.npmjs.org/sourcemap-codec/-/sourcemap-codec-1.4.8.tgz" + resolved "https://registry.yarnpkg.com/sourcemap-codec/-/sourcemap-codec-1.4.8.tgz#ea804bd94857402e6992d05a38ef1ae35a9ab4c4" integrity sha512-9NykojV5Uih4lgo5So5dtw+f0JgJX30KCNI8gwhz2J9A15wD0Ml6tjHKwf6fTSa6fAdVBdZeNOs9eJ71qCk8vA== split@0.3: version "0.3.3" - resolved "https://registry.npmjs.org/split/-/split-0.3.3.tgz" + resolved "https://registry.yarnpkg.com/split/-/split-0.3.3.tgz#cd0eea5e63a211dfff7eb0f091c4133e2d0dd28f" integrity sha512-wD2AeVmxXRBoX44wAycgjVpMhvbwdI2aZjCkvfNcH1YqHQvJVa1duWc73OyVGJUc05fhFaTZeQ/PYsrmyH0JVA== dependencies: through "2" stream-combiner@~0.0.4: version "0.0.4" - resolved "https://registry.npmjs.org/stream-combiner/-/stream-combiner-0.0.4.tgz" + resolved "https://registry.yarnpkg.com/stream-combiner/-/stream-combiner-0.0.4.tgz#4d5e433c185261dde623ca3f44c586bcf5c4ad14" integrity sha512-rT00SPnTVyRsaSz5zgSPma/aHSOic5U1prhYdRy5HS2kTZviFpmDgzilbtsJsxiroqACmayynDN/9VzIbX5DOw== dependencies: duplexer "~0.1.1" string-argv@^0.1.1: version "0.1.2" - resolved "https://registry.npmjs.org/string-argv/-/string-argv-0.1.2.tgz" + resolved "https://registry.yarnpkg.com/string-argv/-/string-argv-0.1.2.tgz#c5b7bc03fb2b11983ba3a72333dd0559e77e4738" integrity sha512-mBqPGEOMNJKXRo7z0keX0wlAhbBAjilUdPW13nN0PecVryZxdHIeM7TqbsSUA7VYuS00HGC6mojP7DlQzfa9ZA== strip-ansi@^6.0.0, strip-ansi@^6.0.1: version "6.0.1" - resolved "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz" + resolved "https://registry.yarnpkg.com/strip-ansi/-/strip-ansi-6.0.1.tgz#9e26c63d30f53443e9489495b2105d37b67a85d9" integrity sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A== dependencies: ansi-regex "^5.0.1" +strip-bom@^3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/strip-bom/-/strip-bom-3.0.0.tgz#2334c18e9c759f7bdd56fdef7e9ae3d588e68ed3" + integrity sha512-vavAMRXOgBVNF6nyEEmL3DBK19iRpDcoIwW+swQ+CbGiu7lju6t+JklA1MHweoWtadgt4ISVUsXLyDq34ddcwA== + strip-json-comments@^3.1.0, strip-json-comments@^3.1.1: version "3.1.1" - resolved "https://registry.npmjs.org/strip-json-comments/-/strip-json-comments-3.1.1.tgz" + resolved "https://registry.yarnpkg.com/strip-json-comments/-/strip-json-comments-3.1.1.tgz#31f1281b3832630434831c310c01cccda8cbe006" integrity sha512-6fPc+R4ihwqP6N/aIv2f1gMH8lOVtWQHoqC4yK6oSDVVocumAsfCqjkXnqiYMhmMwS/mEHLp7Vehlt3ql6lEig== style-value-types@5.1.2: version "5.1.2" - resolved "https://registry.npmjs.org/style-value-types/-/style-value-types-5.1.2.tgz" + resolved "https://registry.yarnpkg.com/style-value-types/-/style-value-types-5.1.2.tgz#6be66b237bd546048a764883528072ed95713b62" integrity sha512-Vs9fNreYF9j6W2VvuDTP7kepALi7sk0xtk2Tu8Yxi9UoajJdEVpNpCov0HsLTqXvNGKX+Uv09pkozVITi1jf3Q== dependencies: hey-listen "^1.0.8" @@ -3537,33 +3615,59 @@ stylis@4.1.3: resolved "https://registry.yarnpkg.com/stylis/-/stylis-4.1.3.tgz#fd2fbe79f5fed17c55269e16ed8da14c84d069f7" integrity sha512-GP6WDNWf+o403jrEp9c5jibKavrtLW+/qYGhFxFrG8maXhwTBI7gLLhiBb0o7uFccWN+EOS9aMO6cGHWAO07OA== +sucrase@^3.20.3: + version "3.28.0" + resolved "https://registry.yarnpkg.com/sucrase/-/sucrase-3.28.0.tgz#7fd8b3118d2155fcdf291088ab77fa6eefd63c4c" + integrity sha512-TK9600YInjuiIhVM3729rH4ZKPOsGeyXUwY+Ugu9eilNbdTFyHr6XcAGYbRVZPDgWj6tgI7bx95aaJjHnbffag== + dependencies: + commander "^4.0.0" + glob "7.1.6" + lines-and-columns "^1.1.6" + mz "^2.7.0" + pirates "^4.0.1" + ts-interface-checker "^0.1.9" + supports-color@^5.3.0: version "5.5.0" - resolved "https://registry.npmjs.org/supports-color/-/supports-color-5.5.0.tgz" + resolved "https://registry.yarnpkg.com/supports-color/-/supports-color-5.5.0.tgz#e2e69a44ac8772f78a1ec0b35b689df6530efc8f" integrity sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow== dependencies: has-flag "^3.0.0" supports-color@^7.1.0: version "7.2.0" - resolved "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz" + resolved "https://registry.yarnpkg.com/supports-color/-/supports-color-7.2.0.tgz#1b7dcdcb32b8138801b3e478ba6a51caa89648da" integrity sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw== dependencies: has-flag "^4.0.0" supports-preserve-symlinks-flag@^1.0.0: version "1.0.0" - resolved "https://registry.npmjs.org/supports-preserve-symlinks-flag/-/supports-preserve-symlinks-flag-1.0.0.tgz" + resolved "https://registry.yarnpkg.com/supports-preserve-symlinks-flag/-/supports-preserve-symlinks-flag-1.0.0.tgz#6eda4bd344a3c94aea376d4cc31bc77311039e09" integrity sha512-ot0WnXS9fgdkgIcePe6RHNk1WA8+muPa6cSjeR3V8K27q9BB1rTE3R1p7Hv0z1ZyAc8s6Vvv8DIyWf681MAt0w== text-table@^0.2.0: version "0.2.0" - resolved "https://registry.npmjs.org/text-table/-/text-table-0.2.0.tgz" + resolved "https://registry.yarnpkg.com/text-table/-/text-table-0.2.0.tgz#7f5ee823ae805207c00af2df4a84ec3fcfa570b4" integrity sha512-N+8UisAXDGk8PFXP4HAzVR9nbfmVJ3zYLAWiTIoqC5v5isinhr+r5uaO8+7r3BMfuNIufIsA7RdpVgacC2cSpw== +thenify-all@^1.0.0: + version "1.6.0" + resolved "https://registry.yarnpkg.com/thenify-all/-/thenify-all-1.6.0.tgz#1a1918d402d8fc3f98fbf234db0bcc8cc10e9726" + integrity sha512-RNxQH/qI8/t3thXJDwcstUO4zeqo64+Uy/+sNVRBx4Xn2OX+OZ9oP+iJnNFqplFra2ZUVeKCSa2oVWi3T4uVmA== + dependencies: + thenify ">= 3.1.0 < 4" + +"thenify@>= 3.1.0 < 4": + version "3.3.1" + resolved "https://registry.yarnpkg.com/thenify/-/thenify-3.3.1.tgz#8932e686a4066038a016dd9e2ca46add9838a95f" + integrity sha512-RVZSIV5IG10Hk3enotrhvz0T9em6cyHBLkH/YAZuKqd8hRkKhSfCGIcP2KUY0EPxndzANBmNllzWPwak+bheSw== + dependencies: + any-promise "^1.0.0" + through@2, through@~2.3, through@~2.3.1: version "2.3.8" - resolved "https://registry.npmjs.org/through/-/through-2.3.8.tgz" + resolved "https://registry.yarnpkg.com/through/-/through-2.3.8.tgz#0dd4c9ffaabc357960b1b724115d7e0e86a2e1f5" integrity sha512-w89qg7PI8wAdvX60bMDP+bFoD5Dvhm9oLheFp5O4a2QF0cSBGsBX4qZmadPMvVqlLJBBci+WqGGOAPvcDeNSVg== tiny-invariant@^1.0.6: @@ -3573,24 +3677,29 @@ tiny-invariant@^1.0.6: to-fast-properties@^2.0.0: version "2.0.0" - resolved "https://registry.npmjs.org/to-fast-properties/-/to-fast-properties-2.0.0.tgz" + resolved "https://registry.yarnpkg.com/to-fast-properties/-/to-fast-properties-2.0.0.tgz#dc5e698cbd079265bc73e0377681a4e4e83f616e" integrity sha512-/OaKK0xYrs3DmxRYqL/yDc+FxFUVYhDlXMhRmv3z915w2HF1tnN1omB354j8VUGO/hbRzyD6Y3sA7v7GS/ceog== to-regex-range@^5.0.1: version "5.0.1" - resolved "https://registry.npmjs.org/to-regex-range/-/to-regex-range-5.0.1.tgz" + resolved "https://registry.yarnpkg.com/to-regex-range/-/to-regex-range-5.0.1.tgz#1648c44aae7c8d988a326018ed72f5b4dd0392e4" integrity sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ== dependencies: is-number "^7.0.0" toggle-selection@^1.0.6: version "1.0.6" - resolved "https://registry.npmjs.org/toggle-selection/-/toggle-selection-1.0.6.tgz" + resolved "https://registry.yarnpkg.com/toggle-selection/-/toggle-selection-1.0.6.tgz#6e45b1263f2017fa0acc7d89d78b15b8bf77da32" integrity sha512-BiZS+C1OS8g/q2RRbJmy59xpyghNBqrr6k5L/uKBGRsTfxmu3ffiRnd8mlGPUVayg8pvfi5urfnu8TU7DVOkLQ== +ts-interface-checker@^0.1.9: + version "0.1.13" + resolved "https://registry.yarnpkg.com/ts-interface-checker/-/ts-interface-checker-0.1.13.tgz#784fd3d679722bc103b1b4b8030bcddb5db2a699" + integrity sha512-Y/arvbn+rrz3JCKl9C4kVNfTfSm2/mEp5FSz5EsZSANGPSlQrpRI5M4PKF+mJnE52jOO90PnPSc3Ur3bTQw0gA== + tsc-watch@^5.0.3: version "5.0.3" - resolved "https://registry.npmjs.org/tsc-watch/-/tsc-watch-5.0.3.tgz" + resolved "https://registry.yarnpkg.com/tsc-watch/-/tsc-watch-5.0.3.tgz#4d0b2bda8f2677c8f9ed36e001c1a86c31701145" integrity sha512-Hz2UawwELMSLOf0xHvAFc7anLeMw62cMVXr1flYmhRuOhOyOljwmb1l/O60ZwRyy1k7N1iC1mrn1QYM2zITfuw== dependencies: cross-spawn "^7.0.3" @@ -3599,12 +3708,21 @@ tsc-watch@^5.0.3: string-argv "^0.1.1" strip-ansi "^6.0.0" +tsconfig-paths@^4.0.0: + version "4.1.0" + resolved "https://registry.yarnpkg.com/tsconfig-paths/-/tsconfig-paths-4.1.0.tgz#f8ef7d467f08ae3a695335bf1ece088c5538d2c1" + integrity sha512-AHx4Euop/dXFC+Vx589alFba8QItjF+8hf8LtmuiCwHyI4rHXQtOOENaM8kvYf5fR0dRChy3wzWIZ9WbB7FWow== + dependencies: + json5 "^2.2.1" + minimist "^1.2.6" + strip-bom "^3.0.0" + tslib@2.4.0: version "2.4.0" resolved "https://registry.npmjs.org/tslib/-/tslib-2.4.0.tgz" integrity sha512-d6xOpEDfsi2CZVlPQzGeux8XMwLT9hssAsaPYExaQMuYskwb+x1x7J371tWlbBdWHroy99KnVB6qIkUbs5X3UQ== -tslib@^1.8.1: +tslib@^1.8.1, tslib@^1.9.3: version "1.14.1" resolved "https://registry.yarnpkg.com/tslib/-/tslib-1.14.1.tgz#cf2d38bdc34a134bcaf1091c41f6619e2f672d00" integrity sha512-Xni35NKzjgMrwevysHTCArtLDpPvye8zV/0E4EyYn43P7/7qvQwPh9BGkHewbMulVntbigmcT7rdX3BNo9wRJg== @@ -3623,14 +3741,14 @@ tsutils@^3.21.0: type-check@^0.4.0, type-check@~0.4.0: version "0.4.0" - resolved "https://registry.npmjs.org/type-check/-/type-check-0.4.0.tgz" + resolved "https://registry.yarnpkg.com/type-check/-/type-check-0.4.0.tgz#07b8203bfa7056c0657050e3ccd2c37730bab8f1" integrity sha512-XleUoc9uwGXqjWwXaUTZAmzMcFZ5858QA2vvx1Ur5xIcixXIP+8LnFDgRplU30us6teqdlskFfu+ae4K79Ooew== dependencies: prelude-ls "^1.2.1" type-fest@^0.20.2: version "0.20.2" - resolved "https://registry.npmjs.org/type-fest/-/type-fest-0.20.2.tgz" + resolved "https://registry.yarnpkg.com/type-fest/-/type-fest-0.20.2.tgz#1bf207f4b28f91583666cb5fbd327887301cd5f4" integrity sha512-Ne+eE4r0/iWnpAxD852z3A+N0Bt5RN//NjJwRd2VFHEmrywxf5vsZlh4R6lixl6B+wz/8d+maTSAkN1FIkI3LQ== typescript@^4.6.4: @@ -3648,26 +3766,31 @@ update-browserslist-db@^1.0.9: uri-js@^4.2.2: version "4.4.1" - resolved "https://registry.npmjs.org/uri-js/-/uri-js-4.4.1.tgz" + resolved "https://registry.yarnpkg.com/uri-js/-/uri-js-4.4.1.tgz#9b1a52595225859e55f669d928f88c6c57f2a77e" integrity sha512-7rKUyy33Q1yc98pQ1DAmLtwX109F7TIfWlW1Ydo8Wl1ii1SeHieeh0HHfPeL2fMXK6z0s8ecKs9frCuLJvndBg== dependencies: punycode "^2.1.0" use-callback-ref@^1.3.0: version "1.3.0" - resolved "https://registry.npmjs.org/use-callback-ref/-/use-callback-ref-1.3.0.tgz" + resolved "https://registry.yarnpkg.com/use-callback-ref/-/use-callback-ref-1.3.0.tgz#772199899b9c9a50526fedc4993fc7fa1f7e32d5" integrity sha512-3FT9PRuRdbB9HfXhEq35u4oZkvpJ5kuYbpqhCfmiZyReuRgpnhDlbr2ZEnnuS0RrJAPn6l23xjFg9kpDM+Ms7w== dependencies: tslib "^2.0.0" +use-image@^1.1.0: + version "1.1.0" + resolved "https://registry.yarnpkg.com/use-image/-/use-image-1.1.0.tgz#dc244c34506d3cf3a8177c1f0bbfb158b9beefe5" + integrity sha512-+cBHRR/44ZyMUS873O0vbVylgMM0AbdTunEplAWXvIQ2p69h2sIo2Qq74zeUsq6AMo+27e5lERQvXzd1crGiMg== + use-isomorphic-layout-effect@^1.1.1: version "1.1.2" - resolved "https://registry.npmjs.org/use-isomorphic-layout-effect/-/use-isomorphic-layout-effect-1.1.2.tgz" + resolved "https://registry.yarnpkg.com/use-isomorphic-layout-effect/-/use-isomorphic-layout-effect-1.1.2.tgz#497cefb13d863d687b08477d9e5a164ad8c1a6fb" integrity sha512-49L8yCO3iGT/ZF9QttjwLF/ZD9Iwto5LnH5LmEdk/6cFmXddqi2ulF0edxTwjj+7mqvpVVGQWvbXZdn32wRSHA== use-sidecar@^1.1.2: version "1.1.2" - resolved "https://registry.npmjs.org/use-sidecar/-/use-sidecar-1.1.2.tgz" + resolved "https://registry.yarnpkg.com/use-sidecar/-/use-sidecar-1.1.2.tgz#2f43126ba2d7d7e117aa5855e5d8f0276dfe73c2" integrity sha512-epTbsLuzZ7lPClpz2TyryBfztm7m+28DlEv2ZCQ3MDr5ssiwyOwGH/e5F9CkfWjJ1t4clvI58yF822/GUkjjhw== dependencies: detect-node-es "^1.1.0" @@ -3675,28 +3798,38 @@ use-sidecar@^1.1.2: use-sync-external-store@^1.0.0: version "1.2.0" - resolved "https://registry.npmjs.org/use-sync-external-store/-/use-sync-external-store-1.2.0.tgz" + resolved "https://registry.yarnpkg.com/use-sync-external-store/-/use-sync-external-store-1.2.0.tgz#7dbefd6ef3fe4e767a0cf5d7287aacfb5846928a" integrity sha512-eEgnFxGQ1Ife9bzYs6VLi8/4X6CObHMw9Qr9tPY43iKwsPw8xE8+EFsf/2cFZ5S3esXgpWgtSCtLNS41F+sKPA== uuid@^9.0.0: version "9.0.0" - resolved "https://registry.npmjs.org/uuid/-/uuid-9.0.0.tgz" + resolved "https://registry.yarnpkg.com/uuid/-/uuid-9.0.0.tgz#592f550650024a38ceb0c562f2f6aa435761efb5" integrity sha512-MXcSTerfPa4uqyzStbRoTgt5XIe3x5+42+q1sDuy3R5MDk66URdLMOZe5aPX/SQd+kuYAh0FdP/pO28IkQyTeg== vary@^1: version "1.1.2" - resolved "https://registry.npmjs.org/vary/-/vary-1.1.2.tgz" + resolved "https://registry.yarnpkg.com/vary/-/vary-1.1.2.tgz#2299f02c6ded30d4a5961b0b9f74524a18f634fc" integrity sha512-BNGbWLfd0eUPabhkXUVm0j8uuvREyTh5ovRa/dyow/BqAbZJyC+5fU+IzQOzmAKzYqYRAISoRhdQr3eIZ/PXqg== vite-plugin-eslint@^1.8.1: version "1.8.1" - resolved "https://registry.npmjs.org/vite-plugin-eslint/-/vite-plugin-eslint-1.8.1.tgz" + resolved "https://registry.yarnpkg.com/vite-plugin-eslint/-/vite-plugin-eslint-1.8.1.tgz#0381b8272e7f0fd8b663311b64f7608d55d8b04c" integrity sha512-PqdMf3Y2fLO9FsNPmMX+//2BF5SF8nEWspZdgl4kSt7UvHDRHVVfHvxsD7ULYzZrJDGRxR81Nq7TOFgwMnUang== dependencies: "@rollup/pluginutils" "^4.2.1" "@types/eslint" "^8.4.5" rollup "^2.77.2" +vite-tsconfig-paths@^3.5.2: + version "3.5.2" + resolved "https://registry.yarnpkg.com/vite-tsconfig-paths/-/vite-tsconfig-paths-3.5.2.tgz#fd3232f93c426311d7e0d581187d8b63fff55fbc" + integrity sha512-xJMgHA2oJ28QCG2f+hXrcqzo7IttrSRK4A//Tp94CfuX5eetOx33qiwXHUdi3FwkHP2ocpxHuvE45Ix67gwEmQ== + dependencies: + debug "^4.1.1" + globrex "^0.1.2" + recrawl-sync "^2.0.3" + tsconfig-paths "^4.0.0" + vite@^3.0.7: version "3.2.2" resolved "https://registry.yarnpkg.com/vite/-/vite-3.2.2.tgz#280762bfaf47bcea1d12698427331c0009ac7c1f" @@ -3711,47 +3844,47 @@ vite@^3.0.7: which@^2.0.1: version "2.0.2" - resolved "https://registry.npmjs.org/which/-/which-2.0.2.tgz" + resolved "https://registry.yarnpkg.com/which/-/which-2.0.2.tgz#7c6a8dd0a636a0327e10b59c9286eee93f3f51b1" integrity sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA== dependencies: isexe "^2.0.0" word-wrap@^1.2.3: version "1.2.3" - resolved "https://registry.npmjs.org/word-wrap/-/word-wrap-1.2.3.tgz" + resolved "https://registry.yarnpkg.com/word-wrap/-/word-wrap-1.2.3.tgz#610636f6b1f703891bd34771ccb17fb93b47079c" integrity sha512-Hz/mrNwitNRh/HUAtM/VT/5VH+ygD6DV7mYKZAtHOrbs8U7lvPS6xf7EJKMF0uW1KJCl0H701g3ZGus+muE5vQ== wrappy@1: version "1.0.2" - resolved "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz" + resolved "https://registry.yarnpkg.com/wrappy/-/wrappy-1.0.2.tgz#b5243d8f3ec1aa35f1364605bc0d1036e30ab69f" integrity sha512-l4Sp/DRseor9wL6EvV2+TuQn63dMkPjZ/sp9XkghTEbV9KlPS1xUsZ3u7/IQO4wxtcFB4bgpQPRcR3QCvezPcQ== ws@~8.2.3: version "8.2.3" - resolved "https://registry.npmjs.org/ws/-/ws-8.2.3.tgz" + resolved "https://registry.yarnpkg.com/ws/-/ws-8.2.3.tgz#63a56456db1b04367d0b721a0b80cae6d8becbba" integrity sha512-wBuoj1BDpC6ZQ1B7DWQBYVLphPWkm8i9Y0/3YdHjHKHiohOJ1ws+3OccDWtH+PoC9DZD5WOTrJvNbWvjS6JWaA== xmlhttprequest-ssl@~2.0.0: version "2.0.0" - resolved "https://registry.npmjs.org/xmlhttprequest-ssl/-/xmlhttprequest-ssl-2.0.0.tgz" + resolved "https://registry.yarnpkg.com/xmlhttprequest-ssl/-/xmlhttprequest-ssl-2.0.0.tgz#91360c86b914e67f44dce769180027c0da618c67" integrity sha512-QKxVRxiRACQcVuQEYFsI1hhkrMlrXHPegbbd1yn9UHOmRxY+si12nQYzri3vbzt8VdTTRviqcKxcyllFas5z2A== yallist@^4.0.0: version "4.0.0" - resolved "https://registry.npmjs.org/yallist/-/yallist-4.0.0.tgz" + resolved "https://registry.yarnpkg.com/yallist/-/yallist-4.0.0.tgz#9bb92790d9c0effec63be73519e11a35019a3a72" integrity sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A== yaml@^1.10.0: version "1.10.2" - resolved "https://registry.npmjs.org/yaml/-/yaml-1.10.2.tgz" + resolved "https://registry.yarnpkg.com/yaml/-/yaml-1.10.2.tgz#2301c5ffbf12b467de8da2333a459e29e7920e4b" integrity sha512-r3vXyErRCYJ7wg28yvBY5VSoAF8ZvlcW9/BwUzEtUsjvX/DKs24dIkuwjtuprwJJHsbyUbLApepYTR1BN4uHrg== yarn@^1.22.19: version "1.22.19" - resolved "https://registry.npmjs.org/yarn/-/yarn-1.22.19.tgz" + resolved "https://registry.yarnpkg.com/yarn/-/yarn-1.22.19.tgz#4ba7fc5c6e704fce2066ecbfb0b0d8976fe62447" integrity sha512-/0V5q0WbslqnwP91tirOvldvYISzaqhClxzyUKXYxs07yUILIs5jx/k6CFe8bvKSkds5w+eiOqta39Wk3WxdcQ== yocto-queue@^0.1.0: version "0.1.0" - resolved "https://registry.npmjs.org/yocto-queue/-/yocto-queue-0.1.0.tgz" + resolved "https://registry.yarnpkg.com/yocto-queue/-/yocto-queue-0.1.0.tgz#0294eb3dee05028d31ee1a5fa2c556a6aaf10a1b" integrity sha512-rVksvsnNCdJ/ohGc6xgPwyN8eheCxsiLM8mxuE/t/mOVqJewPuO1miLpTHQiRgTKCLexL4MeAFVagts7HmNZ2Q== diff --git a/ldm/generate.py b/ldm/generate.py index e544cbde4f..12127e69ea 100644 --- a/ldm/generate.py +++ b/ldm/generate.py @@ -324,6 +324,7 @@ class Generate: seam_steps: int = 10, tile_size: int = 32, force_outpaint: bool = False, + enable_image_debugging = False, **args, ): # eat up additional cruft """ @@ -462,7 +463,7 @@ class Generate: ) # TODO: Hacky selection of operation to perform. Needs to be refactored. - generator = self.select_generator(init_image, mask_image, embiggen, hires_fix) + generator = self.select_generator(init_image, mask_image, embiggen, hires_fix, force_outpaint) generator.set_variation( self.seed, variation_amount, with_variations @@ -505,8 +506,9 @@ class Generate: seam_steps = seam_steps, tile_size = tile_size, force_outpaint = force_outpaint, - inpaint_width = inpaint_width, - inpaint_height = inpaint_height + inpaint_height = inpaint_height, + inpaint_width = inpaint_width, + enable_image_debugging = enable_image_debugging, ) if init_color: diff --git a/ldm/invoke/args.py b/ldm/invoke/args.py index cb6a4ac3d9..e626b4206f 100644 --- a/ldm/invoke/args.py +++ b/ldm/invoke/args.py @@ -550,6 +550,11 @@ class Args(object): type=str, help='Path to a pre-trained embedding manager checkpoint - can only be set on command line', ) + render_group.add_argument( + '--enable_image_debugging', + action='store_true', + help='Generates debugging image to display' + ) # Restoration related args postprocessing_group.add_argument( '--no_restore', diff --git a/ldm/invoke/generator/base.py b/ldm/invoke/generator/base.py index 003ac1b466..a8ef62822d 100644 --- a/ldm/invoke/generator/base.py +++ b/ldm/invoke/generator/base.py @@ -8,7 +8,8 @@ import random import os import traceback from tqdm import tqdm, trange -from PIL import Image, ImageFilter +from PIL import Image, ImageFilter, ImageChops +import cv2 as cv from einops import rearrange, repeat from pytorch_lightning import seed_everything from ldm.invoke.devices import choose_autocast @@ -118,6 +119,55 @@ class Generator(): # write an approximate RGB image from latent samples for a single step to PNG + def repaste_and_color_correct(self, result: Image.Image, init_image: Image.Image, init_mask: Image.Image, mask_blur_radius: int = 8) -> Image.Image: + if init_image is None or init_mask is None: + return result + + # Get the original alpha channel of the mask if there is one. + # Otherwise it is some other black/white image format ('1', 'L' or 'RGB') + pil_init_mask = init_mask.getchannel('A') if init_mask.mode == 'RGBA' else init_mask.convert('L') + pil_init_image = init_image.convert('RGBA') # Add an alpha channel if one doesn't exist + + # Build an image with only visible pixels from source to use as reference for color-matching. + init_rgb_pixels = np.asarray(init_image.convert('RGB'), dtype=np.uint8) + init_a_pixels = np.asarray(pil_init_image.getchannel('A'), dtype=np.uint8) + init_mask_pixels = np.asarray(pil_init_mask, dtype=np.uint8) + + # Get numpy version of result + np_image = np.asarray(result, dtype=np.uint8) + + # Mask and calculate mean and standard deviation + mask_pixels = init_a_pixels * init_mask_pixels > 0 + np_init_rgb_pixels_masked = init_rgb_pixels[mask_pixels, :] + np_image_masked = np_image[mask_pixels, :] + + init_means = np_init_rgb_pixels_masked.mean(axis=0) + init_std = np_init_rgb_pixels_masked.std(axis=0) + gen_means = np_image_masked.mean(axis=0) + gen_std = np_image_masked.std(axis=0) + + # Color correct + np_matched_result = np_image.copy() + np_matched_result[:,:,:] = (((np_matched_result[:,:,:].astype(np.float32) - gen_means[None,None,:]) / gen_std[None,None,:]) * init_std[None,None,:] + init_means[None,None,:]).clip(0, 255).astype(np.uint8) + matched_result = Image.fromarray(np_matched_result, mode='RGB') + + # Blur the mask out (into init image) by specified amount + if mask_blur_radius > 0: + nm = np.asarray(pil_init_mask, dtype=np.uint8) + nmd = cv.erode(nm, kernel=np.ones((3,3), dtype=np.uint8), iterations=int(mask_blur_radius / 2)) + pmd = Image.fromarray(nmd, mode='L') + blurred_init_mask = pmd.filter(ImageFilter.BoxBlur(mask_blur_radius)) + else: + blurred_init_mask = pil_init_mask + + multiplied_blurred_init_mask = ImageChops.multiply(blurred_init_mask, self.pil_image.split()[-1]) + + # Paste original on color-corrected generation (using blurred mask) + matched_result.paste(init_image, (0,0), mask = multiplied_blurred_init_mask) + return matched_result + + + def sample_to_lowres_estimated_image(self,samples): # origingally adapted from code by @erucipe and @keturn here: # https://discuss.huggingface.co/t/decoding-latents-to-rgb-without-upscaling/23204/7 diff --git a/ldm/invoke/generator/inpaint.py b/ldm/invoke/generator/inpaint.py index d1f79b934f..72601a7146 100644 --- a/ldm/invoke/generator/inpaint.py +++ b/ldm/invoke/generator/inpaint.py @@ -8,7 +8,7 @@ import torchvision.transforms as T import numpy as np import cv2 as cv import PIL -from PIL import Image, ImageFilter, ImageOps +from PIL import Image, ImageFilter, ImageOps, ImageChops from skimage.exposure.histogram_matching import match_histograms from einops import rearrange, repeat from ldm.invoke.devices import choose_autocast @@ -16,6 +16,7 @@ from ldm.invoke.generator.img2img import Img2Img from ldm.models.diffusion.ddim import DDIMSampler from ldm.models.diffusion.ksampler import KSampler from ldm.invoke.generator.base import downsampling +from ldm.util import debug_image class Inpaint(Img2Img): def __init__(self, model, precision): @@ -47,6 +48,13 @@ class Inpaint(Img2Img): if im.mode != 'RGBA': return im + # # HACK PATCH MATCH + # from src.PyPatchMatch import patch_match + # im_patched_np = patch_match.inpaint(im.convert('RGB'), ImageOps.invert(im.split()[-1]), patch_size = 3) + # im_patched = Image.fromarray(im_patched_np, mode = 'RGB') + # return im_patched + # # /HACK + a = np.asarray(im, dtype=np.uint8) tile_size = (tile_size, tile_size) @@ -150,9 +158,7 @@ class Inpaint(Img2Img): seam_steps: int = 10, tile_size: int = 32, step_callback=None, - inpaint_replace=False, - inpaint_width=None, - inpaint_height=None, + inpaint_replace=False, enable_image_debugging=False, **kwargs): """ Returns a function returning an image derived from the prompt and @@ -160,8 +166,7 @@ class Inpaint(Img2Img): the time you call it. kwargs are 'init_latent' and 'strength' """ - self.inpaint_width = inpaint_width - self.inpaint_height = inpaint_height + self.enable_image_debugging = enable_image_debugging if isinstance(init_image, PIL.Image.Image): self.pil_image = init_image @@ -174,21 +179,17 @@ class Inpaint(Img2Img): tile_size = tile_size ) init_filled.paste(init_image, (0,0), init_image.split()[-1]) - - # Resize if requested for inpainting - if inpaint_width and inpaint_height: - init_filled = init_filled.resize((inpaint_width, inpaint_height)) - + debug_image(init_filled, "init_filled", debug_status=self.enable_image_debugging) + # Create init tensor init_image = self._image_to_tensor(init_filled.convert('RGB')) if isinstance(mask_image, PIL.Image.Image): self.pil_mask = mask_image + debug_image(mask_image, "mask_image BEFORE multiply with pil_image", debug_status=self.enable_image_debugging) - # Resize if requested for inpainting - if inpaint_width and inpaint_height: - mask_image = mask_image.resize((inpaint_width, inpaint_height)) - + mask_image = ImageChops.multiply(mask_image, self.pil_image.split()[-1].convert('RGB')) + debug_image(mask_image, "mask_image AFTER multiply with pil_image", debug_status=self.enable_image_debugging) mask_image = mask_image.resize( ( mask_image.width // downsampling, @@ -277,59 +278,14 @@ class Inpaint(Img2Img): return make_image - def color_correct(self, image: Image.Image, base_image: Image.Image, mask: Image.Image, mask_blur_radius: int) -> Image.Image: - # Get the original alpha channel of the mask if there is one. - # Otherwise it is some other black/white image format ('1', 'L' or 'RGB') - pil_init_mask = mask.getchannel('A') if mask.mode == 'RGBA' else mask.convert('L') - pil_init_image = base_image.convert('RGBA') # Add an alpha channel if one doesn't exist - - # Build an image with only visible pixels from source to use as reference for color-matching. - init_rgb_pixels = np.asarray(base_image.convert('RGB'), dtype=np.uint8) - init_a_pixels = np.asarray(pil_init_image.getchannel('A'), dtype=np.uint8) - init_mask_pixels = np.asarray(pil_init_mask, dtype=np.uint8) - - # Get numpy version of result - np_image = np.asarray(image, dtype=np.uint8) - - # Mask and calculate mean and standard deviation - mask_pixels = init_a_pixels * init_mask_pixels > 0 - np_init_rgb_pixels_masked = init_rgb_pixels[mask_pixels, :] - np_image_masked = np_image[mask_pixels, :] - - init_means = np_init_rgb_pixels_masked.mean(axis=0) - init_std = np_init_rgb_pixels_masked.std(axis=0) - gen_means = np_image_masked.mean(axis=0) - gen_std = np_image_masked.std(axis=0) - - # Color correct - np_matched_result = np_image.copy() - np_matched_result[:,:,:] = (((np_matched_result[:,:,:].astype(np.float32) - gen_means[None,None,:]) / gen_std[None,None,:]) * init_std[None,None,:] + init_means[None,None,:]).clip(0, 255).astype(np.uint8) - matched_result = Image.fromarray(np_matched_result, mode='RGB') - - # Blur the mask out (into init image) by specified amount - if mask_blur_radius > 0: - nm = np.asarray(pil_init_mask, dtype=np.uint8) - nmd = cv.erode(nm, kernel=np.ones((3,3), dtype=np.uint8), iterations=int(mask_blur_radius / 2)) - pmd = Image.fromarray(nmd, mode='L') - blurred_init_mask = pmd.filter(ImageFilter.BoxBlur(mask_blur_radius)) - else: - blurred_init_mask = pil_init_mask - - # Paste original on color-corrected generation (using blurred mask) - matched_result.paste(base_image, (0,0), mask = blurred_init_mask) - return matched_result - - def sample_to_image(self, samples)->Image.Image: gen_result = super().sample_to_image(samples).convert('RGB') - - # Resize if necessary - if self.inpaint_width and self.inpaint_height: - gen_result = gen_result.resize(self.pil_image.size) + debug_image(gen_result, "gen_result", debug_status=self.enable_image_debugging) if self.pil_image is None or self.pil_mask is None: return gen_result - corrected_result = self.color_correct(gen_result, self.pil_image, self.pil_mask, self.mask_blur_radius) + corrected_result = super().repaste_and_color_correct(gen_result, self.pil_image, self.pil_mask, self.mask_blur_radius) + debug_image(corrected_result, "corrected_result", debug_status=self.enable_image_debugging) return corrected_result diff --git a/ldm/invoke/generator/omnibus.py b/ldm/invoke/generator/omnibus.py index e8426a9205..35c4a62d66 100644 --- a/ldm/invoke/generator/omnibus.py +++ b/ldm/invoke/generator/omnibus.py @@ -3,7 +3,7 @@ import torch import numpy as np from einops import repeat -from PIL import Image, ImageOps +from PIL import Image, ImageOps, ImageChops from ldm.invoke.devices import choose_autocast from ldm.invoke.generator.base import downsampling from ldm.invoke.generator.img2img import Img2Img @@ -29,6 +29,7 @@ class Omnibus(Img2Img,Txt2Img): step_callback=None, threshold=0.0, perlin=0.0, + mask_blur_radius: int = 8, **kwargs): """ Returns a function returning an image derived from the prompt and the initial image @@ -42,12 +43,18 @@ class Omnibus(Img2Img,Txt2Img): ) if isinstance(init_image, Image.Image): + self.pil_image = init_image if init_image.mode != 'RGB': init_image = init_image.convert('RGB') init_image = self._image_to_tensor(init_image) if isinstance(mask_image, Image.Image): - mask_image = self._image_to_tensor(ImageOps.invert(mask_image).convert('L'),normalize=False) + self.pil_mask = mask_image + + mask_image = ImageChops.multiply(mask_image.convert('L'), self.pil_image.split()[-1]) + mask_image = self._image_to_tensor(ImageOps.invert(mask_image), normalize=False) + + self.mask_blur_radius = mask_blur_radius t_enc = steps @@ -151,3 +158,14 @@ class Omnibus(Img2Img,Txt2Img): height = self.init_latent.shape[2] width = self.init_latent.shape[3] return Txt2Img.get_noise(self,width,height) + + + def sample_to_image(self, samples)->Image.Image: + gen_result = super().sample_to_image(samples).convert('RGB') + + if self.pil_image is None or self.pil_mask is None: + return gen_result + + corrected_result = super(Img2Img, self).repaste_and_color_correct(gen_result, self.pil_image, self.pil_mask, self.mask_blur_radius) + + return corrected_result diff --git a/ldm/util.py b/ldm/util.py index 478c66b8b5..ae28edb96a 100644 --- a/ldm/util.py +++ b/ldm/util.py @@ -244,3 +244,21 @@ def ask_user(question: str, answers: list): user_answers = map(input, pose_question) valid_response = next(filter(answers.__contains__, user_answers)) return valid_response + + +def debug_image(debug_image, debug_text, debug_show=True, debug_result=False, debug_status=False ): + if not debug_status: + return + + image_copy = debug_image.copy() + ImageDraw.Draw(image_copy).text( + (5, 5), + debug_text, + (255, 0, 0) + ) + + if debug_show: + image_copy.show() + + if debug_result: + return image_copy \ No newline at end of file

C`IdITI8^NMLH7Sa^$lcN=%pdJ{w_+W0 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