add settings slice and allow resizing image history
This commit is contained in:
parent
2b562d9464
commit
5888cae298
|
@ -1,3 +1,4 @@
|
|||
bundle/main.css
|
||||
bundle/main.js
|
||||
config.json
|
||||
index.html
|
||||
|
|
|
@ -22,6 +22,7 @@ docs-local:
|
|||
|
||||
build: deps
|
||||
yarn tsc
|
||||
cp -v src/components/main.css out/src/components/
|
||||
|
||||
build-shebang: build
|
||||
sed -i '1s;^;#! /usr/bin/env node\n\n;g' $(shell pwd)/out/src/main.js
|
||||
|
@ -35,6 +36,7 @@ bundle: build
|
|||
# copy everything into the server's default path
|
||||
cp -v src/index.html ../api/gui/
|
||||
cp -v src/config.json ../api/gui/
|
||||
cp -v out/bundle/main.css ../api/gui/bundle/
|
||||
cp -v out/bundle/main.js ../api/gui/bundle/
|
||||
|
||||
COVER_OPTS := --all \
|
||||
|
|
|
@ -16,6 +16,7 @@
|
|||
"@tanstack/react-query": "^4.0.5",
|
||||
"@types/lodash": "^4.14.192",
|
||||
"@types/node": "^18.15.11",
|
||||
"allotment": "^1.19.5",
|
||||
"browser-bunyan": "^1.8.0",
|
||||
"exifreader": "^4.13.0",
|
||||
"i18next": "^22.4.14",
|
||||
|
|
|
@ -48,8 +48,13 @@ export function ImageHistory(props: ImageHistoryProps) {
|
|||
}
|
||||
}
|
||||
|
||||
// eslint-disable-next-line @typescript-eslint/no-magic-numbers
|
||||
return <Grid container spacing={2}>{children.map(([key, child]) => <Grid item key={key} xs={12 / width}>{child}</Grid>)}</Grid>;
|
||||
return <Grid
|
||||
container
|
||||
spacing={2}
|
||||
>{
|
||||
// eslint-disable-next-line @typescript-eslint/no-magic-numbers
|
||||
children.map(([key, child]) => <Grid item key={key} xs={12 / width}>{child}</Grid>)
|
||||
}</Grid>;
|
||||
}
|
||||
|
||||
export function selectActions(state: OnnxState) {
|
||||
|
|
|
@ -1,13 +1,16 @@
|
|||
/* eslint-disable @typescript-eslint/no-magic-numbers */
|
||||
import { mustExist } from '@apextoaster/js-utils';
|
||||
import { TabContext, TabList, TabPanel } from '@mui/lab';
|
||||
import { Box, Button, Container, CssBaseline, Divider, Stack, Tab, useMediaQuery } from '@mui/material';
|
||||
import { Box, Container, CssBaseline, Divider, Stack, Tab, useMediaQuery } from '@mui/material';
|
||||
import { Breakpoint, SxProps, Theme, ThemeProvider, createTheme } from '@mui/material/styles';
|
||||
import { Allotment } from 'allotment';
|
||||
import * as React from 'react';
|
||||
import { useContext, useMemo } from 'react';
|
||||
import { useHash } from 'react-use/lib/useHash';
|
||||
import { useStore } from 'zustand';
|
||||
import { shallow } from 'zustand/shallow';
|
||||
|
||||
import { Motd } from '../Motd.js';
|
||||
import { OnnxState, StateContext } from '../state/full.js';
|
||||
import { ImageHistory } from './ImageHistory.js';
|
||||
import { Logo } from './Logo.js';
|
||||
|
@ -19,7 +22,9 @@ import { Settings } from './tab/Settings.js';
|
|||
import { Txt2Img } from './tab/Txt2Img.js';
|
||||
import { Upscale } from './tab/Upscale.js';
|
||||
import { TAB_LABELS, getTab, getTheme } from './utils.js';
|
||||
import { Motd } from '../Motd.js';
|
||||
|
||||
import 'allotment/dist/style.css';
|
||||
import './main.css';
|
||||
|
||||
export interface OnnxWebProps {
|
||||
motd: boolean;
|
||||
|
@ -30,7 +35,7 @@ export function OnnxWeb(props: OnnxWebProps) {
|
|||
const prefersDarkMode = useMediaQuery('(prefers-color-scheme: dark)');
|
||||
const store = mustExist(useContext(StateContext));
|
||||
const stateTheme = useStore(store, selectTheme);
|
||||
const layout = useStore(store, selectLayout);
|
||||
const layout = useStore(store, selectLayout, shallow);
|
||||
|
||||
const theme = useMemo(
|
||||
() => createTheme({
|
||||
|
@ -41,13 +46,7 @@ export function OnnxWeb(props: OnnxWebProps) {
|
|||
[prefersDarkMode, stateTheme],
|
||||
);
|
||||
|
||||
const [hash, setHash] = useHash();
|
||||
|
||||
const historyStyle: SxProps<Theme> = {
|
||||
mx: 4,
|
||||
my: 4,
|
||||
...LAYOUT_STYLES[layout.direction].history.style,
|
||||
};
|
||||
const historyStyle: SxProps<Theme> = LAYOUT_STYLES[layout.direction].history.style;
|
||||
|
||||
return (
|
||||
<ThemeProvider theme={theme}>
|
||||
|
@ -57,44 +56,7 @@ export function OnnxWeb(props: OnnxWebProps) {
|
|||
<Logo />
|
||||
</Box>
|
||||
{props.motd && <Motd />}
|
||||
<Stack direction={LAYOUT_STYLES[layout.direction].direction} spacing={2}>
|
||||
<Stack direction='column'>
|
||||
<TabContext value={getTab(hash)}>
|
||||
<Box sx={{ borderBottom: 1, borderColor: 'divider' }}>
|
||||
<TabList onChange={(_e, idx) => {
|
||||
setHash(idx);
|
||||
}}>
|
||||
{TAB_LABELS.map((name) => <Tab key={name} label={name} value={name} />)}
|
||||
</TabList>
|
||||
</Box>
|
||||
<TabPanel value='txt2img'>
|
||||
<Txt2Img />
|
||||
</TabPanel>
|
||||
<TabPanel value='img2img'>
|
||||
<Img2Img />
|
||||
</TabPanel>
|
||||
<TabPanel value='inpaint'>
|
||||
<Inpaint />
|
||||
</TabPanel>
|
||||
<TabPanel value='upscale'>
|
||||
<Upscale />
|
||||
</TabPanel>
|
||||
<TabPanel value='blend'>
|
||||
<Blend />
|
||||
</TabPanel>
|
||||
<TabPanel value='models'>
|
||||
<Models />
|
||||
</TabPanel>
|
||||
<TabPanel value='settings'>
|
||||
<Settings />
|
||||
</TabPanel>
|
||||
</TabContext>
|
||||
</Stack>
|
||||
<Divider flexItem variant='middle' orientation={LAYOUT_STYLES[layout.direction].divider} />
|
||||
<Box sx={historyStyle}>
|
||||
<ImageHistory width={layout.width} />
|
||||
</Box>
|
||||
</Stack>
|
||||
{layout.direction === 'vertical' ? <VerticalBody layout={layout} style={historyStyle} /> : <HorizontalBody layout={layout} style={historyStyle} />}
|
||||
</Container>
|
||||
</ThemeProvider>
|
||||
);
|
||||
|
@ -114,10 +76,14 @@ export function selectLayout(state: OnnxState) {
|
|||
export const LAYOUT_STYLES = {
|
||||
horizontal: {
|
||||
container: false,
|
||||
control: {
|
||||
width: '30%',
|
||||
},
|
||||
direction: 'row',
|
||||
divider: 'vertical',
|
||||
history: {
|
||||
style: {
|
||||
marginLeft: 4,
|
||||
maxHeight: '85vb',
|
||||
overflowY: 'auto',
|
||||
},
|
||||
|
@ -126,11 +92,91 @@ export const LAYOUT_STYLES = {
|
|||
},
|
||||
vertical: {
|
||||
container: 'lg' as Breakpoint,
|
||||
control: {
|
||||
width: undefined,
|
||||
},
|
||||
direction: 'column',
|
||||
divider: 'horizontal',
|
||||
history: {
|
||||
style: {},
|
||||
style: {
|
||||
mx: 4,
|
||||
my: 4,
|
||||
},
|
||||
width: 2,
|
||||
},
|
||||
},
|
||||
} as const;
|
||||
|
||||
// used for both horizontal and vertical
|
||||
export interface BodyProps {
|
||||
layout: ReturnType<typeof selectLayout>;
|
||||
style: SxProps<Theme>;
|
||||
}
|
||||
|
||||
export function HorizontalBody(props: BodyProps) {
|
||||
const store = mustExist(useContext(StateContext));
|
||||
const {direction} = useStore(store, selectLayout, shallow);
|
||||
const layout = LAYOUT_STYLES[direction];
|
||||
|
||||
return <Allotment separator className='body-allotment' minSize={300}>
|
||||
<TabGroup />
|
||||
<Box sx={layout.history.style}>
|
||||
<ImageHistory width={props.layout.width} />
|
||||
</Box>
|
||||
</Allotment>;
|
||||
}
|
||||
|
||||
export function VerticalBody(props: BodyProps) {
|
||||
const store = mustExist(useContext(StateContext));
|
||||
const {direction, width} = useStore(store, selectLayout, shallow);
|
||||
const layout = LAYOUT_STYLES[direction];
|
||||
|
||||
return <Stack direction={layout.direction} spacing={2}>
|
||||
<TabGroup />
|
||||
<Divider flexItem variant='middle' orientation={layout.divider} />
|
||||
<Box sx={layout.history.style}>
|
||||
<ImageHistory width={width} />
|
||||
</Box>
|
||||
</Stack>;
|
||||
}
|
||||
|
||||
export function TabGroup() {
|
||||
const store = mustExist(useContext(StateContext));
|
||||
const {direction} = useStore(store, selectLayout, shallow);
|
||||
const layout = LAYOUT_STYLES[direction];
|
||||
|
||||
const [hash, setHash] = useHash();
|
||||
|
||||
return <Stack direction='column' minWidth={layout.control.width} sx={{ mx: 4 }}>
|
||||
<TabContext value={getTab(hash)}>
|
||||
<Box sx={{ borderBottom: 1, borderColor: 'divider' }}>
|
||||
<TabList onChange={(_e, idx) => {
|
||||
setHash(idx);
|
||||
}}>
|
||||
{TAB_LABELS.map((name) => <Tab key={name} label={name} value={name} />)}
|
||||
</TabList>
|
||||
</Box>
|
||||
<TabPanel value='txt2img'>
|
||||
<Txt2Img />
|
||||
</TabPanel>
|
||||
<TabPanel value='img2img'>
|
||||
<Img2Img />
|
||||
</TabPanel>
|
||||
<TabPanel value='inpaint'>
|
||||
<Inpaint />
|
||||
</TabPanel>
|
||||
<TabPanel value='upscale'>
|
||||
<Upscale />
|
||||
</TabPanel>
|
||||
<TabPanel value='blend'>
|
||||
<Blend />
|
||||
</TabPanel>
|
||||
<TabPanel value='models'>
|
||||
<Models />
|
||||
</TabPanel>
|
||||
<TabPanel value='settings'>
|
||||
<Settings />
|
||||
</TabPanel>
|
||||
</TabContext>
|
||||
</Stack>;
|
||||
}
|
||||
|
|
|
@ -25,6 +25,7 @@ import { OnnxState, StateContext } from '../state/full.js';
|
|||
import { ImageMetadata } from '../types/api.js';
|
||||
import { DeepPartial } from '../types/model.js';
|
||||
import { BaseImgParams, HighresParams, ModelParams, Txt2ImgParams, UpscaleParams } from '../types/params.js';
|
||||
import { downloadAsJson } from '../utils.js';
|
||||
|
||||
export const ALLOWED_EXTENSIONS = ['.json','.jpg','.jpeg','.png','.txt','.webp'];
|
||||
export const EXTENSION_FILTER = ALLOWED_EXTENSIONS.join(',');
|
||||
|
@ -119,10 +120,10 @@ export function Profiles(props: ProfilesProps) {
|
|||
onClick={() => {
|
||||
const state = store.getState();
|
||||
saveProfile({
|
||||
model: props.selectModel(state),
|
||||
params: props.selectParams(state),
|
||||
name: profileName,
|
||||
highres: props.selectHighres(state),
|
||||
model: props.selectModel(state),
|
||||
params: props.selectParams(state),
|
||||
upscale: props.selectUpscale(state),
|
||||
});
|
||||
setDialogOpen(false);
|
||||
|
@ -166,9 +167,9 @@ export function Profiles(props: ProfilesProps) {
|
|||
</Button>
|
||||
<Button component='label' variant='contained' onClick={() => {
|
||||
const state = store.getState();
|
||||
downloadParamsAsFile({
|
||||
// TODO: save model parameters
|
||||
// model: props.selectModel(state),
|
||||
downloadAsJson({
|
||||
name: 'web-ui-profile',
|
||||
model: props.selectModel(state),
|
||||
params: props.selectParams(state),
|
||||
highres: props.selectHighres(state),
|
||||
upscale: props.selectUpscale(state),
|
||||
|
@ -210,19 +211,6 @@ export async function loadParamsFromFile(file: File): Promise<DeepPartial<ImageM
|
|||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* from https://stackoverflow.com/a/30800715
|
||||
*/
|
||||
export function downloadParamsAsFile(data: DeepPartial<ImageMetadata>): void {
|
||||
const dataStr = 'data:text/json;charset=utf-8,' + encodeURIComponent(JSON.stringify(data));
|
||||
const elem = document.createElement('a');
|
||||
elem.setAttribute('href', dataStr);
|
||||
elem.setAttribute('download', 'parameters.json');
|
||||
document.body.appendChild(elem); // required for firefox
|
||||
elem.click();
|
||||
elem.remove();
|
||||
}
|
||||
|
||||
export async function parseImageParams(file: File): Promise<DeepPartial<ImageMetadata>> {
|
||||
const tags = await ExifReader.load(file);
|
||||
|
||||
|
|
|
@ -0,0 +1,3 @@
|
|||
.body-allotment {
|
||||
height: 85vb;
|
||||
}
|
|
@ -1,5 +1,5 @@
|
|||
import { doesExist, mustExist } from '@apextoaster/js-utils';
|
||||
import { Refresh } from '@mui/icons-material';
|
||||
import { Download, Refresh } from '@mui/icons-material';
|
||||
import { Alert, Button, FormControlLabel, Stack, Switch, TextField, useMediaQuery } from '@mui/material';
|
||||
import * as React from 'react';
|
||||
import { useContext, useState } from 'react';
|
||||
|
@ -10,6 +10,7 @@ import { getApiRoot } from '../../config.js';
|
|||
import { ConfigContext, StateContext, STATE_KEY } from '../../state/full.js';
|
||||
import { getTheme } from '../utils.js';
|
||||
import { NumericField } from '../input/NumericField.js';
|
||||
import { downloadAsJson } from '../../utils.js';
|
||||
|
||||
function removeBlobs(key: string, value: unknown): unknown {
|
||||
if (value instanceof Blob || value instanceof File) {
|
||||
|
@ -55,7 +56,7 @@ export function Settings() {
|
|||
value={state.historyWidth}
|
||||
onChange={(value) => state.setWidth(value)}
|
||||
/>
|
||||
<Button onClick={() => state.setLayout(state.layout === 'horizontal' ? 'vertical' : 'horizontal')}>Toggle Layout</Button>
|
||||
<Button variant='contained' onClick={() => state.setLayout(state.layout === 'horizontal' ? 'vertical' : 'horizontal')}>Toggle Layout</Button>
|
||||
<TextField variant='outlined' label={t('setting.prompt')} value={state.defaults.prompt} onChange={(event) => {
|
||||
state.setDefaults({
|
||||
prompt: event.target.value,
|
||||
|
@ -82,14 +83,19 @@ export function Settings() {
|
|||
</Alert>
|
||||
</Stack>
|
||||
<Stack direction='row' spacing={2}>
|
||||
<TextField variant='outlined' label={t('setting.state')} value={json} onChange={(event) => {
|
||||
<TextField variant='outlined' label={t('setting.state.label')} value={json} onChange={(event) => {
|
||||
setJson(event.target.value);
|
||||
}} />
|
||||
<Button variant='contained' startIcon={<Refresh />} onClick={() => {
|
||||
window.localStorage.setItem(STATE_KEY, json);
|
||||
window.location.reload();
|
||||
}}>
|
||||
{t('setting.loadState')}
|
||||
{t('setting.state.load')}
|
||||
</Button>
|
||||
<Button variant='contained' startIcon={<Download />} onClick={() => {
|
||||
downloadAsJson(state, 'state.json');
|
||||
}}>
|
||||
{t('setting.state.save')}
|
||||
</Button>
|
||||
</Stack>
|
||||
<FormControlLabel control={
|
||||
|
|
|
@ -2,6 +2,7 @@
|
|||
<html lang="en">
|
||||
<head>
|
||||
<title>ONNX Web</title>
|
||||
<link href="./bundle/main.css" rel="stylesheet">
|
||||
</head>
|
||||
<body>
|
||||
<div id="app"></div>
|
||||
|
|
|
@ -0,0 +1,34 @@
|
|||
import { Slice } from './types.js';
|
||||
|
||||
export type Layout = 'horizontal' | 'vertical';
|
||||
|
||||
export const DEFAULT_LAYOUT = {
|
||||
historyWidth: 4,
|
||||
layout: 'vertical' as Layout,
|
||||
} as const;
|
||||
|
||||
export interface SettingsSlice {
|
||||
historyWidth: number;
|
||||
layout: Layout;
|
||||
|
||||
setLayout(layout: Layout): void;
|
||||
setWidth(width: number): void;
|
||||
}
|
||||
|
||||
export function createSettingsSlice<TState extends SettingsSlice>(): Slice<TState, SettingsSlice> {
|
||||
return (set) => ({
|
||||
...DEFAULT_LAYOUT,
|
||||
setLayout(layout) {
|
||||
set((prev) => ({
|
||||
...prev,
|
||||
layout,
|
||||
}));
|
||||
},
|
||||
setWidth(width) {
|
||||
set((prev) => ({
|
||||
...prev,
|
||||
historyWidth: width,
|
||||
}));
|
||||
},
|
||||
});
|
||||
}
|
|
@ -216,7 +216,6 @@ export const I18N_STRINGS_DE = {
|
|||
limit: 'Bildgeschichte',
|
||||
width: '',
|
||||
},
|
||||
loadState: 'Laden',
|
||||
prompt: 'Standard-Eingabeaufforderung',
|
||||
reset: {
|
||||
all: 'Alles zurücksetzen',
|
||||
|
@ -226,7 +225,11 @@ export const I18N_STRINGS_DE = {
|
|||
},
|
||||
scheduler: 'Standardplaner',
|
||||
server: 'API-Server',
|
||||
state: 'Kundenstatus',
|
||||
state: {
|
||||
label: 'Kundenstatus',
|
||||
load: 'Laden',
|
||||
save: '',
|
||||
},
|
||||
darkMode: 'Dunkelmodus',
|
||||
},
|
||||
sourceFilter: {
|
||||
|
|
|
@ -279,7 +279,6 @@ export const I18N_STRINGS_EN = {
|
|||
limit: 'Image History Length',
|
||||
width: 'Image History Width',
|
||||
},
|
||||
loadState: 'Load',
|
||||
prompt: 'Default Prompt',
|
||||
reset: {
|
||||
all: 'Reset All',
|
||||
|
@ -289,7 +288,11 @@ export const I18N_STRINGS_EN = {
|
|||
},
|
||||
scheduler: 'Default Scheduler',
|
||||
server: 'API Server',
|
||||
state: 'Client State',
|
||||
state: {
|
||||
label: 'Client State',
|
||||
save: 'Save',
|
||||
load: 'Load',
|
||||
},
|
||||
darkMode: 'Dark Mode',
|
||||
},
|
||||
scheduler: {
|
||||
|
|
|
@ -216,7 +216,6 @@ export const I18N_STRINGS_ES = {
|
|||
limit: 'Historia de la imagen',
|
||||
width: '',
|
||||
},
|
||||
loadState: 'Carga estado',
|
||||
prompt: 'Solicitud predeterminada',
|
||||
reset: {
|
||||
all: 'Resetear todo',
|
||||
|
@ -226,7 +225,11 @@ export const I18N_STRINGS_ES = {
|
|||
},
|
||||
scheduler: 'Programador predeterminado',
|
||||
server: 'Servidor API',
|
||||
state: 'Estado del cliente',
|
||||
state: {
|
||||
label: 'Estado del cliente',
|
||||
load: 'Carga estado',
|
||||
save: '',
|
||||
},
|
||||
darkMode: 'Modo Oscuro',
|
||||
},
|
||||
sourceFilter: {
|
||||
|
|
|
@ -216,7 +216,6 @@ export const I18N_STRINGS_FR = {
|
|||
limit: '',
|
||||
width: '',
|
||||
},
|
||||
loadState: '',
|
||||
prompt: '',
|
||||
reset: {
|
||||
all: '',
|
||||
|
@ -226,7 +225,11 @@ export const I18N_STRINGS_FR = {
|
|||
},
|
||||
scheduler: '',
|
||||
server: '',
|
||||
state: '',
|
||||
state: {
|
||||
label: '',
|
||||
load: '',
|
||||
save: '',
|
||||
},
|
||||
darkMode: 'Mode Sombre',
|
||||
},
|
||||
sourceFilter: {
|
||||
|
|
|
@ -26,3 +26,16 @@ export function trimHash(val: string): string {
|
|||
|
||||
return val;
|
||||
}
|
||||
|
||||
/**
|
||||
* from https://stackoverflow.com/a/30800715
|
||||
*/
|
||||
export function downloadAsJson(data: object, filename = 'parameters.json'): void {
|
||||
const dataStr = 'data:text/json;charset=utf-8,' + encodeURIComponent(JSON.stringify(data));
|
||||
const elem = document.createElement('a');
|
||||
elem.setAttribute('href', dataStr);
|
||||
elem.setAttribute('download', filename);
|
||||
document.body.appendChild(elem); // required for firefox
|
||||
elem.click();
|
||||
elem.remove();
|
||||
}
|
||||
|
|
|
@ -389,6 +389,11 @@
|
|||
"@jridgewell/resolve-uri" "3.1.0"
|
||||
"@jridgewell/sourcemap-codec" "1.4.14"
|
||||
|
||||
"@juggle/resize-observer@^3.3.1":
|
||||
version "3.4.0"
|
||||
resolved "https://registry.yarnpkg.com/@juggle/resize-observer/-/resize-observer-3.4.0.tgz#08d6c5e20cf7e4cc02fd181c4b0c225cd31dbb60"
|
||||
integrity sha512-dfLbk+PwWvFzSxwk3n5ySL0hfBog779o8h68wK/7/APo/7cgyWp5jcXockbxdk5kFRkbeXWm4Fbi9FrdN381sA==
|
||||
|
||||
"@mochajs/multi-reporter@^1.1.0":
|
||||
version "1.1.0"
|
||||
resolved "https://registry.yarnpkg.com/@mochajs/multi-reporter/-/multi-reporter-1.1.0.tgz#378aafd9b9ecbd612753899a3be35026b79b62a5"
|
||||
|
@ -806,6 +811,18 @@ ajv@^6.10.0, ajv@^6.12.4:
|
|||
json-schema-traverse "^0.4.1"
|
||||
uri-js "^4.2.2"
|
||||
|
||||
allotment@^1.19.5:
|
||||
version "1.19.5"
|
||||
resolved "https://registry.yarnpkg.com/allotment/-/allotment-1.19.5.tgz#238e5457cba8ebfc5a6a59c411b4c563048b38ed"
|
||||
integrity sha512-lQDeuqMkEEzITT56NAXNOWxRXycqVyV62w3X7jVZQS9n+cznDx6RLJMD1cnWcRMfCdPUmAj07FAIR69ueytxDQ==
|
||||
dependencies:
|
||||
classnames "^2.3.0"
|
||||
eventemitter3 "^5.0.0"
|
||||
lodash.clamp "^4.0.0"
|
||||
lodash.debounce "^4.0.0"
|
||||
lodash.isequal "^4.5.0"
|
||||
use-resize-observer "^9.0.0"
|
||||
|
||||
ansi-colors@4.1.1:
|
||||
version "4.1.1"
|
||||
resolved "https://registry.yarnpkg.com/ansi-colors/-/ansi-colors-4.1.1.tgz#cbb9ae256bf750af1eab344f229aa27fe94ba348"
|
||||
|
@ -1056,6 +1073,11 @@ chokidar@3.5.3, chokidar@^3.5.3:
|
|||
optionalDependencies:
|
||||
fsevents "~2.3.2"
|
||||
|
||||
classnames@^2.3.0:
|
||||
version "2.5.1"
|
||||
resolved "https://registry.yarnpkg.com/classnames/-/classnames-2.5.1.tgz#ba774c614be0f016da105c858e7159eae8e7687b"
|
||||
integrity sha512-saHYOzhIQs6wy2sVxTM6bUDsQO4F50V9RQ22qBpEdCW+I+/Wmke2HOl6lS6dTpdxVhb88/I6+Hs+438c3lfUow==
|
||||
|
||||
cliui@^7.0.2:
|
||||
version "7.0.4"
|
||||
resolved "https://registry.yarnpkg.com/cliui/-/cliui-7.0.4.tgz#a0265ee655476fc807aea9df3df8df7783808b4f"
|
||||
|
@ -1568,6 +1590,11 @@ esutils@^2.0.2:
|
|||
resolved "https://registry.yarnpkg.com/esutils/-/esutils-2.0.3.tgz#74d2eb4de0b8da1293711910d50775b9b710ef64"
|
||||
integrity sha512-kVscqXk4OCp68SZ0dkgEKVi6/8ij300KBWTJq32P/dYeWTSwK41WyTxalN1eRmA5Z9UU/LX9D7FWSmV9SAYx6g==
|
||||
|
||||
eventemitter3@^5.0.0:
|
||||
version "5.0.1"
|
||||
resolved "https://registry.yarnpkg.com/eventemitter3/-/eventemitter3-5.0.1.tgz#53f5ffd0a492ac800721bb42c66b841de96423c4"
|
||||
integrity sha512-GWkBvjiSZK87ELrYOSESUYeVIc9mvLLf/nXalMOS5dYrgZq9o5OVkbZAVM06CVxYsCwH9BDZFPlQTlPA1j4ahA==
|
||||
|
||||
exifreader@^4.13.0:
|
||||
version "4.13.0"
|
||||
resolved "https://registry.yarnpkg.com/exifreader/-/exifreader-4.13.0.tgz#f380b33cfc85630a0dbd56edd41e28710a9e9679"
|
||||
|
@ -2233,11 +2260,26 @@ locate-path@^6.0.0:
|
|||
dependencies:
|
||||
p-locate "^5.0.0"
|
||||
|
||||
lodash.clamp@^4.0.0:
|
||||
version "4.0.3"
|
||||
resolved "https://registry.yarnpkg.com/lodash.clamp/-/lodash.clamp-4.0.3.tgz#5c24bedeeeef0753560dc2b4cb4671f90a6ddfaa"
|
||||
integrity sha512-HvzRFWjtcguTW7yd8NJBshuNaCa8aqNFtnswdT7f/cMd/1YKy5Zzoq4W/Oxvnx9l7aeY258uSdDfM793+eLsVg==
|
||||
|
||||
lodash.debounce@^4.0.0:
|
||||
version "4.0.8"
|
||||
resolved "https://registry.yarnpkg.com/lodash.debounce/-/lodash.debounce-4.0.8.tgz#82d79bff30a67c4005ffd5e2515300ad9ca4d7af"
|
||||
integrity sha512-FT1yDzDYEoYWhnSGnpE/4Kj1fLZkDFyqRb7fNt6FdYOSxlUWAtp42Eh6Wb0rGIv/m9Bgo7x4GhQbm5Ys4SG5ow==
|
||||
|
||||
lodash.get@^4.4.2:
|
||||
version "4.4.2"
|
||||
resolved "https://registry.yarnpkg.com/lodash.get/-/lodash.get-4.4.2.tgz#2d177f652fa31e939b4438d5341499dfa3825e99"
|
||||
integrity sha512-z+Uw/vLuy6gQe8cfaFWD7p0wVv8fJl3mbzXh33RS+0oW2wvUqiRXiQ69gLWSLpgB5/6sU+r6BlQR0MBILadqTQ==
|
||||
|
||||
lodash.isequal@^4.5.0:
|
||||
version "4.5.0"
|
||||
resolved "https://registry.yarnpkg.com/lodash.isequal/-/lodash.isequal-4.5.0.tgz#415c4478f2bcc30120c22ce10ed3226f7d3e18e0"
|
||||
integrity sha512-pDo3lu8Jhfjqls6GkMgpahsF9kCyayhgykjyLMNFTKWrpVdAQtYyB4muAMWozBB4ig/dtWAmsMxLEI8wuz+DYQ==
|
||||
|
||||
lodash.merge@^4.6.2:
|
||||
version "4.6.2"
|
||||
resolved "https://registry.yarnpkg.com/lodash.merge/-/lodash.merge-4.6.2.tgz#558aa53b43b661e1925a0afdfa36a9a1085fe57a"
|
||||
|
@ -3101,6 +3143,13 @@ uri-js@^4.2.2:
|
|||
dependencies:
|
||||
punycode "^2.1.0"
|
||||
|
||||
use-resize-observer@^9.0.0:
|
||||
version "9.1.0"
|
||||
resolved "https://registry.yarnpkg.com/use-resize-observer/-/use-resize-observer-9.1.0.tgz#14735235cf3268569c1ea468f8a90c5789fc5c6c"
|
||||
integrity sha512-R25VqO9Wb3asSD4eqtcxk8sJalvIOYBqS8MNZlpDSQ4l4xMQxC/J7Id9HoTqPq8FwULIn0PVW+OAqF2dyYbjow==
|
||||
dependencies:
|
||||
"@juggle/resize-observer" "^3.3.1"
|
||||
|
||||
use-sync-external-store@1.2.0, use-sync-external-store@^1.2.0:
|
||||
version "1.2.0"
|
||||
resolved "https://registry.yarnpkg.com/use-sync-external-store/-/use-sync-external-store-1.2.0.tgz#7dbefd6ef3fe4e767a0cf5d7287aacfb5846928a"
|
||||
|
|
Loading…
Reference in New Issue