Scroll to output (#1077)

* implement loader + scroll into view

* changes

* refactor components to use Block inside the app

* cleanup

* cleanup

* implement all changes for all changes for all relevant components

* fix formatting

* demos

* add status tracker to every component

* fix tests

* fix unti test flake: randInt

* cleanup CI

* fix CI

Co-authored-by: Abubakar Abid <abubakar@huggingface.co>
This commit is contained in:
pngwn 2022-04-26 15:48:39 +01:00 committed by GitHub
parent 73ac1e1389
commit 2b0898b9a2
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
58 changed files with 1111 additions and 931 deletions

View File

@ -58,12 +58,6 @@ jobs:
node-version: 16
cache: pnpm
cache-dependency-path: ui/pnpm-lock.yaml
- name: Cache browsers
id: browser_cache
uses: actions/cache@main
with:
path: "~/.cache/ms-playwright"
key: chromium-${{ runner.os }}-${{ hashFiles('**/pnpm-lock.yaml') }}
- run: pnpm install --frozen-lockfile
- run: pnpx playwright install chromium
- run: pnpm build

View File

@ -1,3 +1,4 @@
import os
import json
import numpy as np
@ -40,9 +41,9 @@ def fn(
}, # Label
(audio1[0], np.flipud(audio1[1]))
if audio1 is not None
else "files/cantina.wav", # Audio
np.flipud(im1) if im1 is not None else "files/cheetah1.jpg", # Image
video if video is not None else "files/world.mp4", # Video
else os.path.join(os.path.dirname(__file__),"files/cantina.wav"), # Audio
np.flipud(im1) if im1 is not None else os.path.join(os.path.dirname(__file__),"files/cheetah1.jpg"), # Image
video if video is not None else os.path.join(os.path.dirname(__file__),"files/world.mp4"), # Video
[
("The", "art"),
("quick brown", "adj"),
@ -72,11 +73,11 @@ def fn(
"<button style='background-color: red'>Click Me: "
+ radio
+ "</button>", # HTML
"files/titanic.csv",
os.path.join(os.path.dirname(__file__),"files/titanic.csv"),
df1, # Dataframe
np.random.randint(0, 10, (4, 4)), # Dataframe
[
im for im in [im1, im2, im3, im4, "files/cheetah1.jpg"] if im is not None
im for im in [im1, im2, im3, im4, os.path.join(os.path.dirname(__file__),"files/cheetah1.jpg")] if im is not None
], # Carousel
df2, # Timeseries
)
@ -136,16 +137,16 @@ demo = gr.Interface(
["foo", "baz"],
"baz",
"bar",
"files/cheetah1.jpg",
"files/cheetah1.jpg",
"files/cheetah1.jpg",
"files/cheetah1.jpg",
"files/world.mp4",
"files/cantina.wav",
"files/cantina.wav",
"files/titanic.csv",
os.path.join(os.path.dirname(__file__),"files/cheetah1.jpg"),
os.path.join(os.path.dirname(__file__),"files/cheetah1.jpg"),
os.path.join(os.path.dirname(__file__),"files/cheetah1.jpg"),
os.path.join(os.path.dirname(__file__),"files/cheetah1.jpg"),
os.path.join(os.path.dirname(__file__),"files/world.mp4"),
os.path.join(os.path.dirname(__file__),"files/cantina.wav"),
os.path.join(os.path.dirname(__file__),"files/cantina.wav"),
os.path.join(os.path.dirname(__file__),"files/titanic.csv"),
[[1, 2, 3], [3, 4, 5]],
"files/time.csv",
os.path.join(os.path.dirname(__file__),"files/time.csv"),
]
]
* 3,

View File

@ -1,6 +1,6 @@
from math import log2, pow
import os
import matplotlib.pyplot as plt
import numpy as np
from scipy.fftpack import fft
@ -46,8 +46,8 @@ demo = gr.Interface(
gr.Audio(source="microphone"),
gr.Label(num_top_classes=4),
examples=[
["audio/recording1.wav"],
["audio/cantina.wav"],
[os.path.join(os.path.dirname(__file__),"audio/recording1.wav")],
[os.path.join(os.path.dirname(__file__),"audio/cantina.wav")],
],
interpretation="default",
)

View File

@ -1,3 +1,4 @@
import os
from zipfile import ZipFile
import gradio as gr
@ -15,7 +16,8 @@ demo = gr.Interface(
["file", "file"],
"file",
examples=[
["files/titanic.csv", "files/titanic.csv"],
[os.path.join(os.path.dirname(__file__),"files/titanic.csv"),
os.path.join(os.path.dirname(__file__),"files/titanic.csv")],
],
)

View File

@ -23,32 +23,32 @@
"dependencies": {
"@gradio/tootils": "workspace:^0.0.1",
"@playwright/test": "^1.20.0",
"@sveltejs/vite-plugin-svelte": "^1.0.0-next.36",
"@sveltejs/vite-plugin-svelte": "^1.0.0-next.41",
"@tailwindcss/forms": "^0.5.0",
"@testing-library/dom": "^8.11.3",
"@testing-library/svelte": "^3.1.0",
"@testing-library/user-event": "^13.5.0",
"autoprefixer": "^10.4.4",
"babylonjs": "^4.2.1",
"babylonjs-loaders": "^4.2.1",
"happy-dom": "^2.49.0",
"npm-run-all": "^4.1.5",
"plotly.js-dist-min": "^2.10.1",
"polka": "^1.0.0-next.22",
"postcss": "^8.4.5",
"postcss-nested": "^5.0.6",
"prettier": "^2.5.1",
"prettier-plugin-svelte": "^2.6.0",
"prettier": "^2.6.2",
"prettier-plugin-svelte": "^2.7.0",
"sirv": "^2.0.2",
"sirv-cli": "^2.0.2",
"svelte": "^3.46.3",
"svelte-check": "^2.4.1",
"svelte": "^3.47.0",
"svelte-check": "^2.7.0",
"svelte-i18n": "^3.3.13",
"svelte-preprocess": "^4.10.1",
"svelte-preprocess": "^4.10.6",
"tailwindcss": "^3.0.23",
"tinyspy": "^0.3.0",
"vite": "^2.9.1",
"vitest": "^0.3.2",
"plotly.js-dist-min": "^2.10.1",
"babylonjs": "^4.2.1",
"babylonjs-loaders": "^4.2.1"
"vite": "^2.9.5",
"vitest": "^0.10.0"
},
"devDependencies": {
"@types/three": "^0.138.0"

View File

@ -55,7 +55,7 @@
value?: unknown;
}
const instance_map = components.reduce((acc, next) => {
let instance_map = components.reduce((acc, next) => {
return {
...acc,
[next.id]: {
@ -89,8 +89,6 @@
_n.has_modes = true;
}
// console.log(await _component_map.get(meta.type));
if (node.children) {
_n.children = await Promise.all(node.children.map((v) => walk_layout(v)));
}
@ -107,6 +105,7 @@
});
let tree;
Promise.all(Array.from(component_set)).then((v) => {
Promise.all(layout.children.map((c) => walk_layout(c))).then((v) => {
console.log(v);
@ -114,17 +113,17 @@
});
});
function set_prop(obj: Instance, prop: string, val: any) {
if (!obj?.props) {
obj.props = {};
}
obj.props[prop] = val;
tree = tree;
}
let handled_dependencies: Array<number[]> = [];
let status_tracker_values: Record<number, string> = {};
let set_status = (dependency_index: number, status: string) => {
dependencies[dependency_index].status = status;
let status_tracker_id = dependencies[dependency_index].status_tracker;
if (status_tracker_id !== null) {
status_tracker_values[status_tracker_id] = status;
}
};
async function handle_mount({ detail }) {
await tick();
dependencies.forEach(({ targets, trigger, inputs, outputs, queue }, i) => {
@ -164,14 +163,15 @@
}
target_instances.forEach(([id, { instance }]: [number, Instance]) => {
// console.log(id, handled_dependencies[i]?.includes(id) || !instance);
if (handled_dependencies[i]?.includes(id) || !instance) return;
// console.log(trigger, target_instances, instance);
instance?.$on(trigger, () => {
if (status === "pending") {
return;
}
set_status(i, "pending");
outputs.forEach((_id) =>
set_prop(instance_map[_id], "loading_status", "pending")
);
fn(
"predict",
{
@ -182,13 +182,21 @@
() => {}
)
.then((output) => {
set_status(i, "complete");
// set_status(i, "complete");
output.data.forEach((value, i) => {
instance_map[outputs[i]].value = value;
set_prop(
instance_map[outputs[i]],
"loading_status",
"complete"
);
});
})
.catch((error) => {
set_status(i, "error");
outputs.forEach((_id) =>
set_prop(instance_map[_id], "loading_status", "error")
);
console.error(error);
});
});

View File

@ -79,6 +79,9 @@
node.props.form_position = "single";
}
}
children =
children &&
children.filter((v) => instance_map[v.id].type !== "statustracker");
</script>
<svelte:component
@ -91,7 +94,7 @@
tracked_status={status_tracker_values[id]}
>
{#if children && children.length}
{#each children as { component, id, props, children, has_modes }}
{#each children as { component, id, props, children, has_modes } (id)}
<svelte:self
{component}
{id}

View File

@ -2,6 +2,9 @@
import { Audio, StaticAudio } from "@gradio/audio";
import type { FileData } from "@gradio/upload";
import { normalise_file } from "@gradio/upload";
import { Block } from "@gradio/atoms";
import StatusTracker from "../StatusTracker/StatusTracker.svelte";
import { _ } from "svelte-i18n";
export let mode: "static" | "dynamic";
@ -14,29 +17,44 @@
export let label: string;
export let root: string;
export let loading_status: "complete" | "pending" | "error";
if (default_value) value = default_value;
let _value: null | FileData;
$: _value = normalise_file(value, root);
let dragging: boolean;
</script>
{#if mode === "dynamic"}
<Audio
{label}
value={_value}
on:change={({ detail }) => (value = detail)}
{style}
{name}
{source}
{type}
on:edit
on:play
on:pause
on:ended
drop_text={$_("interface.drop_audio")}
or_text={$_("or")}
upload_text={$_("interface.click_to_upload")}
/>
{:else}
<StaticAudio value={_value} name={_value?.name || "audio_file"} {label} />
{/if}
<Block
variant={mode === "dynamic" && value === null && source === "upload"
? "dashed"
: "solid"}
color={dragging ? "green" : "grey"}
padding={false}
>
<StatusTracker tracked_status={loading_status} />
{#if mode === "dynamic"}
<Audio
{label}
value={_value}
on:change={({ detail }) => (value = detail)}
on:drag={({ detail }) => (dragging = detail)}
{style}
{name}
{source}
{type}
on:edit
on:play
on:pause
on:ended
drop_text={$_("interface.drop_audio")}
or_text={$_("or")}
upload_text={$_("interface.click_to_upload")}
/>
{:else}
<StaticAudio value={_value} name={_value?.name || "audio_file"} {label} />
{/if}
</Block>

View File

@ -3,7 +3,7 @@
import { _ } from "svelte-i18n";
export let value: string;
export let default_value: string;
export let default_value: string | undefined = undefined;
export let style: string = "";
export let variant: "primary" | "secondary" = "primary";

View File

@ -1,9 +1,13 @@
<script lang="ts">
import { Carousel } from "@gradio/carousel";
import StatusTracker from "../StatusTracker/StatusTracker.svelte";
export let style: string = "";
export let loading_status: "complete" | "pending" | "error";
</script>
<Carousel {style} on:change>
<StatusTracker tracked_status={loading_status} />
<slot />
</Carousel>

View File

@ -4,7 +4,7 @@
import api_logo from "../../../public/static/img/api-logo.svg";
</script>
<Carousel on:change>
<Carousel on:change loading_status="complete">
<CarouselItem>
<h1>Item 1</h1>
</CarouselItem>

View File

@ -1,11 +1,19 @@
<script lang="ts">
import { ChatBot } from "@gradio/chatbot";
import { Block } from "@gradio/atoms";
import StatusTracker from "../StatusTracker/StatusTracker.svelte";
export let value: Array<[string, string]> = [];
export let default_value: Array<[string, string]>;
export let style: string = "";
export let loading_status: "complete" | "pending" | "error";
if (default_value) value = default_value;
</script>
<ChatBot {value} {style} on:change />
<Block padding={false}>
<StatusTracker tracked_status={loading_status} />
<ChatBot {value} {style} on:change />
</Block>

View File

@ -1,5 +1,7 @@
<script lang="ts">
import { Checkbox } from "@gradio/form";
import { Block } from "@gradio/atoms";
import StatusTracker from "../StatusTracker/StatusTracker.svelte";
export let value: boolean = false;
export let default_value: boolean = false;
@ -8,14 +10,13 @@
export let mode: "static" | "dynamic";
export let form_position: "first" | "last" | "mid" | "single" = "single";
export let loading_status: "complete" | "pending" | "error";
if (default_value) value = default_value;
</script>
<Checkbox
{form_position}
{style}
{label}
bind:value
on:change
disabled={mode === "static"}
/>
<Block {form_position}>
<StatusTracker tracked_status={loading_status} />
<Checkbox {style} {label} bind:value on:change disabled={mode === "static"} />
</Block>

View File

@ -1,5 +1,7 @@
<script lang="ts">
import { CheckboxGroup } from "@gradio/form";
import { Block } from "@gradio/atoms";
import StatusTracker from "../StatusTracker/StatusTracker.svelte";
export let value: Array<string> = [];
export let default_value: Array<string> = [];
@ -10,15 +12,20 @@
export let label: string = "Checkbox Group";
export let form_position: "first" | "last" | "mid" | "single" = "single";
export let loading_status: "complete" | "pending" | "error";
if (default_value) value = default_value;
</script>
<CheckboxGroup
{form_position}
bind:value
{choices}
{style}
{label}
on:change
disabled={mode === "static"}
/>
<Block {form_position} type="fieldset">
<StatusTracker tracked_status={loading_status} />
<CheckboxGroup
bind:value
{choices}
{style}
{label}
on:change
disabled={mode === "static"}
/>
</Block>

View File

@ -1,5 +1,6 @@
<script lang="ts">
import { Table } from "@gradio/table";
import StatusTracker from "../StatusTracker/StatusTracker.svelte";
import { createEventDispatcher, tick } from "svelte";
type Headers = Array<string>;
@ -25,6 +26,8 @@
const dispatch = createEventDispatcher();
export let loading_status: "complete" | "pending" | "error";
async function handle_change({ detail }) {
value = detail;
await tick();
@ -32,10 +35,13 @@
}
</script>
<Table
values={value}
{headers}
{style}
on:change={handle_change}
editable={mode === "dynamic"}
/>
<div class="relative">
<StatusTracker tracked_status={loading_status} />
<Table
values={value}
{headers}
{style}
on:change={handle_change}
editable={mode === "dynamic"}
/>
</div>

View File

@ -1,5 +1,8 @@
<script lang="ts">
import { Dropdown } from "@gradio/form";
import { Block } from "@gradio/atoms";
import StatusTracker from "../StatusTracker/StatusTracker.svelte";
export let label: string = "Dropdown";
export let value: string = "";
export let default_value: string = "";
@ -7,17 +10,22 @@
export let choices: Array<string>;
export let form_position: "first" | "last" | "mid" | "single" = "single";
export let loading_status: "complete" | "pending" | "error";
export let mode: "static" | "dynamic";
if (default_value) value = default_value;
</script>
<Dropdown
{form_position}
bind:value
{style}
{choices}
{label}
on:change
disabled={mode === "static"}
/>
<Block {form_position}>
<StatusTracker tracked_status={loading_status} />
<Dropdown
bind:value
{style}
{choices}
{label}
on:change
disabled={mode === "static"}
/>
</Block>

View File

@ -2,6 +2,9 @@
import { File, FileUpload } from "@gradio/file";
import type { FileData } from "@gradio/upload";
import { normalise_file } from "@gradio/upload";
import { Block } from "@gradio/atoms";
import StatusTracker from "../StatusTracker/StatusTracker.svelte";
import { _ } from "svelte-i18n";
export let value: null | FileData = null;
@ -9,24 +12,38 @@
export let style: string = "";
export let mode: "static" | "dynamic";
export let root: string;
export let label: string;
export let loading_status: "complete" | "pending" | "error";
if (default_value) value = default_value;
let _value: null | FileData;
$: _value = normalise_file(value, root);
let dragging = false;
</script>
{#if mode === "dynamic"}
<FileUpload
value={_value}
on:change={({ detail }) => (value = detail)}
{style}
on:change
on:clear
drop_text={$_("interface.drop_file")}
or_text={$_("or")}
upload_text={$_("interface.click_to_upload")}
/>
{:else if _value}
<File value={_value} {style} />
{/if}
<Block
variant={mode === "dynamic" && value === null ? "dashed" : "solid"}
color={dragging ? "green" : "grey"}
padding={false}
>
<StatusTracker tracked_status={loading_status} />
{#if mode === "dynamic"}
<FileUpload
value={_value}
on:change={({ detail }) => (value = detail)}
on:drag={({ detail }) => (dragging = detail)}
{style}
on:change
on:clear
drop_text={$_("interface.drop_file")}
or_text={$_("or")}
upload_text={$_("interface.click_to_upload")}
/>
{:else}
<File value={_value} {style} {label} />
{/if}
</Block>

View File

@ -1,6 +1,8 @@
<script lang="ts">
import { createEventDispatcher } from "svelte";
import { HighlightedText } from "@gradio/highlighted-text";
import { Block } from "@gradio/atoms";
import StatusTracker from "../StatusTracker/StatusTracker.svelte";
export let value: Array<[string, string | number]>;
export let default_value: Array<[string, string | number]>;
@ -8,6 +10,8 @@
export let show_legend: boolean;
export let color_map: Record<string, string> = {};
export let loading_status: "complete" | "pending" | "error";
const dispatch = createEventDispatcher<{ change: undefined }>();
if (default_value) value = default_value;
@ -15,4 +19,8 @@
$: value, dispatch("change");
</script>
<HighlightedText {value} {style} {show_legend} {color_map} />
<Block>
<StatusTracker tracked_status={loading_status} />
<HighlightedText {value} {style} {show_legend} {color_map} />
</Block>

View File

@ -1,7 +1,9 @@
<script lang="ts">
import { createEventDispatcher } from "svelte";
import { Image, StaticImage } from "@gradio/image";
import { Block } from "@gradio/atoms";
import { _ } from "svelte-i18n";
import { Component as StatusTracker } from "../StatusTracker/";
export let value: null | string = null;
export let default_value: null | string = null;
@ -10,6 +12,8 @@
export let tool: "editor" | "select" = "editor";
export let label: string;
export let loading_status: "complete" | "pending" | "error";
export let mode: "static" | "dynamic";
const dispatch = createEventDispatcher<{ change: undefined }>();
@ -17,22 +21,34 @@
if (default_value) value = default_value;
$: value, dispatch("change");
let dragging: boolean;
</script>
{#if mode === "static"}
<StaticImage {value} {label} {style} />
{:else}
<Image
bind:value
{style}
{source}
{tool}
on:edit
on:clear
on:change
{label}
drop_text={$_("interface.drop_image")}
or_text={$_("or")}
upload_text={$_("interface.click_to_upload")}
/>
{/if}
<Block
variant={mode === "dynamic" && value === null && source === "upload"
? "dashed"
: "solid"}
color={dragging ? "green" : "grey"}
padding={false}
>
<StatusTracker tracked_status={loading_status} />
{#if mode === "static"}
<StaticImage {value} {label} {style} />
{:else}
<Image
bind:value
{style}
{source}
{tool}
on:edit
on:clear
on:change
on:drag={({ detail }) => (dragging = detail)}
{label}
drop_text={$_("interface.drop_image")}
or_text={$_("or")}
upload_text={$_("interface.click_to_upload")}
/>
{/if}
</Block>

View File

@ -1,10 +1,14 @@
<script lang="ts">
import { createEventDispatcher } from "svelte";
import { JSON } from "@gradio/json";
import { Block } from "@gradio/atoms";
import StatusTracker from "../StatusTracker/StatusTracker.svelte";
export let value: any = {};
export let default_value: any;
export let style: string = "";
export let loading_status: "complete" | "pending" | "error";
const dispatch = createEventDispatcher<{ change: undefined }>();
@ -13,4 +17,8 @@
if (default_value) value = default_value;
</script>
<JSON {style} {value} />
<Block test_id="json">
<StatusTracker tracked_status={loading_status} />
<JSON {style} {value} />
</Block>

View File

@ -1,6 +1,8 @@
<script lang="ts">
import { createEventDispatcher } from "svelte";
import { Label } from "@gradio/label";
import { Block } from "@gradio/atoms";
import StatusTracker from "../StatusTracker/StatusTracker.svelte";
export let value: {
label: string;
@ -13,6 +15,7 @@
};
export let style: string = "";
export let loading_status: "complete" | "pending" | "error";
const dispatch = createEventDispatcher<{ change: undefined }>();
@ -21,6 +24,10 @@
$: value, dispatch("change");
</script>
{#if value !== undefined && value !== null}
<Label {style} {value} />
{/if}
<Block>
<StatusTracker tracked_status={loading_status} />
{#if value !== undefined && value !== null}
<Label {style} {value} />
{/if}
</Block>

View File

@ -2,6 +2,9 @@
import type { FileData } from "@gradio/upload";
import { normalise_file } from "@gradio/upload";
import { Model3D, Model3DUpload } from "@gradio/model3D";
import { Block } from "@gradio/atoms";
import StatusTracker from "../StatusTracker/StatusTracker.svelte";
import { _ } from "svelte-i18n";
export let value: null | FileData = null;
@ -11,23 +14,36 @@
export let root: string;
export let clearColor: [];
export let loading_status: "complete" | "pending" | "error";
if (default_value) value = default_value;
let _value: null | FileData;
$: _value = normalise_file(value, root);
let dragging = false;
</script>
{#if mode === "dynamic"}
<Model3DUpload
value={_value}
on:change={({ detail }) => (value = detail)}
{style}
on:change
on:clear
drop_text={$_("interface.drop_file")}
or_text={$_("or")}
upload_text={$_("interface.click_to_upload")}
/>
{:else if _value}
<Model3D value={_value} {clearColor} {style} />
{/if}
<Block
variant={value === null ? "dashed" : "solid"}
color={dragging ? "green" : "grey"}
padding={false}
>
<StatusTracker tracked_status={loading_status} />
{#if mode === "dynamic"}
<Model3DUpload
value={_value}
on:change={({ detail }) => (value = detail)}
on:drag={({ detail }) => (dragging = detail)}
{style}
on:change
on:clear
drop_text={$_("interface.drop_file")}
or_text={$_("or")}
upload_text={$_("interface.click_to_upload")}
/>
{:else if _value}
<Model3D value={_value} {clearColor} {style} />
{/if}
</Block>

View File

@ -1,11 +1,15 @@
<script lang="ts">
import { Number } from "@gradio/form";
import { Block } from "@gradio/atoms";
import StatusTracker from "../StatusTracker/StatusTracker.svelte";
export let label: string = "Number";
export let value: number = 0;
export let default_value: number;
export let form_position: "first" | "last" | "mid" | "single" = "single";
export let loading_status: "complete" | "pending" | "error";
export let style: string = "";
export let mode: "static" | "dynamic";
@ -13,12 +17,15 @@
if (default_value) value = default_value;
</script>
<Number
{form_position}
bind:value
{label}
{style}
disabled={mode === "static"}
on:change
on:submit
/>
<Block {form_position}>
<StatusTracker tracked_status={loading_status} />
<Number
bind:value
{label}
{style}
disabled={mode === "static"}
on:change
on:submit
/>
</Block>

View File

@ -5,6 +5,8 @@
export let default_value: null | string = null;
export let style: string = "";
export let loading_status: "complete" | "pending" | "error";
if (default_value) value = default_value;
</script>

View File

@ -1,5 +1,7 @@
<script lang="ts">
import { Radio } from "@gradio/form";
import { Block } from "@gradio/atoms";
import StatusTracker from "../StatusTracker/StatusTracker.svelte";
export let label: string = "Radio";
export let value: string = "";
@ -9,15 +11,21 @@
export let mode: "static" | "dynamic";
export let form_position: "first" | "last" | "mid" | "single" = "single";
export let loading_status: "complete" | "pending" | "error";
if (default_value) value = default_value;
</script>
<Radio
{form_position}
bind:value
{label}
{style}
{choices}
disabled={mode === "static"}
on:change
/>
<Block {form_position} type="fieldset">
<StatusTracker tracked_status={loading_status} />
<Radio
{form_position}
bind:value
{label}
{style}
{choices}
disabled={mode === "static"}
on:change
/>
</Block>

View File

@ -1,5 +1,7 @@
<script lang="ts">
import { Range } from "@gradio/form";
import { Block } from "@gradio/atoms";
import StatusTracker from "../StatusTracker/StatusTracker.svelte";
export let value: number = 0;
@ -13,17 +15,22 @@
export let mode: "static" | "dynamic";
export let form_position: "first" | "last" | "mid" | "single" = "single";
export let loading_status: "complete" | "pending" | "error";
if (default_value) value = default_value;
</script>
<Range
{form_position}
bind:value
{label}
{style}
{minimum}
{maximum}
{step}
disabled={mode === "static"}
on:change
/>
<Block {form_position}>
<StatusTracker tracked_status={loading_status} />
<Range
bind:value
{label}
{style}
{minimum}
{maximum}
{step}
disabled={mode === "static"}
on:change
/>
</Block>

View File

@ -23,21 +23,22 @@
async function run() {
await animate();
console.log(dismounted);
if (!dismounted) run();
}
async function loading() {}
onMount(async () => {
async function loading() {
await Promise.all([top.set([125, 0]), bottom.set([-125, 0])]);
run();
}
onMount(() => {
loading();
return () => (dismounted = true);
});
</script>
<div class="m-12" style="transform: translateY(3rem)">
<div class="m-12">
<svg
class="text-xl"
width="7em"

View File

@ -1,74 +1,100 @@
<script lang="ts">
import { onDestroy } from "svelte";
<script context="module" lang="ts">
import { tick } from "svelte";
export let style: string = "";
export let cover_container: bool = false;
export let eta: number | null = null;
export let duration: number = 8.2;
export let queue_pos: number | null = 0;
export let tracked_status: "complete" | "pending" | "error";
let items: Array<HTMLDivElement> = [];
$: progress = eta === null ? null : Math.min(duration / eta, 1);
let called = false;
let timer: NodeJS.Timeout = null;
let timer_start = 0;
let timer_diff = 0;
async function scroll_into_view(el: HTMLDivElement) {
items.push(el);
if (!called) called = true;
else return;
const start_timer = () => {
timer_start = Date.now();
timer_diff = 0;
timer = setInterval(() => {
timer_diff = (Date.now() - timer_start) / 1000;
}, 100);
};
await tick();
const stop_timer = () => {
clearInterval(timer);
};
requestAnimationFrame(() => {
let min = [0, 0];
onDestroy(() => {
if (timer) stop_timer();
});
for (let i = 0; i < items.length; i++) {
const element = items[i];
$: {
if (tracked_status === "pending") {
start_timer();
} else {
stop_timer();
}
const box = element.getBoundingClientRect();
if (i === 0 || box.top + window.scrollY <= min[0]) {
min[0] = box.top + window.scrollY;
min[1] = i;
}
}
window.scrollTo({ top: min[0] - 20, behavior: "smooth" });
called = false;
items = [];
});
}
</script>
{#if tracked_status === "pending"}
<div class:cover_container {style}>
<div class="text-xs font-mono text-gray-400">
{#if queue_pos}
{queue_pos} in line
{:else}
{timer_diff.toFixed(1)}s
{/if}
</div>
<div class="border-gray-200 rounded border w-40 h-2 relative">
{#if progress === null}
<div class="bounce absolute bg-amber-500 shadow-inner h-full w-1/4" />
{:else}
<div
class="blink bg-amber-500 shadow-inner h-full"
style="width: {progress * 100}%;"
/>
{/if}
</div>
</div>
{:else if tracked_status === "error"}
<div class:cover_container {style}>
<script lang="ts">
// import { onDestroy, onMount } from "svelte";
import Loader from "./Loader.svelte";
export let style: string = "";
// export let eta: number | null = null;
// export let duration: number = 8.2;
// export let queue_pos: number | null = 0;
export let tracked_status: "complete" | "pending" | "error";
let el: HTMLDivElement;
// $: progress = eta === null ? null : Math.min(duration / eta, 1);
// let timer: NodeJS.Timeout | null = null;
// let timer_start = 0;
// let timer_diff = 0;
// const start_timer = () => {
// timer_start = performance.now();
// timer_diff = 0;
// timer = setInterval(() => {
// timer_diff = (performance.now() - timer_start) / 1000;
// }, 100);
// };
// const stop_timer = () => {
// if (!timer) return;
// clearInterval(timer);
// };
// onDestroy(() => {
// if (timer) stop_timer();
// });
// $: {
// if (tracked_status === "pending") {
// start_timer();
// } else {
// stop_timer();
// }
// }
$: el &&
(tracked_status === "pending" || tracked_status === "complete") &&
scroll_into_view(el);
</script>
<div
class=" absolute top-0 left-0 w-full h-full z-10 flex flex-col justify-center items-center bg-white pointer-events-none transition-opacity"
class:opacity-0={!tracked_status || tracked_status === "complete"}
{style}
bind:this={el}
>
{#if tracked_status === "pending"}
<Loader />
{:else if tracked_status === "error"}
<span class="text-red-400 font-mono font-semibold text-lg">ERROR</span>
</div>
{/if}
{/if}
</div>
<style lang="postcss">
.cover_container {
@apply absolute top-0 left-0 w-full h-full z-10 flex flex-col justify-center items-center bg-gray-100 bg-opacity-25;
}
@keyframes blink {
0% {
opacity: 100%;

View File

@ -2,6 +2,8 @@
<script lang="ts">
import { TextBox } from "@gradio/form";
import { Block } from "@gradio/atoms";
import StatusTracker from "../StatusTracker/StatusTracker.svelte";
export let label: string = "Textbox";
export let value: string = " ";
@ -11,20 +13,25 @@
export let placeholder: string = "";
export let form_position: "first" | "last" | "mid" | "single" = "single";
export let loading_status: "complete" | "pending" | "error";
export let mode: "static" | "dynamic";
if (default_value) value = default_value;
</script>
<TextBox
{form_position}
bind:value
{label}
{style}
{lines}
autoheight={mode === "static"}
{placeholder}
on:change
on:submit
disabled={mode === "static"}
/>
<Block {form_position}>
<StatusTracker tracked_status={loading_status} />
<TextBox
bind:value
{label}
{style}
{lines}
autoheight={mode === "static"}
{placeholder}
on:change
on:submit
disabled={mode === "static"}
/>
</Block>

View File

@ -4,6 +4,8 @@
import type { FileData } from "@gradio/upload";
import { Block, BlockLabel } from "@gradio/atoms";
import { Chart } from "@gradio/chart";
import StatusTracker from "../StatusTracker/StatusTracker.svelte";
import { _ } from "svelte-i18n";
import chart_icon from "./chart.svg";
@ -33,6 +35,8 @@
export let mode: "static" | "dynamic";
export let label: string;
export let loading_status: "complete" | "pending" | "error";
let _value: string | null;
function data_uri_to_blob(data_uri: string) {
@ -109,8 +113,13 @@
if (default_value) value = default_value;
</script>
<Block variant={"solid"} color={"grey"} padding={false}>
<Block
variant={mode === "dynamic" ? "dashed" : "solid"}
color={"grey"}
padding={false}
>
<BlockLabel image={chart_icon} label={label || "TimeSeries"} />
<StatusTracker tracked_status={loading_status} />
{#if mode === "static"}
{#if static_data}
@ -127,16 +136,18 @@
{x}
on:process={({ detail: { x, y } }) => (value = make_dict(x, y))}
/>
{:else if value === null}
<Upload
filetype="text/csv"
on:load={({ detail }) => handle_load(detail)}
include_file_metadata={false}
{style}
>
{$_("interface.drop_csv")}
<br />- {$_("or")} -<br />
{$_("interface.click_to_upload")}
</Upload>
{:else if value === undefined}
<div class="min-h-[8rem]">
<Upload
filetype="text/csv"
on:load={({ detail }) => handle_load(detail)}
include_file_metadata={false}
{style}
>
{$_("interface.drop_csv")}
<br />- {$_("or")} -<br />
{$_("interface.click_to_upload")}
</Upload>
</div>
{/if}
</Block>

View File

@ -1,9 +1,10 @@
<script lang="ts">
import type { FileData } from "@gradio/upload";
import { normalise_file } from "@gradio/upload";
import { playable } from "../utils/helpers";
import { Block } from "@gradio/atoms";
import { Video, StaticVideo } from "@gradio/video";
import StatusTracker from "../StatusTracker/StatusTracker.svelte";
import { _ } from "svelte-i18n";
export let value: FileData | null | string = null;
@ -13,29 +14,44 @@
export let source: string;
export let root: string;
export let loading_status: "complete" | "pending" | "error";
export let mode: "static" | "dynamic";
if (default_value) value = default_value;
let _value: null | FileData;
$: _value = normalise_file(value, root);
let dragging = false;
</script>
{#if mode === "static"}
<StaticVideo value={_value} {label} {style} />
{:else}
<Video
value={_value}
on:change={({ detail }) => (value = detail)}
{label}
{style}
{source}
drop_text={$_("interface.drop_video")}
or_text={$_("or")}
upload_text={$_("interface.click_to_upload")}
on:change
on:clear
on:play
on:pause
/>
{/if}
<Block
variant={mode === "dynamic" && value === null && source === "upload"
? "dashed"
: "solid"}
color={dragging ? "green" : "grey"}
padding={false}
>
<StatusTracker tracked_status={loading_status} />
{#if mode === "static"}
<StaticVideo value={_value} {label} {style} />
{:else}
<Video
value={_value}
on:change={({ detail }) => (value = detail)}
on:drag={({ detail }) => (dragging = detail)}
{label}
{style}
{source}
drop_text={$_("interface.drop_video")}
or_text={$_("or")}
upload_text={$_("interface.click_to_upload")}
on:change
on:clear
on:play
on:pause
/>
{/if}
</Block>

View File

@ -74,7 +74,7 @@ describe("randInt", () => {
test("respects min and max when negative", () => {
const n = randInt(-100, -10);
assert.ok(n > -100 && n < -10);
assert.ok(n >= -100 && n <= -10);
});
});

View File

@ -68,6 +68,6 @@ test("can run an api request and display the data", async ({ page }) => {
page.waitForResponse("**/api/predict/")
]);
const json = await page.locator(".output-json");
const json = await page.locator("data-testid=json");
await expect(json).toContainText(`Covid: 0.75, Lung Cancer: 0.25`);
});

View File

@ -2,7 +2,10 @@
export let variant: "solid" | "dashed" = "solid";
export let color: "grey" | "green" = "grey";
export let padding: boolean = true;
export let form_position: "first" | "last" | "mid" | "single";
export let form_position: "first" | "last" | "mid" | "single" | undefined =
undefined;
export let type: "normal" | "fieldset" = "normal";
export let test_id: string | undefined = undefined;
const styles = {
dashed: "border-dashed border-[3px]",
@ -10,9 +13,13 @@
grey: "border-gray-200",
green: "border-green-400"
};
let tag = type === "fieldset" ? "fieldset" : "div";
</script>
<div
<svelte:element
this={tag}
data-testid={test_id}
class="gr-box overflow-hidden {styles[variant]} {styles[color]}"
class:gr-panel={padding}
class:form={form_position}
@ -21,4 +28,4 @@
class:!rounded-t-none={form_position === "last"}
>
<slot />
</div>
</svelte:element>

View File

@ -42,6 +42,7 @@
play: undefined;
pause: undefined;
ended: undefined;
drag: boolean;
}>();
function blob_to_data_url(blob: Blob): Promise<string> {
@ -148,78 +149,73 @@
}
export let dragging = false;
$: dispatch("drag", dragging);
</script>
<Block
variant={value === null && source === "upload" ? "dashed" : "solid"}
color={dragging ? "green" : "grey"}
padding={false}
>
<BlockLabel image={audio_icon} label={label || "Audio"} />
{#if value === null}
{#if source === "microphone"}
<div class="mt-6 p-2">
{#if recording}
<button class="gr-button !bg-red-500/10" on:click={stop}>
<span class="flex h-1.5 w-1.5 relative mr-2">
<span
class="animate-ping absolute inline-flex h-full w-full rounded-full bg-red-400 opacity-75"
/>
<span
class="relative inline-flex rounded-full h-1.5 w-1.5 bg-red-500"
/>
</span>
<div class="whitespace-nowrap text-red-500">Stop recording</div>
</button>
{:else}
<button class="gr-button" on:click={record}>
<span class="flex h-1.5 w-1.5 relative mr-2">
<span
class="relative inline-flex rounded-full h-1.5 w-1.5 bg-red-500"
/>
</span>
<div class="whitespace-nowrap">Record from microphone</div>
</button>
{/if}
<BlockLabel image={audio_icon} label={label || "Audio"} />
{#if value === null}
{#if source === "microphone"}
<div class="mt-6 p-2">
{#if recording}
<button class="gr-button !bg-red-500/10" on:click={stop}>
<span class="flex h-1.5 w-1.5 relative mr-2">
<span
class="animate-ping absolute inline-flex h-full w-full rounded-full bg-red-400 opacity-75"
/>
<span
class="relative inline-flex rounded-full h-1.5 w-1.5 bg-red-500"
/>
</span>
<div class="whitespace-nowrap text-red-500">Stop recording</div>
</button>
{:else}
<button class="gr-button" on:click={record}>
<span class="flex h-1.5 w-1.5 relative mr-2">
<span
class="relative inline-flex rounded-full h-1.5 w-1.5 bg-red-500"
/>
</span>
<div class="whitespace-nowrap">Record from microphone</div>
</button>
{/if}
</div>
{:else if source === "upload"}
<Upload filetype="audio/*" on:load={handle_load} bind:dragging>
<div class="flex flex-col">
{drop_text}
<span class="text-gray-300">- {or_text} -</span>
{upload_text}
</div>
{:else if source === "upload"}
<Upload filetype="audio/*" on:load={handle_load} bind:dragging>
<div class="flex flex-col">
{drop_text}
<span class="text-gray-300">- {or_text} -</span>
{upload_text}
</div>
</Upload>
{/if}
{:else}
<ModifyUpload
on:clear={clear}
on:edit={() => (mode = "edit")}
editable
absolute={false}
/>
<audio
use:loaded
class="w-full h-14 p-2"
controls
bind:this={player}
preload="metadata"
src={value.data}
on:play
on:pause
on:ended
/>
{#if mode === "edit" && player?.duration}
<Range
bind:values={crop_values}
range
min={0}
max={100}
step={1}
on:change={handle_change}
/>
{/if}
</Upload>
{/if}
</Block>
{:else}
<ModifyUpload
on:clear={clear}
on:edit={() => (mode = "edit")}
editable
absolute={false}
/>
<audio
use:loaded
class="w-full h-14 p-2"
controls
bind:this={player}
preload="metadata"
src={value.data}
on:play
on:pause
on:ended
/>
{#if mode === "edit" && player?.duration}
<Range
bind:values={crop_values}
range
min={0}
max={100}
step={1}
on:change={handle_change}
/>
{/if}
{/if}

View File

@ -31,21 +31,19 @@
});
</script>
<Block variant={"solid"} color={"grey"} padding={false}>
<BlockLabel image={audio_icon} label={label || "Audio"} />
{#if value === null}
<div class="min-h-[8rem] flex justify-center items-center">
<img src={audio_icon} alt="" class="h-6 opacity-20" />
</div>
{:else}
<audio
class="w-full h-14 p-2 mt-7"
controls
preload="metadata"
src={value.data}
on:play
on:pause
on:ended
/>
{/if}
</Block>
<BlockLabel image={audio_icon} label={label || "Audio"} />
{#if value === null}
<div class="min-h-[8rem] flex justify-center items-center">
<img src={audio_icon} alt="" class="h-6 opacity-20" />
</div>
{:else}
<audio
class="w-full h-14 p-2 mt-7"
controls
preload="metadata"
src={value.data}
on:play
on:pause
on:ended
/>
{/if}

View File

@ -45,7 +45,7 @@
};
</script>
<div class="output-carousel flex flex-col">
<div class="output-carousel flex flex-col relative">
<slot />
<div

View File

@ -21,7 +21,7 @@
$: value && dispatch("change");
</script>
<div class="overflow-y-auto h-[40vh] border rounded-lg" bind:this={div}>
<div class="overflow-y-auto h-[40vh]" bind:this={div}>
<div class="flex flex-col items-end space-y-4 p-3">
{#each value as message}
<div

View File

@ -1,38 +1,41 @@
<script lang="ts">
import type { FileData } from "@gradio/upload";
import { BlockLabel } from "@gradio/atoms";
import { prettyBytes } from "./utils";
import file_icon from "./file.svg";
export let value: FileData;
export let value: FileData | null;
export let style: string = "";
export let label: string;
</script>
<a
class="output-file w-full h-full flex flex-row flex-wrap justify-center items-center relative"
href={value.data}
download={value.name}
>
<svg
xmlns="http://www.w3.org/2000/svg"
class="h-10 w-1/5"
fill="none"
viewBox="0 0 24 24"
stroke="currentColor"
>
<path
stroke-linecap="round"
stroke-linejoin="round"
stroke-width="2"
d="M9 12h6m-6 4h6m2 5H7a2 2 0 01-2-2V5a2 2 0 012-2h5.586a1 1 0 01.707.293l5.414 5.414a1 1 0 01.293.707V19a2 2 0 01-2 2z"
/>
</svg>
<div class="file-name w-3/5 text-4xl p-6 break-all">{value.name}</div>
<div class="text-2xl p-2">
{isNaN(value.size || NaN) ? "" : prettyBytes(value.size || 0)}
</div>
</a>
<BlockLabel image={file_icon} label={label || "File"} />
<style lang="postcss">
.output-file[theme="default"] {
@apply h-60 hover:text-gray-500;
}
</style>
{#if value}
<a
class="output-file w-full h-full flex flex-row flex-wrap justify-center items-center relative"
href={value.data}
download={value.name}
>
<svg
xmlns="http://www.w3.org/2000/svg"
class="h-10 w-1/5"
fill="none"
viewBox="0 0 24 24"
stroke="currentColor"
>
<path
stroke-linecap="round"
stroke-linejoin="round"
stroke-width="2"
d="M9 12h6m-6 4h6m2 5H7a2 2 0 01-2-2V5a2 2 0 012-2h5.586a1 1 0 01.707.293l5.414 5.414a1 1 0 01.293.707V19a2 2 0 01-2 2z"
/>
</svg>
<div class="file-name w-3/5 text-4xl p-6 break-all">{value.name}</div>
<div class="text-2xl p-2">
{isNaN(value.size || NaN) ? "" : prettyBytes(value.size || 0)}
</div>
</a>
{:else}
<div class="min-h-[8rem]" />
{/if}

View File

@ -2,7 +2,7 @@
import { createEventDispatcher, tick } from "svelte";
import { Upload, ModifyUpload } from "@gradio/upload";
import type { FileData } from "@gradio/upload";
import { Block, BlockLabel } from "@gradio/atoms";
import { BlockLabel } from "@gradio/atoms";
import { prettyBytes } from "./utils";
import file_icon from "./file.svg";
@ -15,22 +15,23 @@
export let label: string = "";
export let style: string;
let file_count: string;
async function handle_upload({ detail }: CustomEvent<FileData>) {
value = detail;
await tick();
dispatch("change", value);
}
async function handle_clear({ detail }: CustomEvent<null>) {
function handle_clear({ detail }: CustomEvent<null>) {
value = null;
await tick();
dispatch("change", value);
dispatch("clear");
}
const dispatch =
createEventDispatcher<{ change: FileData | null; clear: undefined }>();
const dispatch = createEventDispatcher<{
change: FileData | null;
clear: undefined;
drag: boolean;
}>();
function truncate(str: string): string {
if (str.length > 30) {
@ -39,38 +40,33 @@
}
let dragging = false;
$: dispatch("drag", dragging);
</script>
<Block
variant={value === null ? "dashed" : "solid"}
color={dragging ? "green" : "grey"}
padding={false}
>
<BlockLabel image={file_icon} label={label || "File"} />
<BlockLabel image={file_icon} label={label || "File"} />
{#if value === null}
<Upload on:load={handle_upload} filetype="file" bind:dragging>
{drop_text}
<br />- {or_text} -<br />
{upload_text}
</Upload>
{:else}
<div
class="file-preview w-full flex flex-row justify-between overflow-y-auto mt-7"
>
<ModifyUpload on:clear={handle_clear} absolute />
{#if value === null}
<Upload on:load={handle_upload} filetype="file" bind:dragging>
{drop_text}
<br />- {or_text} -<br />
{upload_text}
</Upload>
{:else}
<div
class="file-preview w-full flex flex-row justify-between overflow-y-auto mt-7"
>
<ModifyUpload on:clear={handle_clear} absolute />
<div class="file-name p-2">
{truncate(value.name)}
</div>
<div class="file-size p-2">
{prettyBytes(value.size || 0)}
</div>
<div class="file-size p-2 hover:underline">
<a href={value.data} download class="text-indigo-600 hover:underline"
>Download</a
>
</div>
<div class="file-name p-2">
{truncate(value.name)}
</div>
{/if}
</Block>
<div class="file-size p-2">
{prettyBytes(value.size || 0)}
</div>
<div class="file-size p-2 hover:underline">
<a href={value.data} download class="text-indigo-600 hover:underline"
>Download</a
>
</div>
</div>
{/if}

View File

@ -7,7 +7,6 @@
export let disabled: boolean = false;
export let label: string;
export let style: string = "";
export let form_position: "first" | "last" | "mid" | "single" = "single";
const dispatch = createEventDispatcher<{ change: boolean }>();
@ -17,19 +16,17 @@
}
</script>
<Block {form_position}>
<!-- svelte-ignore a11y-label-has-associated-control -->
<label
class:!cursor-not-allowed={disabled}
class="flex items-center text-gray-700 text-sm space-x-2 rounded-lg cursor-pointer bg-white"
>
<input
bind:checked={value}
{disabled}
type="checkbox"
name="test"
class="rounded border-gray-300 text-blue-600 disabled:text-gray-400 disabled:!cursor-not-allowed shadow-sm focus:border-blue-300 focus:ring focus:ring-offset-0 focus:ring-blue-200 focus:ring-opacity-50"
/>
<span class="ml-2">{label}</span></label
>
</Block>
<!-- svelte-ignore a11y-label-has-associated-control -->
<label
class:!cursor-not-allowed={disabled}
class="flex items-center text-gray-700 text-sm space-x-2 rounded-lg cursor-pointer bg-white"
>
<input
bind:checked={value}
{disabled}
type="checkbox"
name="test"
class="rounded border-gray-300 text-blue-600 disabled:text-gray-400 disabled:!cursor-not-allowed shadow-sm focus:border-blue-300 focus:ring focus:ring-offset-0 focus:ring-blue-200 focus:ring-opacity-50"
/>
<span class="ml-2">{label}</span></label
>

View File

@ -7,7 +7,6 @@
export let disabled: boolean = false;
export let label: string;
export let style: string = "";
export let form_position: "first" | "last" | "mid" | "single" = "single";
const dispatch = createEventDispatcher<{ change: Array<string> }>();
@ -22,29 +21,22 @@
};
</script>
<fieldset
class="form gr-box overflow-hidden border-solid border border-gray-200 gr-panel"
class:!rounded-none={form_position === "mid"}
class:!rounded-b-none={form_position === "first"}
class:!rounded-t-none={form_position === "last"}
>
<BlockTitle>{label}</BlockTitle>
<BlockTitle>{label}</BlockTitle>
<div class="flex flex-wrap gap-2" data-testid="checkbox-group">
{#each choices as choice, i}
<label
class:!cursor-not-allowed={disabled}
class="flex items-center text-gray-700 text-sm space-x-2 border py-1.5 px-3 rounded-lg cursor-pointer bg-white shadow-sm checked:shadow-inner"
>
<input
{disabled}
on:change={() => toggleChoice(choice)}
checked={value.includes(choice)}
type="checkbox"
name="test"
class="rounded border-gray-300 text-blue-600 disabled:text-gray-400 disabled:cursor-not-allowed shadow-sm focus:border-blue-300 focus:ring focus:ring-offset-0 focus:ring-blue-200 focus:ring-opacity-50"
/> <span class="ml-2">{choice}</span></label
>
{/each}
</div>
</fieldset>
<div class="flex flex-wrap gap-2" data-testid="checkbox-group">
{#each choices as choice, i}
<label
class:!cursor-not-allowed={disabled}
class="flex items-center text-gray-700 text-sm space-x-2 border py-1.5 px-3 rounded-lg cursor-pointer bg-white shadow-sm checked:shadow-inner"
>
<input
{disabled}
on:change={() => toggleChoice(choice)}
checked={value.includes(choice)}
type="checkbox"
name="test"
class="rounded border-gray-300 text-blue-600 disabled:text-gray-400 disabled:cursor-not-allowed shadow-sm focus:border-blue-300 focus:ring focus:ring-offset-0 focus:ring-blue-200 focus:ring-opacity-50"
/> <span class="ml-2">{choice}</span></label
>
{/each}
</div>

View File

@ -7,24 +7,21 @@
export let choices: Array<string>;
export let style: string = "";
export let disabled: boolean = false;
export let form_position: "first" | "last" | "mid" | "single" = "single";
const dispatch = createEventDispatcher<{ change: string }>();
$: dispatch("change", value);
</script>
<Block {form_position}>
<label>
<BlockTitle>{label}</BlockTitle>
<select
class="gr-box gr-input w-full disabled:cursor-not-allowed"
bind:value
{disabled}
>
{#each choices as choice, i}
<option>{choice}</option>
{/each}
</select>
</label>
</Block>
<label>
<BlockTitle>{label}</BlockTitle>
<select
class="gr-box gr-input w-full disabled:cursor-not-allowed"
bind:value
{disabled}
>
{#each choices as choice, i}
<option>{choice}</option>
{/each}
</select>
</label>

View File

@ -6,10 +6,11 @@
export let disabled: boolean = false;
export let label: string;
export let style: string = "";
export let form_position: "first" | "last" | "mid" | "single" = "single";
const dispatch =
createEventDispatcher<{ change: number; submit: undefined }>();
const dispatch = createEventDispatcher<{
change: number;
submit: undefined;
}>();
function handle_change(n: number) {
dispatch("change", n);
@ -27,16 +28,14 @@
$: handle_change(value);
</script>
<Block {form_position}>
<!-- svelte-ignore a11y-label-has-associated-control -->
<label class="block">
<BlockTitle>{label}</BlockTitle>
<input
type="number"
class="gr-box gr-input w-full gr-text-input"
bind:value
on:keypress={handle_keypress}
{disabled}
/>
</label>
</Block>
<!-- svelte-ignore a11y-label-has-associated-control -->
<label class="block">
<BlockTitle>{label}</BlockTitle>
<input
type="number"
class="gr-box gr-input w-full gr-text-input"
bind:value
on:keypress={handle_keypress}
{disabled}
/>
</label>

View File

@ -14,29 +14,22 @@
$: dispatch("change", value);
</script>
<fieldset
class="form gr-box overflow-hidden border-solid border border-gray-200 gr-panel"
class:!rounded-none={form_position === "mid"}
class:!rounded-b-none={form_position === "first"}
class:!rounded-t-none={form_position === "last"}
>
<BlockTitle>{label}</BlockTitle>
<BlockTitle>{label}</BlockTitle>
<div class="flex flex-wrap gap-2">
{#each choices as choice, i}
<label
class:!cursor-not-allowed={disabled}
class="flex items-center text-gray-700 text-sm space-x-2 border py-1.5 px-3 rounded-lg cursor-pointer bg-white shadow-sm checked:shadow-inner"
>
<input
{disabled}
bind:group={value}
type="radio"
name="test"
class="rounded-full border-gray-300 text-blue-600 disabled:text-gray-400 disabled:cursor-not-allowed shadow-sm focus:border-blue-300 focus:ring focus:ring-offset-0 focus:ring-blue-200 focus:ring-opacity-50"
value={choice}
/> <span class="ml-2">{choice}</span></label
>
{/each}
</div>
</fieldset>
<div class="flex flex-wrap gap-2">
{#each choices as choice, i}
<label
class:!cursor-not-allowed={disabled}
class="flex items-center text-gray-700 text-sm space-x-2 border py-1.5 px-3 rounded-lg cursor-pointer bg-white shadow-sm checked:shadow-inner"
>
<input
{disabled}
bind:group={value}
type="radio"
name="test"
class="rounded-full border-gray-300 text-blue-600 disabled:text-gray-400 disabled:cursor-not-allowed shadow-sm focus:border-blue-300 focus:ring focus:ring-offset-0 focus:ring-blue-200 focus:ring-opacity-50"
value={choice}
/> <span class="ml-2">{choice}</span></label
>
{/each}
</div>

View File

@ -13,7 +13,6 @@
export let step: number = 1;
export let disabled: boolean = false;
export let label: string;
export let form_position: "first" | "last" | "mid" | "single" = "single";
const id = `range_id_${_id++}`;
@ -22,25 +21,23 @@
$: dispatch("change", value);
</script>
<Block {form_position}>
<div class="w-full flex flex-col">
<div class="flex justify-between">
<label for={id}>
<BlockTitle>{label}</BlockTitle>
</label>
<div class="font-medium">{value}</div>
</div>
<div class="w-full flex flex-col">
<div class="flex justify-between">
<label for={id}>
<BlockTitle>{label}</BlockTitle>
</label>
<div class="font-medium">{value}</div>
</div>
</div>
<input
type="range"
{id}
name="cowbell"
class="w-full disabled:cursor-not-allowed"
bind:value
min={minimum}
max={maximum}
{step}
{disabled}
/>
</Block>
<input
type="range"
{id}
name="cowbell"
class="w-full disabled:cursor-not-allowed"
bind:value
min={minimum}
max={maximum}
{step}
{disabled}
/>

View File

@ -9,10 +9,11 @@
export let style: string = "";
export let disabled = false;
export let autoheight: boolean = false;
export let form_position: "first" | "last" | "mid" | "single" = "single";
const dispatch =
createEventDispatcher<{ change: string; submit: undefined }>();
const dispatch = createEventDispatcher<{
change: string;
submit: undefined;
}>();
function handle_change(val: string) {
dispatch("change", val);
@ -56,31 +57,29 @@
}
</script>
<Block {form_position}>
<!-- svelte-ignore a11y-label-has-associated-control -->
<label class="block">
<BlockTitle>{label}</BlockTitle>
<!-- svelte-ignore a11y-label-has-associated-control -->
<label class="block">
<BlockTitle>{label}</BlockTitle>
{#if autoheight || lines > 1}
<textarea
use:text_area_resize={{ enabled: autoheight, value }}
class="block gr-box gr-input w-full gr-text-input"
bind:value
{placeholder}
{style}
rows={lines}
{disabled}
/>
{:else}
<input
type="text"
class="gr-box gr-input w-full gr-text-input"
{placeholder}
bind:value
on:keypress={handle_keypress}
{style}
{disabled}
/>
{/if}
</label>
</Block>
{#if autoheight || lines > 1}
<textarea
use:text_area_resize={{ enabled: autoheight, value }}
class="block gr-box gr-input w-full gr-text-input"
bind:value
{placeholder}
{style}
rows={lines}
{disabled}
/>
{:else}
<input
type="text"
class="gr-box gr-input w-full gr-text-input"
{placeholder}
bind:value
on:keypress={handle_keypress}
{style}
{disabled}
/>
{/if}
</label>

View File

@ -2,7 +2,6 @@
import { getNextColor } from "./utils";
export let value: Array<[string, string | number]> = [];
export let theme: string = "default";
export let show_legend: boolean = false;
export let color_map: Record<string, string> = {};
export let style: string = "";
@ -69,70 +68,68 @@
/>
-->
<div class="border rounded-lg p-2" {theme}>
{#if mode === "categories"}
{#if show_legend}
<div class="category-legend flex flex-wrap gap-1 mb-2">
{#each Object.entries(color_map) as [category, color], i}
<div
class="category-label px-2 rounded text-white font-semibold"
style={"background-color:" + color}
>
{category}
</div>
{/each}
</div>
{/if}
<div
class="textfield bg-white dark:bg-gray-800 rounded box-border max-w-full break-word inline-flex flex-wrap gap-1"
>
{#each value as [text, category]}
<span
class="textspan bg-opacity-10 rounded inline-flex items-center px-1.5 space-x-1.5"
style={category === null
? ""
: `color: ${color_map[category]}; background-color: ${color_map[
category
].replace("1)", "var(--tw-bg-opacity))")}`}
{#if mode === "categories"}
{#if show_legend}
<div class="category-legend flex flex-wrap gap-1 mb-2">
{#each Object.entries(color_map) as [category, color], i}
<div
class="category-label px-2 rounded text-white font-semibold"
style={"background-color:" + color}
>
<span class="text dark:text-white">{text}</span>
{#if !show_legend && category !== null}
<span
class="inline-category text-xs text-white rounded-sm px-1"
style={category === null
? ""
: `background-color: ${color_map[category]}`}
>
{category}
</span>
{/if}
</span>
{/each}
</div>
{:else}
{#if show_legend}
<div
class="color_legend flex px-2 py-1 justify-between rounded mb-3 font-semibold"
style="background: -webkit-linear-gradient(to right,#8d83d6,(255,255,255,0),#eb4d4b); background: linear-gradient(to right,#8d83d6,rgba(255,255,255,0),#eb4d4b);"
>
<span>-1</span>
<span>0</span>
<span>+1</span>
</div>
{/if}
<div
class="textfield p-2 bg-white dark:bg-gray-800 rounded box-border max-w-full break-word"
>
{#each value as [text, score]}
<span
class="textspan p-1 mr-0.5 bg-opacity-20 dark:bg-opacity-80 rounded-sm"
style={"background-color: rgba(" +
(score < 0 ? "141, 131, 214," + -score : "235, 77, 75," + score) +
")"}
>
<span class="text dark:text-white">{text}</span>
</span>
{category}
</div>
{/each}
</div>
{/if}
</div>
<div
class="textfield bg-white dark:bg-gray-800 rounded box-border max-w-full break-word inline-flex flex-wrap gap-1"
>
{#each value as [text, category]}
<span
class="textspan bg-opacity-10 rounded inline-flex items-center px-1.5 space-x-1.5"
style={category === null
? ""
: `color: ${color_map[category]}; background-color: ${color_map[
category
].replace("1)", "var(--tw-bg-opacity))")}`}
>
<span class="text dark:text-white">{text}</span>
{#if !show_legend && category !== null}
<span
class="inline-category text-xs text-white rounded-sm px-1"
style={category === null
? ""
: `background-color: ${color_map[category]}`}
>
{category}
</span>
{/if}
</span>
{/each}
</div>
{:else}
{#if show_legend}
<div
class="color_legend flex px-2 py-1 justify-between rounded mb-3 font-semibold"
style="background: -webkit-linear-gradient(to right,#8d83d6,(255,255,255,0),#eb4d4b); background: linear-gradient(to right,#8d83d6,rgba(255,255,255,0),#eb4d4b);"
>
<span>-1</span>
<span>0</span>
<span>+1</span>
</div>
{/if}
<div
class="textfield p-2 bg-white dark:bg-gray-800 rounded box-border max-w-full break-word"
>
{#each value as [text, score]}
<span
class="textspan p-1 mr-0.5 bg-opacity-20 dark:bg-opacity-80 rounded-sm"
style={"background-color: rgba(" +
(score < 0 ? "141, 131, 214," + -score : "235, 77, 75," + score) +
")"}
>
<span class="text dark:text-white">{text}</span>
</span>
{/each}
</div>
{/if}

View File

@ -45,69 +45,66 @@
change: string | null;
edit: undefined;
clear: undefined;
drag: boolean;
}>();
$: dispatch("change", value);
let dragging = false;
$: dispatch("drag", dragging);
</script>
<Block
variant={value === null && source === "upload" ? "dashed" : "solid"}
color={dragging ? "green" : "grey"}
padding={false}
>
<BlockLabel
image={source === "canvas" ? sketch_icon : image_icon}
label={label || (source === "canvas" ? "Sketch" : "Image")}
/>
<BlockLabel
image={source === "canvas" ? sketch_icon : image_icon}
label={label || (source === "canvas" ? "Sketch" : "Image")}
/>
<div class:bg-gray-200={value} class:h-60={source !== "webcam"}>
{#if source === "canvas"}
<ModifySketch
on:undo={() => sketch.undo()}
on:clear={() => sketch.clear()}
/>
<Sketch {value} bind:this={sketch} on:change={handle_save} />
{:else if value === null}
{#if source === "upload"}
<Upload
bind:dragging
filetype="image/x-png,image/gif,image/jpeg"
on:load={handle_upload}
include_file_metadata={false}
>
<div class="flex flex-col">
{drop_text}
<span class="text-gray-300">- {or_text} -</span>
{upload_text}
</div>
</Upload>
{:else if source === "webcam"}
<Webcam on:capture={handle_save} />
{/if}
{:else if tool === "select"}
<Cropper image={value} on:crop={handle_save} />
{:else if tool === "editor"}
{#if mode === "edit"}
<ImageEditor
{value}
on:cancel={() => (mode = "view")}
on:save={handle_save}
/>
{/if}
<ModifyUpload
on:edit={() => (mode = "edit")}
on:clear={handle_clear}
editable
/>
<img class="w-full h-full object-contain" src={value} alt="" />
{:else}
<img class="w-full h-full object-contain" src={value} alt="" />
<div class:bg-gray-200={value} class:h-60={source !== "webcam"}>
{#if source === "canvas"}
<ModifySketch
on:undo={() => sketch.undo()}
on:clear={() => sketch.clear()}
/>
<Sketch {value} bind:this={sketch} on:change={handle_save} />
{:else if value === null}
{#if source === "upload"}
<Upload
bind:dragging
filetype="image/x-png,image/gif,image/jpeg"
on:load={handle_upload}
include_file_metadata={false}
>
<div class="flex flex-col">
{drop_text}
<span class="text-gray-300">- {or_text} -</span>
{upload_text}
</div>
</Upload>
{:else if source === "webcam"}
<Webcam on:capture={handle_save} />
{/if}
</div>
</Block>
{:else if tool === "select"}
<Cropper image={value} on:crop={handle_save} />
{:else if tool === "editor"}
{#if mode === "edit"}
<ImageEditor
{value}
on:cancel={() => (mode = "view")}
on:save={handle_save}
/>
{/if}
<ModifyUpload
on:edit={() => (mode = "edit")}
on:clear={handle_clear}
editable
/>
<img class="w-full h-full object-contain" src={value} alt="" />
{:else}
<img class="w-full h-full object-contain" src={value} alt="" />
{/if}
</div>
<style lang="postcss">
:global(.image_editor_buttons) {

View File

@ -15,13 +15,11 @@
$: value && dispatch("change", value);
</script>
<Block variant={"solid"} color={"grey"} padding={false}>
<BlockLabel image={image_icon} label={label || "Image"} />
{#if value === null}
<div class="min-h-[16rem] flex justify-center items-center">
<img src={image_icon} alt="" class="h-6 opacity-20" />
</div>
{:else}
<img class="w-full h-full object-contain" src={value} alt="" />
{/if}
</Block>
<BlockLabel image={image_icon} label={label || "Image"} />
{#if value === null}
<div class="min-h-[16rem] flex justify-center items-center">
<img src={image_icon} alt="" class="h-6 opacity-20" />
</div>
{:else}
<img class="w-full h-full object-contain" src={value} alt="" />
{/if}

View File

@ -5,14 +5,10 @@
export let style: string = "";
</script>
<div
class="relative overflow-hidden output-json font-mono leading-relaxed w-full border py-2 px-2.5 rounded-lg"
<button
class="font-sans absolute right-0 top-0 py-1 px-2 rounded-bl-lg shadow-sm text-xs text-gray-500 flex items-center pointer-events-none bg-white z-20 border-l border-b border-gray-100"
>
<button
class="font-sans absolute right-0 top-0 py-1 px-2 rounded-bl-lg shadow-sm text-xs text-gray-500 flex items-center pointer-events-none bg-white z-20 border-l border-b border-gray-100"
>
copy to clipboard
</button>
copy to clipboard
</button>
<JSONNode {value} depth={0} />
</div>
<JSONNode {value} depth={0} />

View File

@ -4,7 +4,7 @@
export let collapsed = depth > 4;
</script>
<div class="json-node inline text-sm font-mono leading-tight">
<div class="json-node inline text-sm font-mono leading-tight ">
{#if value instanceof Array}
{#if collapsed}
<button

View File

@ -64,12 +64,4 @@
}
</script>
<div
class="output-model w-full h-60 flex justify-center items-center bg-gray-200 dark:bg-gray-600 relative"
{theme}
>
<canvas class="w-full h-full object-contain" bind:this={canvas} />
</div>
<style lang="postcss">
</style>
<canvas class="w-full h-full object-contain" bind:this={canvas} />

View File

@ -2,7 +2,7 @@
import { createEventDispatcher, tick, afterUpdate } from "svelte";
import { Upload, ModifyUpload } from "@gradio/upload";
import type { FileData } from "@gradio/upload";
import { Block, BlockLabel } from "@gradio/atoms";
import { BlockLabel } from "@gradio/atoms";
import file_icon from "./file.svg";
@ -33,8 +33,11 @@
dispatch("clear");
}
const dispatch =
createEventDispatcher<{ change: FileData | null; clear: undefined }>();
const dispatch = createEventDispatcher<{
change: FileData | null;
clear: undefined;
drag: boolean;
}>();
let dragging = false;
@ -81,27 +84,23 @@
"." + value.name.split(".")[1]
);
}
$: dispatch("drag", dragging);
</script>
<Block
variant={value === null ? "dashed" : "solid"}
color={dragging ? "green" : "grey"}
padding={false}
>
<BlockLabel image={file_icon} label={label || "3D Model File"} />
<BlockLabel image={file_icon} label={label || "3D Model"} />
{#if value === null}
<Upload on:load={handle_upload} filetype=".obj, .gltf, .glb" bind:dragging>
{drop_text}
<br />- {or_text} -<br />
{upload_text}
</Upload>
{:else}
<ModifyUpload on:clear={handle_clear} absolute />
<div
class="input-model w-full h-60 flex justify-center items-center bg-gray-200 dark:bg-gray-600 relative"
>
<canvas class="w-full h-full object-contain" bind:this={canvas} />
</div>
{/if}
</Block>
{#if value === null}
<Upload on:load={handle_upload} filetype=".obj, .gltf, .glb" bind:dragging>
{drop_text}
<br />- {or_text} -<br />
{upload_text}
</Upload>
{:else}
<ModifyUpload on:clear={handle_clear} absolute />
<div
class="input-model w-full h-60 flex justify-center items-center bg-gray-200 dark:bg-gray-600 relative"
>
<canvas class="w-full h-full object-contain" bind:this={canvas} />
</div>
{/if}

View File

@ -70,6 +70,3 @@
<img class="w-full h-full object-contain" src={value["plot"]} />
</div>
{/if}
<style lang="postcss">
</style>

View File

@ -1,5 +1,5 @@
<script lang="ts">
import { createEventDispatcher } from "svelte";
import { createEventDispatcher, tick } from "svelte";
import { Upload, ModifyUpload } from "@gradio/upload";
import type { FileData } from "@gradio/upload";
import { Block, BlockLabel } from "@gradio/atoms";
@ -23,6 +23,7 @@
play: undefined;
pause: undefined;
ended: undefined;
drag: boolean;
}>();
function handle_load({ detail }: CustomEvent<FileData | null>) {
@ -31,54 +32,50 @@
}
function handle_clear({ detail }: CustomEvent<FileData | null>) {
dispatch("clear");
value = null;
dispatch("change", detail);
dispatch("clear");
}
let dragging = false;
$: dispatch("drag", dragging);
</script>
<Block
variant={value === null && source === "upload" ? "dashed" : "solid"}
color={dragging ? "green" : "grey"}
padding={false}
>
<BlockLabel image={video_icon} label={label || "Video"} />
{#if value === null}
{#if source === "upload"}
<Upload
bind:dragging
filetype="video/mp4,video/x-m4v,video/*"
on:load={handle_load}
>
<div class="flex flex-col">
{drop_text}
<span class="text-gray-300">- {or_text} -</span>
{upload_text}
</div>
</Upload>
{:else if source === "webcam"}
<Webcam mode="video" on:capture={({ detail }) => (value = detail)} />
{/if}
{:else}
<ModifyUpload on:clear={handle_clear} />
{#if playable(value.name)}
<!-- svelte-ignore a11y-media-has-caption -->
<video
class="w-full h-full object-contain bg-black"
controls
playsInline
preload="auto"
src={value.data}
on:play
on:pause
on:ended
/>
{:else if value.size}
<div class="file-name text-4xl p-6 break-all">{value.name}</div>
<div class="file-size text-2xl p-2">
{prettyBytes(value.size)}
<BlockLabel image={video_icon} label={label || "Video"} />
{#if value === null}
{#if source === "upload"}
<Upload
bind:dragging
filetype="video/mp4,video/x-m4v,video/*"
on:load={handle_load}
>
<div class="flex flex-col">
{drop_text}
<span class="text-gray-300">- {or_text} -</span>
{upload_text}
</div>
{/if}
</Upload>
{:else if source === "webcam"}
<Webcam mode="video" on:capture={({ detail }) => (value = detail)} />
{/if}
</Block>
{:else}
<ModifyUpload on:clear={handle_clear} />
{#if playable(value.name)}
<!-- svelte-ignore a11y-media-has-caption -->
<video
class="w-full h-full object-contain bg-black"
controls
playsInline
preload="auto"
src={value.data}
on:play
on:pause
on:ended
/>
{:else if value.size}
<div class="file-name text-4xl p-6 break-all">{value.name}</div>
<div class="file-size text-2xl p-2">
{prettyBytes(value.size)}
</div>
{/if}
{/if}

View File

@ -10,11 +10,10 @@
},
"devDependencies": {
"@sveltejs/adapter-auto": "next",
"@sveltejs/kit": "next",
"@sveltejs/kit": "^1.0.0-next.318",
"autoprefixer": "^10.4.2",
"postcss": "^8.4.5",
"postcss-load-config": "^3.1.1",
"svelte": "^3.44.0",
"svelte-check": "^2.2.6",
"svelte-preprocess": "^4.10.1",
"tailwindcss": "^3.0.12",
@ -37,12 +36,12 @@
"@gradio/json": "workspace:^0.0.1",
"@gradio/label": "workspace:^0.0.1",
"@gradio/markdown": "workspace:^0.0.1",
"@gradio/model3D": "workspace:^0.0.1",
"@gradio/plot": "workspace:^0.0.1",
"@gradio/table": "workspace:^0.0.1",
"@gradio/tabs": "workspace:^0.0.1",
"@gradio/theme": "workspace:^0.0.1",
"@gradio/upload": "workspace:^0.0.1",
"@gradio/video": "workspace:^0.0.1",
"@gradio/model3D": "workspace:^0.0.1",
"@gradio/plot": "workspace:^0.0.1"
"@gradio/video": "workspace:^0.0.1"
}
}

219
ui/pnpm-lock.yaml generated
View File

@ -6,7 +6,7 @@ importers:
specifiers:
'@gradio/tootils': workspace:^0.0.1
'@playwright/test': ^1.20.0
'@sveltejs/vite-plugin-svelte': ^1.0.0-next.36
'@sveltejs/vite-plugin-svelte': ^1.0.0-next.41
'@tailwindcss/forms': ^0.5.0
'@testing-library/dom': ^8.11.3
'@testing-library/svelte': ^3.1.0
@ -21,25 +21,25 @@ importers:
polka: ^1.0.0-next.22
postcss: ^8.4.5
postcss-nested: ^5.0.6
prettier: ^2.5.1
prettier-plugin-svelte: ^2.6.0
prettier: ^2.6.2
prettier-plugin-svelte: ^2.7.0
sirv: ^2.0.2
sirv-cli: ^2.0.2
svelte: ^3.46.3
svelte-check: ^2.4.1
svelte: ^3.47.0
svelte-check: ^2.7.0
svelte-i18n: ^3.3.13
svelte-preprocess: ^4.10.1
svelte-preprocess: ^4.10.6
tailwindcss: ^3.0.23
tinyspy: ^0.3.0
vite: ^2.9.1
vitest: ^0.3.2
vite: ^2.9.5
vitest: ^0.10.0
dependencies:
'@gradio/tootils': link:packages/tootils
'@playwright/test': 1.20.0
'@sveltejs/vite-plugin-svelte': 1.0.0-next.36_svelte@3.46.3+vite@2.9.1
'@sveltejs/vite-plugin-svelte': 1.0.0-next.41_svelte@3.47.0+vite@2.9.5
'@tailwindcss/forms': 0.5.0_tailwindcss@3.0.23
'@testing-library/dom': 8.11.3
'@testing-library/svelte': 3.1.0_svelte@3.46.3
'@testing-library/svelte': 3.1.0_svelte@3.47.0
'@testing-library/user-event': 13.5.0_@testing-library+dom@8.11.3
autoprefixer: 10.4.4_postcss@8.4.6
babylonjs: 4.2.2
@ -50,18 +50,18 @@ importers:
polka: 1.0.0-next.22
postcss: 8.4.6
postcss-nested: 5.0.6_postcss@8.4.6
prettier: 2.5.1
prettier-plugin-svelte: 2.6.0_prettier@2.5.1+svelte@3.46.3
prettier: 2.6.2
prettier-plugin-svelte: 2.7.0_prettier@2.6.2+svelte@3.47.0
sirv: 2.0.2
sirv-cli: 2.0.2
svelte: 3.46.3
svelte-check: 2.4.1_postcss@8.4.6+svelte@3.46.3
svelte-i18n: 3.3.13_svelte@3.46.3
svelte-preprocess: 4.10.2_postcss@8.4.6+svelte@3.46.3
svelte: 3.47.0
svelte-check: 2.7.0_postcss@8.4.6+svelte@3.47.0
svelte-i18n: 3.3.13_svelte@3.47.0
svelte-preprocess: 4.10.6_postcss@8.4.6+svelte@3.47.0
tailwindcss: 3.0.23_autoprefixer@10.4.4
tinyspy: 0.3.0
vite: 2.9.1
vitest: 0.3.6_happy-dom@2.49.0
vite: 2.9.5
vitest: 0.10.0_happy-dom@2.49.0
devDependencies:
'@types/three': 0.138.0
@ -113,7 +113,7 @@ importers:
'@gradio/upload': link:../upload
'@gradio/video': link:../video
mime-types: 2.1.34
svelte-i18n: 3.3.13_svelte@3.46.3
svelte-i18n: 3.3.13_svelte@3.47.0
packages/atoms:
specifiers: {}
@ -274,11 +274,10 @@ importers:
'@gradio/upload': workspace:^0.0.1
'@gradio/video': workspace:^0.0.1
'@sveltejs/adapter-auto': next
'@sveltejs/kit': next
'@sveltejs/kit': ^1.0.0-next.318
autoprefixer: ^10.4.2
postcss: ^8.4.5
postcss-load-config: ^3.1.1
svelte: ^3.44.0
svelte-check: ^2.2.6
svelte-preprocess: ^4.10.1
tailwindcss: ^3.0.12
@ -307,14 +306,13 @@ importers:
'@gradio/upload': link:../upload
'@gradio/video': link:../video
devDependencies:
'@sveltejs/adapter-auto': 1.0.0-next.34
'@sveltejs/kit': 1.0.0-next.315_svelte@3.46.3
'@sveltejs/adapter-auto': 1.0.0-next.36
'@sveltejs/kit': 1.0.0-next.318_svelte@3.47.0
autoprefixer: 10.4.2_postcss@8.4.6
postcss: 8.4.6
postcss-load-config: 3.1.1
svelte: 3.46.3
svelte-check: 2.4.1_d5eca2c0d9133f686108b018fa7bac55
svelte-preprocess: 4.10.2_8ad9ba7d678a7e4906317692d003ce22
svelte-check: 2.4.1_1fac02bafd0682bb46b2470c9627a189
svelte-preprocess: 4.10.2_7ea8a6d5efea3309cd53b5ce515684ac
tailwindcss: 3.0.23_autoprefixer@10.4.2
tslib: 2.3.1
typescript: 4.5.5
@ -999,53 +997,53 @@ packages:
resolution: {integrity: sha512-a5Sab1C4/icpTZVzZc5Ghpz88yQtGOyNqYXcZgOssB2uuAr+wF/MvN6bgtW32q7HHrvBki+BsZ0OuNv6EV3K9g==}
dev: false
/@rollup/pluginutils/4.1.2:
resolution: {integrity: sha512-ROn4qvkxP9SyPeHaf7uQC/GPFY6L/OWy9+bd9AwcjOAWQwxRscoEyAUD8qCY5o5iL4jqQwoLk2kaTKJPb/HwzQ==}
/@rollup/pluginutils/4.2.1:
resolution: {integrity: sha512-iKnFXr7NkdZAIHiIWE+BX5ULi/ucVFYWD6TbAV+rZctiRTY2PL6tsIKhoIOaoskiWAkgu+VsbXgUVDNLHf+InQ==}
engines: {node: '>= 8.0.0'}
dependencies:
estree-walker: 2.0.2
picomatch: 2.3.1
/@sveltejs/adapter-auto/1.0.0-next.34:
resolution: {integrity: sha512-BzZVfy39idFojauroLrE/v9paJ1/HOlS2R857ooCwaLg+RrRy6zJHWwYxNSv5e8AaZiVg7ioZZpU/2g6ZgUpaQ==}
/@sveltejs/adapter-auto/1.0.0-next.36:
resolution: {integrity: sha512-BCvSlz77Mz38K2sQUQ3YcudxJsOZprOmIW05rzPf5KrqidWa5CvPH2PdQ7XKX7CYgcZHqWioyYt8oxdXBCIulA==}
dependencies:
'@sveltejs/adapter-cloudflare': 1.0.0-next.17
'@sveltejs/adapter-netlify': 1.0.0-next.51
'@sveltejs/adapter-vercel': 1.0.0-next.47
'@sveltejs/adapter-cloudflare': 1.0.0-next.18
'@sveltejs/adapter-netlify': 1.0.0-next.53
'@sveltejs/adapter-vercel': 1.0.0-next.49
dev: true
/@sveltejs/adapter-cloudflare/1.0.0-next.17:
resolution: {integrity: sha512-B2ze5L0LsHFsZctVNy4sw0XxgV2YiVEHyMrWRo3pmpTwpu6GT5V3U2fsEoCMg/RKMazlWkyKTCuUqmcpYjjf2g==}
/@sveltejs/adapter-cloudflare/1.0.0-next.18:
resolution: {integrity: sha512-iIb7ScN2hnnfVQPhRjw0FYpovYJrw4n22BFAQIg6QvOwmmGz1E3QkyBkm/tRmyY7emDfnljgXtvk4Hsoszp5Ug==}
dependencies:
esbuild: 0.14.31
worktop: 0.8.0-next.12
dev: true
/@sveltejs/adapter-netlify/1.0.0-next.51:
resolution: {integrity: sha512-P7/cW/0z8zd8J6DOI2yxKZG0+HRMMuzfOf0yzFXX0vRwBePhKlZ/H4qhTOo2NrCmj3Len545o+ugj5gyMXl1+g==}
/@sveltejs/adapter-netlify/1.0.0-next.53:
resolution: {integrity: sha512-F35KBfdSbR2FXJWliTRj422Y8OAc3syx9vgVPO/bQRuqSnCpXmgxuUgmPZ73/skv3fS4QStXsXQGTnyV4Xs25A==}
dependencies:
'@iarna/toml': 2.2.5
esbuild: 0.14.31
tiny-glob: 0.2.9
dev: true
/@sveltejs/adapter-vercel/1.0.0-next.47:
resolution: {integrity: sha512-VV3vP8KqL9XOc7xfQLVhXTM5jrTme+r1qJy98u5/dhAhkdjqrGDwAKo/s7MoB3rTYxLb2b8I4QxAaoz2Y2aIBg==}
/@sveltejs/adapter-vercel/1.0.0-next.49:
resolution: {integrity: sha512-Me0Zb10iBv+ySVMc0XgI7rdzwiMmeVHq48iVv3oXORa/et/efJVEknVSVk22q15XRqys7DhoPirf54Mz4jElFQ==}
dependencies:
esbuild: 0.14.31
dev: true
/@sveltejs/kit/1.0.0-next.315_svelte@3.46.3:
resolution: {integrity: sha512-f6ufqd9z6uicOOr1eSIclm4TonwoRtw0kuIYrDatYSZtu/081kZ5r0Vj6sXDI6tFI1kctoRzPtFECXf5zkZvlw==}
/@sveltejs/kit/1.0.0-next.318_svelte@3.47.0:
resolution: {integrity: sha512-/M/XNvEqK71KCGro1xLuiUuklsMPe+G5DiVMs39tpfFIFhH4oCzAt+YBaIZDKORogGz3QDaYc5BV+eFv9E5cyw==}
engines: {node: '>=14.13'}
hasBin: true
peerDependencies:
svelte: ^3.44.0
dependencies:
'@sveltejs/vite-plugin-svelte': 1.0.0-next.36_svelte@3.46.3+vite@2.9.1
'@sveltejs/vite-plugin-svelte': 1.0.0-next.41_svelte@3.47.0+vite@2.9.5
sade: 1.8.1
svelte: 3.46.3
vite: 2.9.1
svelte: 3.47.0
vite: 2.9.5
transitivePeerDependencies:
- diff-match-patch
- less
@ -1054,24 +1052,24 @@ packages:
- supports-color
dev: true
/@sveltejs/vite-plugin-svelte/1.0.0-next.36_svelte@3.46.3+vite@2.9.1:
resolution: {integrity: sha512-X7lTiioTGC3ri5M299fxc2dimuKU7f22zTXcmD+NrF+fO9/b7YNfLeQQwWV7Tvv9REysMlR4G2HQF6+lY62p/Q==}
/@sveltejs/vite-plugin-svelte/1.0.0-next.41_svelte@3.47.0+vite@2.9.5:
resolution: {integrity: sha512-2kZ49mpi/YW1PIPvKaJNSSwIFgmw9QUf1+yaNa4U8yJD6AsfSHXAU3goscWbi1jfWnSg2PhvwAf+bvLCdp2F9g==}
engines: {node: ^14.13.1 || >= 16}
peerDependencies:
diff-match-patch: ^1.0.5
svelte: ^3.44.0
vite: ^2.7.0
vite: ^2.9.0
peerDependenciesMeta:
diff-match-patch:
optional: true
dependencies:
'@rollup/pluginutils': 4.1.2
debug: 4.3.3
'@rollup/pluginutils': 4.2.1
debug: 4.3.4
kleur: 4.1.4
magic-string: 0.25.7
svelte: 3.46.3
svelte-hmr: 0.14.9_svelte@3.46.3
vite: 2.9.1
magic-string: 0.26.1
svelte: 3.47.0
svelte-hmr: 0.14.11_svelte@3.47.0
vite: 2.9.5
transitivePeerDependencies:
- supports-color
@ -1112,14 +1110,14 @@ packages:
pretty-format: 27.5.1
dev: false
/@testing-library/svelte/3.1.0_svelte@3.46.3:
/@testing-library/svelte/3.1.0_svelte@3.47.0:
resolution: {integrity: sha512-xTN6v4xRLQb75GTJn2mrjSUJN4PkhpNZFjwvtdzbOTS6OvxMrkRdm6hFRGauwiFd0LPV7/SqdWbbtMAOC7a+Dg==}
engines: {node: '>= 8'}
peerDependencies:
svelte: 3.x
dependencies:
'@testing-library/dom': 7.31.2
svelte: 3.46.3
svelte: 3.47.0
dev: false
/@testing-library/user-event/13.5.0_@testing-library+dom@8.11.3:
@ -1139,11 +1137,11 @@ packages:
/@types/chai-subset/1.3.3:
resolution: {integrity: sha512-frBecisrNGz+F4T6bcc+NLeolfiojh5FxW2klu669+8BARtyQv2C/GkNW6FUodVe4BroGMP/wER/YDGc7rEllw==}
dependencies:
'@types/chai': 4.3.0
'@types/chai': 4.3.1
dev: false
/@types/chai/4.3.0:
resolution: {integrity: sha512-/ceqdqeRraGolFTcfoXNiqjyQhZzbINDngeoAq9GoHa8PPK1yNzTaxWjA6BFWp5Ua9JpXEMSS4s5i9tS0hOJtw==}
/@types/chai/4.3.1:
resolution: {integrity: sha512-/zPMqDkzSZ8t3VtxOa4KPq7uzzW978M9Tvh+j7GHKuo6k6GTLxPJ4J5gE5cjfJ26pnXst0N5Hax8Sr0T2Mi9zQ==}
dev: false
/@types/concat-stream/1.6.1:
@ -1862,6 +1860,18 @@ packages:
optional: true
dependencies:
ms: 2.1.2
dev: false
/debug/4.3.4:
resolution: {integrity: sha512-PRWFHuSU3eDtQJPvnNY7Jcket1j0t5OuOsFzPPzsekD52Zl8qUfFIPEiswXqIvHWGVHOgX+7G/vCNNhehwxfkQ==}
engines: {node: '>=6.0'}
peerDependencies:
supports-color: '*'
peerDependenciesMeta:
supports-color:
optional: true
dependencies:
ms: 2.1.2
/decompress-response/4.2.1:
resolution: {integrity: sha512-jOSne2qbyE+/r8G1VU+G/82LBs2Fs4LAsTiLSHOCOMZQl2OKZ6i8i4IyHemTe+/yIXOtTcRQMzPcgyhoFlqPkw==}
@ -3032,6 +3042,12 @@ packages:
dependencies:
sourcemap-codec: 1.4.8
/magic-string/0.26.1:
resolution: {integrity: sha512-ndThHmvgtieXe8J/VGPjG+Apu7v7ItcD5mhEIvOscWjPF/ccOiLxHaSuCAS2G+3x4GKsAbT8u7zdyamupui8Tg==}
engines: {node: '>=12'}
dependencies:
sourcemap-codec: 1.4.8
/make-dir/3.1.0:
resolution: {integrity: sha512-g3FeP20LNwhALb/6Cz6Dd4F2ngze0jz7tbzrD2wAV+o9FeNHe4rL+yK2md0J/fiSf1sa1ADhXqi5+oVwOM/eGw==}
engines: {node: '>=8'}
@ -3515,18 +3531,18 @@ packages:
dev: false
optional: true
/prettier-plugin-svelte/2.6.0_prettier@2.5.1+svelte@3.46.3:
resolution: {integrity: sha512-NPSRf6Y5rufRlBleok/pqg4+1FyGsL0zYhkYP6hnueeL1J/uCm3OfOZPsLX4zqD9VAdcXfyEL2PYqGv8ZoOSfA==}
/prettier-plugin-svelte/2.7.0_prettier@2.6.2+svelte@3.47.0:
resolution: {integrity: sha512-fQhhZICprZot2IqEyoiUYLTRdumULGRvw0o4dzl5jt0jfzVWdGqeYW27QTWAeXhoupEZJULmNoH3ueJwUWFLIA==}
peerDependencies:
prettier: ^1.16.4 || ^2.0.0
svelte: ^3.2.0
dependencies:
prettier: 2.5.1
svelte: 3.46.3
prettier: 2.6.2
svelte: 3.47.0
dev: false
/prettier/2.5.1:
resolution: {integrity: sha512-vBZcPRUR5MZJwoyi3ZoyQlc1rXeEck8KgeC9AwwOn+exuxLxq5toTRDTSaVrXHxelDMHy9zlicw8u66yxoSUFg==}
/prettier/2.6.2:
resolution: {integrity: sha512-PkUpF+qoXTqhOeWL9fu7As8LXsIUZ1WYaJiY/a7McAQzxjk82OF0tibkFXVCDImZtWxbvojFjerkiLb0/q8mew==}
engines: {node: '>=10.13.0'}
hasBin: true
dev: false
@ -4099,7 +4115,7 @@ packages:
resolution: {integrity: sha512-ot0WnXS9fgdkgIcePe6RHNk1WA8+muPa6cSjeR3V8K27q9BB1rTE3R1p7Hv0z1ZyAc8s6Vvv8DIyWf681MAt0w==}
engines: {node: '>= 0.4'}
/svelte-check/2.4.1_d5eca2c0d9133f686108b018fa7bac55:
/svelte-check/2.4.1_1fac02bafd0682bb46b2470c9627a189:
resolution: {integrity: sha512-xhf3ShP5rnRwBokrgTBJ/0cO9QIc1DAVu1NWNRTfCDsDBNjGmkS3HgitgUadRuoMKj1+irZR/yHJ+Uqobnkbrw==}
hasBin: true
peerDependencies:
@ -4112,8 +4128,8 @@ packages:
picocolors: 1.0.0
sade: 1.8.1
source-map: 0.7.3
svelte: 3.46.3
svelte-preprocess: 4.10.2_8ad9ba7d678a7e4906317692d003ce22
svelte: 3.47.0
svelte-preprocess: 4.10.2_7ea8a6d5efea3309cd53b5ce515684ac
typescript: 4.5.5
transitivePeerDependencies:
- '@babel/core'
@ -4128,8 +4144,8 @@ packages:
- sugarss
dev: true
/svelte-check/2.4.1_postcss@8.4.6+svelte@3.46.3:
resolution: {integrity: sha512-xhf3ShP5rnRwBokrgTBJ/0cO9QIc1DAVu1NWNRTfCDsDBNjGmkS3HgitgUadRuoMKj1+irZR/yHJ+Uqobnkbrw==}
/svelte-check/2.7.0_postcss@8.4.6+svelte@3.47.0:
resolution: {integrity: sha512-GrvG24j0+i8AOm0k0KyJ6Dqc+TAR2yzB7rtS4nljHStunVxCTr/1KYlv4EsOeoqtHLzeWMOd5D2O6nDdP/yw4A==}
hasBin: true
peerDependencies:
svelte: ^3.24.0
@ -4137,12 +4153,11 @@ packages:
chokidar: 3.5.3
fast-glob: 3.2.11
import-fresh: 3.3.0
minimist: 1.2.5
picocolors: 1.0.0
sade: 1.8.1
source-map: 0.7.3
svelte: 3.46.3
svelte-preprocess: 4.10.2_a2976755b4ca24b5e005a6d2e55b331d
svelte: 3.47.0
svelte-preprocess: 4.10.6_0daff008085ea9eaa2e548676f29671a
typescript: 4.5.5
transitivePeerDependencies:
- '@babel/core'
@ -4157,14 +4172,15 @@ packages:
- sugarss
dev: false
/svelte-hmr/0.14.9_svelte@3.46.3:
resolution: {integrity: sha512-bKE9+4qb4sAnA+TKHiYurUl970rjA0XmlP9TEP7K/ncyWz3m81kA4HOgmlZK/7irGK7gzZlaPDI3cmf8fp/+tg==}
/svelte-hmr/0.14.11_svelte@3.47.0:
resolution: {integrity: sha512-R9CVfX6DXxW1Kn45Jtmx+yUe+sPhrbYSUp7TkzbW0jI5fVPn6lsNG9NEs5dFg5qRhFNAoVdRw5qQDLALNKhwbQ==}
engines: {node: ^12.20 || ^14.13.1 || >= 16}
peerDependencies:
svelte: '>=3.19.0'
dependencies:
svelte: 3.46.3
svelte: 3.47.0
/svelte-i18n/3.3.13_svelte@3.46.3:
/svelte-i18n/3.3.13_svelte@3.47.0:
resolution: {integrity: sha512-RQM+ys4+Y9ztH//tX22H1UL2cniLNmIR+N4xmYygV6QpQ6EyQvloZiENRew8XrVzfvJ8HaE8NU6/yurLkl7z3g==}
engines: {node: '>= 11.15.0'}
hasBin: true
@ -4175,11 +4191,11 @@ packages:
estree-walker: 2.0.2
intl-messageformat: 9.11.4
sade: 1.8.1
svelte: 3.46.3
svelte: 3.47.0
tiny-glob: 0.2.9
dev: false
/svelte-preprocess/4.10.2_8ad9ba7d678a7e4906317692d003ce22:
/svelte-preprocess/4.10.2_7ea8a6d5efea3309cd53b5ce515684ac:
resolution: {integrity: sha512-aPpkCreSo8EL/y8kJSa1trhiX0oyAtTjlNNM7BNjRAsMJ8Yy2LtqHt0zyd4pQPXt+D4PzbO3qTjjio3kwOxDlA==}
engines: {node: '>= 9.11.2'}
requiresBuild: true
@ -4228,12 +4244,12 @@ packages:
postcss-load-config: 3.1.1
sorcery: 0.10.0
strip-indent: 3.0.0
svelte: 3.46.3
svelte: 3.47.0
typescript: 4.5.5
dev: true
/svelte-preprocess/4.10.2_a2976755b4ca24b5e005a6d2e55b331d:
resolution: {integrity: sha512-aPpkCreSo8EL/y8kJSa1trhiX0oyAtTjlNNM7BNjRAsMJ8Yy2LtqHt0zyd4pQPXt+D4PzbO3qTjjio3kwOxDlA==}
/svelte-preprocess/4.10.6_0daff008085ea9eaa2e548676f29671a:
resolution: {integrity: sha512-I2SV1w/AveMvgIQlUF/ZOO3PYVnhxfcpNyGt8pxpUVhPfyfL/CZBkkw/KPfuFix5FJ9TnnNYMhACK3DtSaYVVQ==}
engines: {node: '>= 9.11.2'}
requiresBuild: true
peerDependencies:
@ -4248,7 +4264,7 @@ packages:
stylus: ^0.55.0
sugarss: ^2.0.0
svelte: ^3.23.0
typescript: ^4.5.2
typescript: ^3.9.5 || ^4.0.0
peerDependenciesMeta:
'@babel/core':
optional: true
@ -4280,12 +4296,12 @@ packages:
postcss: 8.4.6
sorcery: 0.10.0
strip-indent: 3.0.0
svelte: 3.46.3
svelte: 3.47.0
typescript: 4.5.5
dev: false
/svelte-preprocess/4.10.2_postcss@8.4.6+svelte@3.46.3:
resolution: {integrity: sha512-aPpkCreSo8EL/y8kJSa1trhiX0oyAtTjlNNM7BNjRAsMJ8Yy2LtqHt0zyd4pQPXt+D4PzbO3qTjjio3kwOxDlA==}
/svelte-preprocess/4.10.6_postcss@8.4.6+svelte@3.47.0:
resolution: {integrity: sha512-I2SV1w/AveMvgIQlUF/ZOO3PYVnhxfcpNyGt8pxpUVhPfyfL/CZBkkw/KPfuFix5FJ9TnnNYMhACK3DtSaYVVQ==}
engines: {node: '>= 9.11.2'}
requiresBuild: true
peerDependencies:
@ -4300,7 +4316,7 @@ packages:
stylus: ^0.55.0
sugarss: ^2.0.0
svelte: ^3.23.0
typescript: ^4.5.2
typescript: ^3.9.5 || ^4.0.0
peerDependenciesMeta:
'@babel/core':
optional: true
@ -4332,16 +4348,17 @@ packages:
postcss: 8.4.6
sorcery: 0.10.0
strip-indent: 3.0.0
svelte: 3.46.3
svelte: 3.47.0
dev: false
/svelte-range-slider-pips/2.0.2:
resolution: {integrity: sha512-VTWHOdwDyWbndGZnI0PQJY9DO7hgQlNubtCcCL6Wlypv5dU4vEsc4A1sX9TWMuvebEe4332SgsQQHzOdZ+guhQ==}
dev: false
/svelte/3.46.3:
resolution: {integrity: sha512-mTOXvv74CVQqJHqoIZDprVfRKVVmYNadXP0VKnOEA54223kLGCr1nMrifS4Zx29qMt/xRB38Eq1D7dDH/fM8fQ==}
/svelte/3.47.0:
resolution: {integrity: sha512-4JaJp3HEoTCGARRWZQIZDUanhYv0iyoHikklVHVLH9xFE9db22g4TDv7CPeNA8HD1JgjXI1vlhR1JZvvhaTu2Q==}
engines: {node: '>= 8'}
dev: false
/symbol-tree/3.2.4:
resolution: {integrity: sha512-9QNk5KwDF+Bvz+PyObkmSYjI5ksVUYtjW7AU22r2NKcfLJcXp96hkDWU3+XndOsUb+AQ9QhfzfCT2O+CNWT5Tw==}
@ -4475,13 +4492,13 @@ packages:
engines: {node: '>=14.0.0'}
dev: false
/tinyspy/0.2.10:
resolution: {integrity: sha512-Qij6rGWCDjWIejxCXXVi6bNgvrYBp3PbqC4cBP/0fD6WHDOHCw09Zd13CsxrDqSR5PFq01WeqDws8t5lz5sH0A==}
/tinyspy/0.3.0:
resolution: {integrity: sha512-c5uFHqtUp74R2DJE3/Efg0mH5xicmgziaQXMm/LvuuZn3RdpADH32aEGDRyCzObXT1DNfwDMqRQ/Drh1MlO12g==}
engines: {node: '>=14.0.0'}
dev: false
/tinyspy/0.3.0:
resolution: {integrity: sha512-c5uFHqtUp74R2DJE3/Efg0mH5xicmgziaQXMm/LvuuZn3RdpADH32aEGDRyCzObXT1DNfwDMqRQ/Drh1MlO12g==}
/tinyspy/0.3.2:
resolution: {integrity: sha512-2+40EP4D3sFYy42UkgkFFB+kiX2Tg3URG/lVvAZFfLxgGpnWl5qQJuBw1gaLttq8UOS+2p3C0WrhJnQigLTT2Q==}
engines: {node: '>=14.0.0'}
dev: false
@ -4639,8 +4656,8 @@ packages:
dev: false
optional: true
/vite/2.9.1:
resolution: {integrity: sha512-vSlsSdOYGcYEJfkQ/NeLXgnRv5zZfpAsdztkIrs7AZHV8RCMZQkwjo4DS5BnrYTqoWqLoUe1Cah4aVO4oNNqCQ==}
/vite/2.9.5:
resolution: {integrity: sha512-dvMN64X2YEQgSXF1lYabKXw3BbN6e+BL67+P3Vy4MacnY+UzT1AfkHiioFSi9+uiDUiaDy7Ax/LQqivk6orilg==}
engines: {node: '>=12.2.0'}
hasBin: true
peerDependencies:
@ -4662,9 +4679,9 @@ packages:
optionalDependencies:
fsevents: 2.3.2
/vitest/0.3.6_happy-dom@2.49.0:
resolution: {integrity: sha512-EzlAmGHDh/sQhzKeqDtEae6nlFM5pJKJefj5P2eUUmg6DcXL2Xj365M7eN29P2tMofzs+qZD/LW+d2wopfNl0g==}
engines: {node: '>=14.14.0'}
/vitest/0.10.0_happy-dom@2.49.0:
resolution: {integrity: sha512-8UXemUg9CA4QYppDTsDV76nH0e1p6C8lV9q+o9i0qMSK9AQ7vA2sjoxtkDP0M+pwNmc3ZGYetBXgSJx0M1D/gg==}
engines: {node: '>=v14.16.0'}
hasBin: true
peerDependencies:
'@vitest/ui': '*'
@ -4681,14 +4698,14 @@ packages:
jsdom:
optional: true
dependencies:
'@types/chai': 4.3.0
'@types/chai': 4.3.1
'@types/chai-subset': 1.3.3
chai: 4.3.6
happy-dom: 2.49.0
local-pkg: 0.4.1
tinypool: 0.1.2
tinyspy: 0.2.10
vite: 2.9.1
tinyspy: 0.3.2
vite: 2.9.5
transitivePeerDependencies:
- less
- sass