pull all components into packages

This commit is contained in:
pngwn 2022-03-02 16:42:43 +00:00
parent 9c00ae8000
commit 0044c243db
100 changed files with 3048 additions and 42 deletions

View File

@ -128,7 +128,7 @@
</button>
{:else}
<button
class="p-2 rounded font-semibold bg-white dark:bg-gray-600 shadow transition hover:shadow-md bg-white dark:bg-gray-800"
class="p-2 rounded font-semibold shadow transition hover:shadow-md bg-white dark:bg-gray-800"
on:click={record}
>
Record

View File

@ -66,7 +66,6 @@
}
onDestroy(() => {
console.log(recorder);
if (recorder && recorder.state !== "inactive") {
recorder.stop();
}

View File

@ -6,8 +6,5 @@
"main": "src/index.ts",
"author": "",
"license": "ISC",
"private": true,
"dependencies": {
"@gradio/upload": "workspace:^0.0.1"
}
"private": true
}

View File

@ -0,0 +1,17 @@
# `@gradio/carousel`
```html
<script>
import { Carousel, CarouselItem } from "@gradio/carousel";
</script>
<Carousel>
<CarouselItem>
<h3>hello</h3>
</CarouselItem>
<CarouselItem>
<img />
</CarouselItem>
</Carousel>
```

View File

@ -0,0 +1,10 @@
{
"name": "@gradio/carousel",
"version": "0.0.1",
"description": "Gradio UI packages",
"type": "module",
"main": "src/index.ts",
"author": "",
"license": "ISC",
"private": true
}

View File

@ -0,0 +1,78 @@
<script context="module">
export const CAROUSEL = {};
</script>
<script lang="ts">
import { setContext } from "svelte";
import { writable } from "svelte/store";
export let theme: string = "default";
const items = writable<Array<number>>([]);
const current = writable<number>();
let id = -1;
setContext(CAROUSEL, {
register: () => {
$items.push(++id);
$items = $items;
return id;
},
unregister: (id: number) => {
const i = $items.findIndex((_id) => _id === id);
$items.slice(i, 1);
$items = $items;
},
current
});
let carousel_index: number = 0;
$: $current = $items[carousel_index] || 0;
const next = () => {
carousel_index = (carousel_index + 1) % $items.length;
};
const prev = () => {
carousel_index = (carousel_index - 1 + $items.length) % $items.length;
};
</script>
<div class="output-carousel flex flex-col gap-2" {theme}>
<slot />
<div class="carousel-control flex gap-4 justify-center items-center my-1">
<button on:click={prev}>
<svg
class="caret h-3 mt-0.5 fill-current"
viewBox="0 0 9.1457395 15.999842"
>
<path
d="M 0.32506616,7.2360106 7.1796187,0.33129769 c 0.4360247,-0.439451 1.1455702,-0.442056 1.5845974,-0.0058 0.4390612,0.435849 0.441666,1.14535901 0.00582,1.58438501 l -6.064985,6.1096644 6.10968,6.0646309 c 0.4390618,0.436026 0.4416664,1.145465 0.00582,1.584526 -0.4358485,0.439239 -1.1453586,0.441843 -1.5845975,0.0058 L 0.33088256,8.8203249 C 0.11135166,8.6022941 0.00105996,8.3161928 7.554975e-6,8.0295489 -0.00104244,7.7427633 0.10735446,7.4556467 0.32524356,7.2361162"
/>
</svg>
</button>
<div
class="carousel_index text-xl text-center font-semibold"
style="min-width: 60px"
>
{carousel_index + 1} / {$items.length}
</div>
<button on:click={next}>
<svg
class="caret h-3 mt-0.5 fill-current"
viewBox="0 0 9.1457395 15.999842"
transform="scale(-1, 1)"
>
<path
d="M 0.32506616,7.2360106 7.1796187,0.33129769 c 0.4360247,-0.439451 1.1455702,-0.442056 1.5845974,-0.0058 0.4390612,0.435849 0.441666,1.14535901 0.00582,1.58438501 l -6.064985,6.1096644 6.10968,6.0646309 c 0.4390618,0.436026 0.4416664,1.145465 0.00582,1.584526 -0.4358485,0.439239 -1.1453586,0.441843 -1.5845975,0.0058 L 0.33088256,8.8203249 C 0.11135166,8.6022941 0.00105996,8.3161928 7.554975e-6,8.0295489 -0.00104244,7.7427633 0.10735446,7.4556467 0.32524356,7.2361162"
/>
</svg>
</button>
</div>
</div>
<style lang="postcss">
</style>

View File

@ -0,0 +1,22 @@
<script lang="ts">
import { onDestroy } from "svelte";
import { getContext } from "svelte";
import { CAROUSEL } from "./Carousel.svelte";
export let label: string | undefined = undefined;
const { register, unregister, current } = getContext(CAROUSEL);
let id = register();
onDestroy(() => unregister(id));
</script>
{#if $current === id}
<div class="component">
{#if label}
<div class="panel-header">{label}</div>
{/if}
<slot />
</div>
{/if}

View File

@ -0,0 +1,2 @@
export { default as Carousel } from "./Carousel.svelte";
export { default as CarouselItem } from "./CarouselItem.svelte";

View File

@ -0,0 +1 @@
# `@gradio/chart`

View File

@ -0,0 +1,16 @@
{
"name": "@gradio/chart",
"version": "0.0.1",
"description": "Gradio UI packages",
"type": "module",
"main": "src/index.ts",
"author": "",
"license": "ISC",
"private": true,
"dependencies": {
"@gradio/tooltip": "workspace:^0.0.1",
"d3-dsv": "^3.0.1",
"d3-scale": "^4.0.2",
"d3-shape": "^3.1.0"
}
}

View File

@ -0,0 +1,162 @@
<script lang="ts">
import { csvParse } from "d3-dsv";
import { scaleLinear } from "d3-scale";
import { line as _line, curveLinear } from "d3-shape";
import { createEventDispatcher, onMount } from "svelte";
import { get_domains, transform_values, get_color } from "./utils";
import { tooltip } from "@gradio/tooltip";
export let value: string | Array<Record<string, string>>;
export let x: string | undefined = undefined;
export let y: Array<string> | undefined = undefined;
const dispatch = createEventDispatcher();
$: ({ x: _x, y: _y } =
typeof value === "string"
? transform_values(csvParse(value) as Array<Record<string, string>>, x, y)
: transform_values(value, x, y));
$: x_domain = get_domains(_x);
$: y_domain = get_domains(_y);
$: scale_x = scaleLinear(x_domain, [0, 600]).nice();
$: scale_y = scaleLinear(y_domain, [350, 0]).nice();
$: x_ticks = scale_x.ticks(8);
$: y_ticks = scale_y.ticks(y_domain[1] < 10 ? y_domain[1] : 8);
let colors: Record<string, string>;
$: colors = _y.reduce(
(acc, next) => ({ ...acc, [next.name]: get_color() }),
{}
);
onMount(() => {
dispatch("process", { x: _x, y: _y });
});
</script>
<div>
<div class="flex justify-center align-items-center text-sm">
{#each _y as { name }}
<div class="mx-2">
<span
class="inline-block w-[10px] h-[10px]"
style="background-color: {colors[name]}"
/>
{name}
</div>
{/each}
</div>
<svg class="w-full" viewBox="-70 -20 700 420">
<g>
{#each x_ticks as tick}
<line
stroke-width="0.5"
x1={scale_x(tick)}
x2={scale_x(tick)}
y1={scale_y(y_ticks[0] < y_domain[0] ? y_ticks[0] : y_domain[0]) + 10}
y2={scale_y(
y_domain[1] > y_ticks[y_ticks.length - 1]
? y_domain[1]
: y_ticks[y_ticks.length - 1]
)}
stroke="#aaa"
/>
<text
class="font-mono text-xs"
text-anchor="middle"
x={scale_x(tick)}
y={scale_y(y_ticks[0]) + 30}
>
{tick}
</text>
{/each}
{#each y_ticks as tick}
<line
stroke-width="0.5"
y1={scale_y(tick)}
y2={scale_y(tick)}
x1={scale_x(x_ticks[0] < x_domain[0] ? x_ticks[0] : x_domain[0]) - 10}
x2={scale_x(
x_domain[1] > x_ticks[x_ticks.length - 1]
? x_domain[1]
: x_ticks[x_ticks.length - 1]
)}
stroke="#aaa"
/>
<text
class="font-mono text-xs"
text-anchor="end"
y={scale_y(tick) + 4}
x={scale_x(x_ticks[0]) - 20}
>
{tick}
</text>
{/each}
{#if y_domain[1] > y_ticks[y_ticks.length - 1]}
<line
stroke-width="0.5"
y1={scale_y(y_domain[1])}
y2={scale_y(y_domain[1])}
x1={scale_x(x_ticks[0])}
x2={scale_x(x_domain[1])}
stroke="#aaa"
/>
<text
class="font-mono text-xs"
text-anchor="end"
y={scale_y(y_domain[1]) + 4}
x={scale_x(x_ticks[0]) - 20}
>
{y_domain[1]}
</text>
{/if}
</g>
{#each _y as { name, values }}
{@const color = colors[name]}
{#each values as { x, y }}
<circle
r="3.5"
cx={scale_x(x)}
cy={scale_y(y)}
stroke-width="1.5"
stroke={color}
fill="none"
/>
{/each}
<path
d={_line().curve(curveLinear)(
values.map(({ x, y }) => [scale_x(x), scale_y(y)])
)}
fill="none"
stroke={color}
stroke-width="3"
/>
{/each}
{#each _y as { name, values }}
{@const color = colors[name]}
{#each values as { x, y }}
<circle
use:tooltip={{ color, text: `(${x}, ${y})` }}
r="7"
cx={scale_x(x)}
cy={scale_y(y)}
stroke="black"
fill="black"
style="cursor: pointer; opacity: 0"
/>
{/each}
{/each}
</svg>
<div class="flex justify-center align-items-center text-sm">
{_x.name}
</div>
</div>

View File

@ -0,0 +1 @@
export { default as Chart } from "./Chart.svelte";

View File

@ -0,0 +1,92 @@
interface XYValue {
x: number;
y: number;
}
interface ObjectValue {
values: XYValue[];
}
export function get_domains(
values: ObjectValue[] | { values: number[] }
): [number, number] {
let _vs: number[];
if (Array.isArray(values)) {
_vs = values.reduce<number[]>((acc, { values }) => {
return [...acc, ...values.map(({ x, y }) => y)];
}, []);
} else {
_vs = values.values;
}
return [Math.min(..._vs), Math.max(..._vs)];
}
interface Row {
name: string;
values: number[];
}
interface RowPoint {
name: string;
values: Array<{ x: number; y: number }>;
}
interface TransformedValues {
x: Row;
y: Array<RowPoint>;
}
export function transform_values(
values: Array<Record<string, string>>,
x?: string,
y?: string[]
) {
const transformed_values = Object.entries(
values[0]
).reduce<TransformedValues>(
(acc, next, i) => {
if ((!x && i === 0) || (x && next[0] === x)) {
acc.x.name = next[0];
} else if (!y || (y && y.includes(next[0]))) {
acc.y.push({ name: next[0], values: [] });
}
return acc;
},
{ x: { name: "", values: [] }, y: [] }
);
for (let i = 0; i < values.length; i++) {
const _a = Object.entries(values[i]);
for (let j = 0; j < _a.length; j++) {
let [name, x] = _a[j];
if (name === transformed_values.x.name) {
transformed_values.x.values.push(parseInt(x, 10));
} else {
transformed_values.y[j - 1].values.push({
y: parseInt(_a[j][1], 10),
x: parseInt(_a[0][1], 10)
});
}
}
}
return transformed_values;
}
let c = 0;
export function get_color(): string {
let default_colors = [
[255, 99, 132],
[54, 162, 235],
[240, 176, 26],
[153, 102, 255],
[75, 192, 192],
[255, 159, 64]
];
if (c >= default_colors.length) c = 0;
const [r, g, b] = default_colors[c++];
return `rgb(${r},${g},${b})`;
}

View File

@ -0,0 +1,11 @@
# `@gradio/button`
```html
<script>
import { Button } from "@gradio/button";
</script>
<button type="primary|secondary" href="string" on:click="{e.detail === href}">
content
</button>
```

View File

@ -0,0 +1,10 @@
{
"name": "@gradio/chatbot",
"version": "0.0.1",
"description": "Gradio UI packages",
"type": "module",
"main": "src/index.ts",
"author": "",
"license": "ISC",
"private": true
}

View File

@ -0,0 +1,33 @@
<script lang="ts">
import { beforeUpdate, afterUpdate } from "svelte";
export let value: Array<[string, string]>;
let div: HTMLDivElement;
let autoscroll: Boolean;
beforeUpdate(() => {
autoscroll =
div && div.offsetHeight + div.scrollTop > div.scrollHeight - 20;
});
afterUpdate(() => {
if (autoscroll) div.scrollTo(0, div.scrollHeight);
});
</script>
<div
class="overflow-y-auto h-64 border border-b-0 rounded-t-lg leading-tight"
bind:this={div}
>
<div class="flex flex-col items-end space-y-4 p-3">
{#each value as message}
<div class="px-3 py-2 rounded-2xl bg-yellow-500 text-white ml-7">
{message[0]}
</div>
<div
class="px-3 py-2 rounded-2xl place-self-start bg-gray-300 dark:bg-gray-850 dark:text-gray-200 mr-7"
>
{message[1]}
</div>
{/each}
</div>
</div>

View File

@ -0,0 +1 @@
export { default as ChatBot } from "./ChatBot.svelte";

View File

@ -0,0 +1,11 @@
# `@gradio/button`
```html
<script>
import { Button } from "@gradio/button";
</script>
<button type="primary|secondary" href="string" on:click="{e.detail === href}">
content
</button>
```

View File

@ -0,0 +1,13 @@
{
"name": "@gradio/file",
"version": "0.0.1",
"description": "Gradio UI packages",
"type": "module",
"main": "src/index.ts",
"author": "",
"license": "ISC",
"private": true,
"dependencies": {
"@gradio/upload": "workspace:^0.0.1"
}
}

View File

@ -0,0 +1,61 @@
<script lang="ts">
import { Upload, ModifyUpload } from "@gradio/upload";
import type { FileData } from "@gradio/upload";
import { prettyBytes } from "./utils";
export let value: null | FileData;
export let theme: string = "default";
export let drop_text: string = "Drop an audio file";
export let or_text: string = "or";
export let upload_text: string = "click to upload";
function handle_upload({ detail }: CustomEvent<FileData>) {
value = detail;
}
function handle_clear({ detail }: CustomEvent<null>) {
value = null;
}
</script>
<div class="input-file" {theme}>
{#if value === null}
<Upload on:load={handle_upload} {theme}>
{drop_text}
<br />- {or_text} -<br />
{upload_text}
</Upload>
{:else}
<div
class="file-preview w-full flex flex-row flex-wrap justify-center items-center relative"
>
<ModifyUpload on:clear={handle_clear} {theme} />
<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="file-size text-2xl p-2">
{prettyBytes(value.size)}
</div>
</div>
{/if}
</div>
<style lang="postcss">
.input-file[theme="default"] .file-preview {
@apply h-60;
}
</style>

View File

@ -0,0 +1 @@
export { default as File } from "./File.svelte";

View File

@ -0,0 +1,10 @@
export const prettyBytes = (bytes: number): string => {
let units = ["B", "KB", "MB", "GB", "PB"];
let i = 0;
while (bytes > 1024) {
bytes /= 1024;
i++;
}
let unit = units[i];
return bytes.toFixed(1) + " " + unit;
};

View File

@ -0,0 +1,11 @@
# `@gradio/button`
```html
<script>
import { Button } from "@gradio/button";
</script>
<button type="primary|secondary" href="string" on:click="{e.detail === href}">
content
</button>
```

View File

@ -1,5 +1,5 @@
{
"name": "~name~",
"name": "@gradio/form",
"version": "0.0.1",
"description": "Gradio UI packages",
"type": "module",

View File

@ -0,0 +1,62 @@
<script lang="ts">
import { createEventDispatcher } from "svelte";
export let value: boolean;
export let theme: string = "default";
const dispatch = createEventDispatcher<{ change: boolean }>();
function handle_change() {
dispatch("change", !value);
value = !value;
}
</script>
<div class="input-checkbox inline-block" {theme} on:click={handle_change}>
<button
class="checkbox-item py-2 px-3 rounded cursor-pointer"
class:selected={value}
>
<div class="checkbox w-4 h-4 bg-white flex items-center justify-center">
<svg class="check opacity-0 h-3 w-4" viewBox="-10 -10 20 20">
<line
x1="-7.5"
y1="0"
x2="-2.5"
y2="5"
stroke="white"
stroke-width="4"
stroke-linecap="round"
/>
<line
x1="-2.5"
y1="5"
x2="7.5"
y2="-7.5"
stroke="white"
stroke-width="4"
stroke-linecap="round"
/>
</svg>
</div>
</button>
</div>
<style lang="postcss">
.selected .check {
@apply opacity-100;
}
.input-checkbox[theme="default"] {
.checkbox-item {
@apply bg-white dark:bg-gray-800 shadow transition hover:shadow-md;
}
.checkbox {
@apply bg-gray-100 dark:bg-gray-400 transition;
}
.checkbox-item.selected {
@apply bg-amber-500 dark:bg-red-600 text-white;
}
.selected .checkbox {
@apply bg-amber-600 dark:bg-red-700;
}
}
</style>

View File

@ -0,0 +1,73 @@
<script lang="ts">
import { createEventDispatcher } from "svelte";
export let value: Array<string>;
export let choices: Array<string>;
export let theme: string = "default";
const dispatch = createEventDispatcher<{ change: Array<string> }>();
const toggleChoice = (choice: string) => {
if (value.includes(choice)) {
value.splice(value.indexOf(choice), 1);
} else {
value.push(choice);
}
dispatch("change", value);
value = value;
};
</script>
<div class="input-checkbox-group flex flex-wrap gap-2" {theme}>
{#each choices as choice, i}
<button
class="checkbox-item py-2 px-3 font-semibold rounded cursor-pointer flex items-center gap-2"
class:selected={value.includes(choice)}
on:click={() => toggleChoice(choice)}
>
<div class="checkbox w-4 h-4 bg-white flex items-center justify-center">
<svg class="check opacity-0 h-3 w-4" viewBox="-10 -10 20 20">
<line
x1="-7.5"
y1="0"
x2="-2.5"
y2="5"
stroke="white"
stroke-width="4"
stroke-linecap="round"
/>
<line
x1="-2.5"
y1="5"
x2="7.5"
y2="-7.5"
stroke="white"
stroke-width="4"
stroke-linecap="round"
/>
</svg>
</div>
{choice}
</button>
{/each}
</div>
<style lang="postcss">
.selected .check {
@apply opacity-100;
}
.input-checkbox-group[theme="default"] {
.checkbox-item {
@apply bg-white dark:bg-gray-800 shadow transition hover:shadow-md;
}
.checkbox {
@apply bg-gray-100 dark:bg-gray-400 transition;
}
.checkbox-item.selected {
@apply bg-amber-500 dark:bg-red-600 text-white;
}
.selected .checkbox {
@apply bg-amber-600 dark:bg-red-700;
}
}
</style>

View File

@ -0,0 +1,55 @@
<script lang="ts">
import { createEventDispatcher } from "svelte";
export let label: string;
export let value: string | undefined = undefined;
export let theme: string = "default";
export let choices: Array<string>;
const dispatch = createEventDispatcher<{ change: string }>();
function handle_change(choice: string) {
dispatch("change", choice);
value = choice;
}
</script>
<div class="input-dropdown group inline-block relative" {theme}>
<button
class="selector py-2 px-3 font-semibold rounded inline-flex items-center"
>
{label}
<svg class="caret ml-2 fill-current h-4 w-4" viewBox="0 0 20 20">
<path
d="M9.293 12.95l.707.707L15.657 8l-1.414-1.414L10 10.828 5.757 6.586 4.343 8z"
/>
</svg>
</button>
<div
class="dropdown-menu-holder absolute hidden group-hover:block pt-1 z-10 bg-none"
>
<ul class="dropdown-menu max-h-80 overflow-y-auto">
{#each choices as choice, i}
<li
class="dropdown-item first:rounded-t transition last:rounded-b py-2 px-3 block whitespace-nowrap cursor-pointer"
on:click={() => handle_change(choice)}
>
{choice}
</li>
{/each}
</ul>
</div>
</div>
<style lang="postcss" global>
.input-dropdown[theme="default"] {
.selector {
@apply bg-white dark:bg-gray-800 shadow transition hover:shadow-md;
}
.dropdown-menu {
@apply shadow;
}
.dropdown-item {
@apply bg-white dark:bg-gray-800 hover:bg-amber-500 dark:hover:bg-red-600 hover:text-gray-50 hover:font-semibold;
}
}
</style>

View File

@ -0,0 +1,38 @@
<script lang="ts">
import { createEventDispatcher } from "svelte";
import { debounce } from "./utils";
export let value: number = 0;
export let theme: string = "default";
const dispatch = createEventDispatcher<{ change: number }>();
function handle_change(n: number) {
dispatch("change", n);
}
const debounced_handle_change = debounce(handle_change, 500);
$: debounced_handle_change(value);
</script>
<input
type="number"
class="input-number w-full rounded box-border p-2 focus:outline-none appearance-none"
bind:value
{theme}
/>
<style lang="postcss" global>
input::-webkit-outer-spin-button,
input::-webkit-inner-spin-button {
-webkit-appearance: none;
margin: 0;
}
input[type="number"] {
-moz-appearance: textfield;
}
.input-number[theme="default"] {
@apply shadow transition hover:shadow-md dark:bg-gray-800;
}
</style>

View File

@ -0,0 +1,47 @@
<script lang="ts">
import { createEventDispatcher } from "svelte";
export let value: string;
export let theme: string = "default";
export let choices: Array<string>;
const dispatch = createEventDispatcher();
function handle_change(choice: string) {
dispatch("change", choice);
value = choice;
}
</script>
<div class="input-radio flex flex-wrap gap-2" {theme}>
{#each choices as choice}
<button
class="radio-item py-2 px-3 font-semibold rounded cursor-pointer flex items-center gap-2"
class:selected={value === choice}
on:click={() => handle_change(choice)}
>
<div class="radio-circle w-4 h-4 rounded-full box-border" />
{choice}
</button>
{/each}
</div>
<style lang="postcss">
.input-radio[theme="default"] {
.radio-item {
@apply bg-white dark:bg-gray-800 shadow transition hover:shadow-md;
}
.radio-circle {
@apply bg-gray-50 dark:bg-gray-400 border-4 border-gray-200 dark:border-gray-600;
}
.radio-item.selected {
@apply bg-amber-500 dark:bg-red-600 text-white shadow;
}
.radio-circle {
@apply w-4 h-4 bg-white transition rounded-full box-border;
}
.selected .radio-circle {
@apply border-amber-600 dark:border-red-700;
}
}
</style>

View File

@ -0,0 +1,50 @@
<script lang="ts">
import { createEventDispatcher } from "svelte";
import { debounce } from "./utils";
export let value: string = "";
export let theme: string = "default";
export let lines: number = 1;
export let placeholder: string = "";
const dispatch = createEventDispatcher<{ change: string }>();
type CustomInputEvent =
| (Event & {
target: EventTarget & HTMLTextAreaElement;
})
| (Event & {
target: EventTarget & HTMLInputElement;
});
function handle_change(event: CustomInputEvent) {
dispatch("change", event?.target?.value);
}
const debounced_handle_change = debounce(handle_change, 500);
</script>
{#if lines > 1}
<textarea
class="input-text w-full rounded box-border p-2 focus:outline-none appearance-none"
{value}
{placeholder}
on:input={debounced_handle_change}
{theme}
/>
{:else}
<input
type="text"
class="input-text w-full rounded box-border p-2 focus:outline-none appearance-none"
{value}
{placeholder}
on:input={debounced_handle_change}
{theme}
/>
{/if}
<style lang="postcss" global>
.input-text[theme="default"] {
@apply shadow transition hover:shadow-md dark:bg-gray-800;
}
</style>

View File

@ -0,0 +1,6 @@
export { default as Checkbox } from "./Checkbox.svelte";
export { default as CheckboxGroup } from "./CheckboxGroup.svelte";
export { default as Dropdown } from "./Dropdown.svelte";
export { default as Number } from "./Number.svelte";
export { default as Radio } from "./Radio.svelte";
export { default as TextBox } from "./Textbox.svelte";

View File

@ -0,0 +1,9 @@
export const debounce = (callback: Function, wait = 250) => {
let timeout: NodeJS.Timeout | null = null;
return (...args: Array<unknown>) => {
const next = () => callback(...args);
if (timeout) clearTimeout(timeout);
timeout = setTimeout(next, wait);
};
};

View File

@ -0,0 +1,11 @@
# `@gradio/button`
```html
<script>
import { Button } from "@gradio/button";
</script>
<button type="primary|secondary" href="string" on:click="{e.detail === href}">
content
</button>
```

View File

@ -0,0 +1,10 @@
{
"name": "@gradio/highlighted-text",
"version": "0.0.1",
"description": "Gradio UI packages",
"type": "module",
"main": "src/index.ts",
"author": "",
"license": "ISC",
"private": true
}

View File

@ -0,0 +1,130 @@
<script lang="ts">
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> = {};
let ctx: CanvasRenderingContext2D;
function name_to_rgba(name: string) {
if (!ctx) {
var canvas = document.createElement("canvas");
ctx = canvas.getContext("2d")!;
}
ctx.fillStyle = name;
ctx.fillRect(0, 0, 1, 1);
const [r, g, b, a] = ctx.getImageData(0, 0, 1, 1).data;
ctx.clearRect(0, 0, 1, 1);
return `rgba(${r}, ${g}, ${b}, ${255 / a})`;
}
let mode: "categories" | "scores";
if (color_map === null) {
color_map = {};
}
if (value.length > 0) {
for (let [_, label] of value) {
if (label !== null) {
if (typeof label === "string") {
mode = "categories";
if (!(label in color_map)) {
let color = getNextColor(Object.keys(color_map).length);
color_map[label] = color;
}
} else {
mode = "scores";
}
}
}
}
function correct_color_map() {
for (const col in color_map) {
const _c = color_map[col].trim();
if (_c.startsWith("rgba")) {
color_map[col] = color_map[col];
} else {
color_map[col] = name_to_rgba(color_map[col]);
}
}
}
</script>
<div class="output-highlightedtext" {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 py-1 rounded text-white font-semibold"
style={"background-color:" + color}
>
{category}
</div>
{/each}
</div>
{/if}
<div
class="textfield p-2 bg-white dark:bg-gray-800 rounded box-border max-w-full leading-8 break-word"
>
{#each value as [text, category], i}
<span
class="textspan p-1 mr-0.5 bg-opacity-20 dark:bg-opacity-80 rounded-sm"
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 ml-0.5 px-0.5 rounded-sm"
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 leading-8 break-word"
>
{#each value as [text, score], i}
<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}
</div>
<style lang="postcss">
.output-highlightedtext[theme="default"] {
.textfield {
@apply shadow;
}
}
</style>

View File

@ -0,0 +1 @@
export { default as HighlightedText } from "./HighlightedText.svelte";

View File

@ -0,0 +1,36 @@
export function randInt(min: number, max: number): number {
return Math.floor(Math.random() * (max - min) + min);
}
export const getNextColor = (index: number, alpha: number = 1): string => {
let default_colors = [
[255, 99, 132],
[54, 162, 235],
[240, 176, 26],
[153, 102, 255],
[75, 192, 192],
[255, 159, 64],
[194, 88, 74],
[44, 102, 219],
[44, 163, 23],
[191, 46, 217],
[160, 162, 162],
[163, 151, 27]
];
if (index < default_colors.length) {
var color_set = default_colors[index];
} else {
var color_set = [randInt(64, 196), randInt(64, 196), randInt(64, 196)];
}
return (
"rgba(" +
color_set[0] +
", " +
color_set[1] +
", " +
color_set[2] +
", " +
alpha +
")"
);
};

View File

@ -0,0 +1,11 @@
# `@gradio/button`
```html
<script>
import { Button } from "@gradio/button";
</script>
<button type="primary|secondary" href="string" on:click="{e.detail === href}">
content
</button>
```

View File

@ -0,0 +1,10 @@
{
"name": "@gradio/html",
"version": "0.0.1",
"description": "Gradio UI packages",
"type": "module",
"main": "src/index.ts",
"author": "",
"license": "ISC",
"private": true
}

View File

@ -0,0 +1,8 @@
<script lang="ts">
export let value: string;
export let theme: string = "default";
</script>
<div class="output-html" {theme}>
{@html value}
</div>

View File

@ -0,0 +1 @@
export { default as HTML } from "./HTML.svelte";

View File

@ -0,0 +1,11 @@
# `@gradio/button`
```html
<script>
import { Button } from "@gradio/button";
</script>
<button type="primary|secondary" href="string" on:click="{e.detail === href}">
content
</button>
```

View File

@ -0,0 +1,17 @@
{
"name": "@gradio/image",
"version": "0.0.1",
"description": "Gradio UI packages",
"type": "module",
"main": "src/index.ts",
"author": "",
"license": "ISC",
"private": true,
"dependencies": {
"@gradio/upload": "workspace:^0.0.1",
"cropperjs": "^1.5.12",
"lazy-brush": "^1.0.1",
"resize-observer-polyfill": "^1.5.1",
"tui-image-editor": "^3.15.2"
}
}

View File

@ -0,0 +1,27 @@
<script lang="ts">
import Cropper from "cropperjs";
import { onMount, createEventDispatcher } from "svelte";
export let image: string;
let el: HTMLImageElement;
const dispatch = createEventDispatcher();
onMount(() => {
const cropper = new Cropper(el, {
autoCropArea: 1,
cropend() {
const image_data = cropper.getCroppedCanvas().toDataURL();
dispatch("crop", image_data);
}
});
dispatch("crop", image);
return () => {
cropper.destroy();
};
});
</script>
<img src={image} bind:this={el} alt="" />

View File

@ -0,0 +1,103 @@
<script lang="ts">
import Cropper from "./Cropper.svelte";
import Sketch from "./Sketch.svelte";
import Webcam from "./Webcam.svelte";
import ModifySketch from "./ModifySketch.svelte";
import ImageEditor from "./ImageEditor.svelte";
import { Upload, ModifyUpload } from "@gradio/upload";
export let value: null | string;
export let theme: string = "default";
export let source: "canvas" | "webcam" | "upload" = "upload";
export let tool: "editor" | "select" = "editor";
export let drop_text: string = "Drop an image file";
export let or_text: string = "or";
export let upload_text: string = "click to upload";
let mode: "edit" | "view" = "view";
let sketch: Sketch;
function handle_upload({ detail }: CustomEvent<string>) {
value = detail;
}
function handle_clear({ detail }: CustomEvent<null>) {
value = null;
}
function handle_save({ detail }: { detail: string }) {
value = detail;
mode = "view";
}
$: console.log(value, source);
</script>
<div class="input-image">
<div
class="image-preview w-full h-60 flex justify-center items-center dark:bg-gray-600 relative"
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
filetype="image/x-png,image/gif,image/jpeg"
on:load={handle_upload}
include_file_metadata={false}
{theme}
>
{drop_text}
<br />- {or_text} -<br />
{upload_text}
</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
{theme}
/>
<img class="w-full h-full object-contain" src={value} alt="" />
{/if}
</div>
</div>
<style lang="postcss">
:global(.image_editor_buttons) {
width: 800px;
@apply flex justify-end gap-1;
}
:global(.image_editor_buttons button) {
@apply px-2 py-1 text-xl bg-black text-white font-semibold rounded-t;
}
:global(.tui-image-editor-header-buttons) {
@apply hidden;
}
:global(.tui-colorpicker-palette-button) {
width: 12px;
height: 12px;
}
</style>

View File

@ -0,0 +1,46 @@
<script lang="ts">
import ImageEditor from "tui-image-editor";
import { createEventDispatcher, onMount } from "svelte";
export let value: string;
let el: HTMLDivElement;
let editor: ImageEditor;
const dispatch = createEventDispatcher();
function create_editor() {
editor = new ImageEditor(el, {
usageStatistics: false,
includeUI: {
loadImage: {
path: value,
name: "Edit Image"
},
menuBarPosition: "left",
uiSize: {
width: "800px",
height: "600px"
}
},
cssMaxWidth: 700,
cssMaxHeight: 500,
selectionStyle: {
cornerSize: 20,
rotatingPointOffset: 70
}
});
}
onMount(create_editor);
</script>
<div
class="fixed w-screen h-screen top-0 left-0 bg-black bg-opacity-50 z-40 flex flex-col justify-center items-center"
>
<div class="image_editor_buttons">
<button on:click={() => dispatch("save", editor.toDataURL())}>Save</button>
<button on:click={() => dispatch("cancel")}>Cancel</button>
</div>
<div bind:this={el} />
</div>

View File

@ -0,0 +1,23 @@
<script lang="ts">
import { createEventDispatcher } from "svelte";
import undo_solid from "./undo-solid.svg";
import clear from "./clear.svg";
const dispatch = createEventDispatcher();
</script>
<div class="z-50 top-0 right-0 justify-end m-1 flex gap-1 absolute">
<button
class="bg-opacity-30 hover:bg-opacity-100 transition p-1.5 bg-amber-500 dark:bg-red-600 rounded shadow w-8 h-8"
on:click={() => dispatch("undo")}
>
<img alt="undo sketch" src={undo_solid} />
</button>
<button
class="clear bg-opacity-30 hover:bg-opacity-100 transition p-1 bg-gray-50 dark:bg-gray-500 rounded shadow w-8 h-8"
on:click={() => dispatch("clear")}
>
<img alt="clear sketch" src={clear} />
</button>
</div>

View File

@ -0,0 +1,365 @@
<script>
import { onMount, onDestroy, createEventDispatcher } from "svelte";
import { LazyBrush } from "lazy-brush/src";
import ResizeObserver from "resize-observer-polyfill";
const dispatch = createEventDispatcher();
export let value;
let mounted;
let brush_radius = 50;
let brush_color = "#444";
let catenary_color = "#aaa";
let background_color = "#FFF";
let canvas_width = 400;
let canvas_height = 400;
$: mounted && !value && clear();
function mid_point(p1, p2) {
return {
x: p1.x + (p2.x - p1.x) / 2,
y: p1.y + (p2.y - p1.y) / 2
};
}
const canvas_types = [
{
name: "interface",
zIndex: 15
},
{
name: "drawing",
zIndex: 11
},
{
name: "temp",
zIndex: 12
}
];
let canvas = {};
let ctx = {};
let points = [];
let lines = [];
let mouse_has_moved = true;
let values_changed = true;
let is_drawing = false;
let is_pressing = false;
let lazy = null;
let chain_length = null;
let canvas_container = null;
let canvas_observer = null;
let save_data = "";
onMount(() => {
Object.keys(canvas).forEach((key) => {
ctx[key] = canvas[key].getContext("2d");
});
lazy = new LazyBrush({
radius: brush_radius / 1.5,
enabled: true,
initialPoint: {
x: window.innerWidth / 2,
y: window.innerHeight / 2
}
});
chain_length = brush_radius;
canvas_observer = new ResizeObserver((entries, observer) =>
handle_canvas_resize(entries, observer)
);
canvas_observer.observe(canvas_container);
loop();
mounted = true;
window.setTimeout(() => {
const initX = window.innerWidth / 2;
const initY = window.innerHeight / 2;
lazy.update({ x: initX - chain_length / 4, y: initY }, { both: true });
lazy.update({ x: initX + chain_length / 4, y: initY }, { both: false });
mouse_has_moved = true;
values_changed = true;
clear();
if (save_data) {
load_save_data(save_data);
}
}, 100);
});
onDestroy(() => {
mounted = false;
canvas_observer.unobserve(canvas_container);
});
export function undo() {
const _lines = lines.slice(0, -1);
clear();
draw_lines({ lines: _lines });
trigger_on_change();
}
let get_save_data = () => {
return JSON.stringify({
lines: lines,
width: canvas_width,
height: canvas_height
});
};
let load_save_data = (save_data) => {
if (typeof save_data !== "string") {
throw new Error("save_data needs to be of type string!");
}
const { lines, width, height } = JSON.parse(save_data);
if (!lines || typeof lines.push !== "function") {
throw new Error("save_data.lines needs to be an array!");
}
clear();
if (width === canvas_width && height === canvas_height) {
draw_lines({
lines
});
} else {
const scaleX = canvas_width / width;
const scaleY = canvas_height / height;
draw_lines({
lines: lines.map((line) => ({
...line,
points: line.points.map((p) => ({
x: p.x * scaleX,
y: p.y * scaleY
})),
brush_radius: line.brush_radius
}))
});
}
};
let draw_lines = ({ lines }) => {
lines.forEach((line) => {
const { points: _points, brush_color, brush_radius } = line;
draw_points({
points: _points,
brush_color,
brush_radius
});
points = _points;
saveLine({ brush_color, brush_radius });
return;
});
};
let handle_draw_start = (e) => {
e.preventDefault();
is_pressing = true;
const { x, y } = get_pointer_pos(e);
if (e.touches && e.touches.length > 0) {
lazy.update({ x, y }, { both: true });
}
handle_pointer_move(x, y);
};
let handle_draw_move = (e) => {
e.preventDefault();
const { x, y } = get_pointer_pos(e);
handle_pointer_move(x, y);
};
let handle_draw_end = (e) => {
e.preventDefault();
handle_draw_move(e);
is_drawing = false;
is_pressing = false;
saveLine();
};
let handle_canvas_resize = (entries) => {
const save_data = get_save_data();
for (const entry of entries) {
const { width, height } = entry.contentRect;
set_canvas_size(canvas.interface, width, height);
set_canvas_size(canvas.drawing, width, height);
set_canvas_size(canvas.temp, width, height);
loop({ once: true });
}
load_save_data(save_data, true);
};
let set_canvas_size = (canvas, width, height) => {
canvas.width = width * 3;
canvas.height = height * 3;
canvas.style.width = width;
canvas.style.height = height;
};
let get_pointer_pos = (e) => {
const rect = canvas.interface.getBoundingClientRect();
let clientX = e.clientX;
let clientY = e.clientY;
if (e.changedTouches && e.changedTouches.length > 0) {
clientX = e.changedTouches[0].clientX;
clientY = e.changedTouches[0].clientY;
}
return {
x: clientX - rect.left,
y: clientY - rect.top
};
};
let handle_pointer_move = (x, y) => {
lazy.update({ x: x * 3, y: y * 3 });
const is_disabled = !lazy.isEnabled();
if ((is_pressing && !is_drawing) || (is_disabled && is_pressing)) {
is_drawing = true;
points.push(lazy.brush.toObject());
}
if (is_drawing) {
points.push(lazy.brush.toObject());
draw_points({
points: points,
brush_color,
brush_radius
});
}
mouse_has_moved = true;
};
let draw_points = ({ points, brush_color, brush_radius }) => {
ctx.temp.lineJoin = "round";
ctx.temp.lineCap = "round";
ctx.temp.strokeStyle = brush_color;
ctx.temp.clearRect(0, 0, ctx.temp.canvas.width, ctx.temp.canvas.height);
ctx.temp.lineWidth = brush_radius;
let p1 = points[0];
let p2 = points[1];
ctx.temp.moveTo(p2.x, p2.y);
ctx.temp.beginPath();
for (var i = 1, len = points.length; i < len; i++) {
var midPoint = mid_point(p1, p2);
ctx.temp.quadraticCurveTo(p1.x, p1.y, midPoint.x, midPoint.y);
p1 = points[i];
p2 = points[i + 1];
}
ctx.temp.lineTo(p1.x, p1.y);
ctx.temp.stroke();
};
let saveLine = () => {
if (points.length < 2) return;
lines.push({
points: [...points],
brush_color: brush_color,
brush_radius
});
points.length = 0;
const width = canvas.temp.width;
const height = canvas.temp.height;
ctx.drawing.drawImage(canvas.temp, 0, 0, width, height);
ctx.temp.clearRect(0, 0, width, height);
trigger_on_change();
};
let trigger_on_change = () => {
dispatch("change", get_image_data());
};
export function clear() {
lines = [];
values_changed = true;
ctx.drawing.clearRect(0, 0, canvas.drawing.width, canvas.drawing.height);
ctx.temp.clearRect(0, 0, canvas.temp.width, canvas.temp.height);
ctx.drawing.fillStyle = "#FFFFFF";
ctx.drawing.fillRect(0, 0, canvas.drawing.width, canvas.drawing.height);
}
let loop = ({ once = false } = {}) => {
if (mouse_has_moved || values_changed) {
const pointer = lazy.getPointerCoordinates();
const brush = lazy.getBrushCoordinates();
draw_interface(ctx.interface, pointer, brush);
mouse_has_moved = false;
values_changed = false;
}
if (!once) {
window.requestAnimationFrame(() => {
loop();
});
}
};
let draw_interface = (ctx, pointer, brush) => {
ctx.clearRect(0, 0, ctx.canvas.width, ctx.canvas.height);
// brush preview
ctx.beginPath();
ctx.fillStyle = brush_color;
ctx.arc(brush.x, brush.y, brush_radius / 2, 0, Math.PI * 2, true);
ctx.fill();
// mouse point dangler
ctx.beginPath();
ctx.fillStyle = catenary_color;
ctx.arc(pointer.x, pointer.y, 4, 0, Math.PI * 2, true);
ctx.fill();
// catenary
if (lazy.isEnabled()) {
ctx.beginPath();
ctx.lineWidth = 2;
ctx.lineCap = "round";
ctx.setLineDash([2, 4]);
ctx.strokeStyle = catenary_color;
ctx.stroke();
}
// tiny brush point dot
ctx.beginPath();
ctx.fillStyle = catenary_color;
ctx.arc(brush.x, brush.y, 2, 0, Math.PI * 2, true);
ctx.fill();
};
export function get_image_data() {
return canvas.drawing.toDataURL("image/png");
}
</script>
<div
class="container"
style="height:100%; width:100%; background-color:{background_color}"
bind:this={canvas_container}
bind:offsetWidth={canvas_width}
bind:offsetHeight={canvas_height}
>
{#each canvas_types as { name, zIndex }}
<canvas
key={name}
style="display:block;position:absolute; z-index:{zIndex}; width: {canvas_width}px; height: {canvas_height}px"
bind:this={canvas[name]}
on:mousedown={name === "interface" ? handle_draw_start : undefined}
on:mousemove={name === "interface" ? handle_draw_move : undefined}
on:mouseup={name === "interface" ? handle_draw_end : undefined}
on:mouseout={name === "interface" ? handle_draw_end : undefined}
on:touchstart={name === "interface" ? handle_draw_start : undefined}
on:touchmove={name === "interface" ? handle_draw_move : undefined}
on:touchend={name === "interface" ? handle_draw_end : undefined}
on:touchcancel={name === "interface" ? handle_draw_end : undefined}
/>
{/each}
</div>
<style>
.container {
display: block;
touch-action: none;
}
</style>

View File

@ -0,0 +1,74 @@
<script lang="ts">
import { createEventDispatcher, onMount } from "svelte";
import camera from "./camera.svg";
let video_source: HTMLVideoElement;
let canvas: HTMLCanvasElement;
const dispatch = createEventDispatcher();
onMount(() => (canvas = document.createElement("canvas")));
async function access_webcam() {
try {
const stream = await navigator.mediaDevices.getUserMedia({
video: true
});
video_source.srcObject = stream;
video_source.play();
} catch (error) {
console.error(error);
}
}
function clearphoto() {
var context = canvas.getContext("2d")!;
context.fillStyle = "#AAA";
context.fillRect(0, 0, canvas.width, canvas.height);
}
function takepicture() {
var context = canvas.getContext("2d")!;
if (video_source.videoWidth && video_source.videoHeight) {
canvas.width = video_source.videoWidth;
canvas.height = video_source.videoHeight;
context.drawImage(
video_source,
0,
0,
video_source.videoWidth,
video_source.videoHeight
);
var data = canvas.toDataURL("image/png");
dispatch("capture", data);
}
}
access_webcam();
</script>
<div class="h-full w-full relative">
<!-- svelte-ignore a11y-media-has-caption -->
<video bind:this={video_source} class=" h-full w-full" />
<button
on:click={takepicture}
style="background-color: #333;"
class="rounded-full w-10 h-10 flex justify-center items-center absolute inset-x-0 bottom-2 m-auto drop-shadow-lg"
>
<img
style="color: white"
src={camera}
alt="take a screenshot"
class="w-2/4 h-2/4"
/>
</button>
</div>
<style lang="postcss" global>
video {
-webkit-transform: scaleX(-1);
transform: scaleX(-1);
}
</style>

View File

@ -0,0 +1 @@
<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="white" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="feather feather-camera"><path d="M23 19a2 2 0 0 1-2 2H3a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h4l2-3h6l2 3h4a2 2 0 0 1 2 2z"></path><circle cx="12" cy="13" r="4"></circle></svg>

After

Width:  |  Height:  |  Size: 349 B

View File

@ -0,0 +1,67 @@
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<!-- Created with Inkscape (http://www.inkscape.org/) -->
<svg
width="5.9403949mm"
height="5.9403949mm"
viewBox="0 0 5.9403949 5.9403949"
version="1.1"
id="svg5"
inkscape:version="1.1 (c68e22c387, 2021-05-23)"
sodipodi:docname="clear.svg"
xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
xmlns="http://www.w3.org/2000/svg"
xmlns:svg="http://www.w3.org/2000/svg">
<sodipodi:namedview
id="namedview7"
pagecolor="#ffffff"
bordercolor="#666666"
borderopacity="1.0"
inkscape:pageshadow="2"
inkscape:pageopacity="0.0"
inkscape:pagecheckerboard="0"
inkscape:document-units="mm"
showgrid="false"
inkscape:zoom="10.925474"
inkscape:cx="4.1188143"
inkscape:cy="15.559965"
inkscape:window-width="1248"
inkscape:window-height="770"
inkscape:window-x="-6"
inkscape:window-y="-6"
inkscape:window-maximized="1"
inkscape:current-layer="layer1" />
<defs
id="defs2" />
<g
inkscape:label="Layer 1"
inkscape:groupmode="layer"
id="layer1"
transform="translate(-115.10942,-119.22353)">
<g
id="g239"
transform="matrix(0.05138986,0.05138986,-0.05138986,0.05138986,117.0869,112.75317)">
<rect
style="fill:#000000;stroke-width:0.295287"
id="rect31"
width="20"
height="80"
x="-111.51107"
y="42.193726"
rx="2.9434128"
ry="2.6448057"
transform="scale(-1,1)" />
<rect
style="fill:#000000;stroke-width:0.295287"
id="rect31-3"
width="20"
height="80"
x="-92.193726"
y="-141.51106"
rx="2.9434128"
ry="2.6448057"
transform="matrix(0,-1,-1,0,0,0)" />
</g>
</g>
</svg>

After

Width:  |  Height:  |  Size: 1.9 KiB

View File

@ -0,0 +1 @@
export { default as Image } from "./Image.svelte";

View File

@ -0,0 +1 @@
<svg aria-hidden="true" focusable="false" data-prefix="fas" data-icon="undo" class="svg-inline--fa fa-undo fa-w-16" role="img" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 512 512"><path fill="currentColor" d="M212.333 224.333H12c-6.627 0-12-5.373-12-12V12C0 5.373 5.373 0 12 0h48c6.627 0 12 5.373 12 12v78.112C117.773 39.279 184.26 7.47 258.175 8.007c136.906.994 246.448 111.623 246.157 248.532C504.041 393.258 393.12 504 256.333 504c-64.089 0-122.496-24.313-166.51-64.215-5.099-4.622-5.334-12.554-.467-17.42l33.967-33.967c4.474-4.474 11.662-4.717 16.401-.525C170.76 415.336 211.58 432 256.333 432c97.268 0 176-78.716 176-176 0-97.267-78.716-176-176-176-58.496 0-110.28 28.476-142.274 72.333h98.274c6.627 0 12 5.373 12 12v48c0 6.627-5.373 12-12 12z"></path></svg>

After

Width:  |  Height:  |  Size: 767 B

View File

@ -0,0 +1,11 @@
# `@gradio/button`
```html
<script>
import { Button } from "@gradio/button";
</script>
<button type="primary|secondary" href="string" on:click="{e.detail === href}">
content
</button>
```

View File

@ -0,0 +1,10 @@
{
"name": "@gradio/json",
"version": "0.0.1",
"description": "Gradio UI packages",
"type": "module",
"main": "src/index.ts",
"author": "",
"license": "ISC",
"private": true
}

View File

@ -0,0 +1,16 @@
<script lang="ts">
import JSONNode from "./JSONNode.svelte";
export let value: any;
export let theme: string = "default";
</script>
<div class="output-json font-mono leading-relaxed" {theme}>
<JSONNode {value} depth={0} {theme} />
</div>
<style lang="postcss" global>
.output-text[theme="default"] {
@apply shadow transition hover:shadow-md dark:bg-gray-800;
}
</style>

View File

@ -0,0 +1,84 @@
<script lang="ts">
export let value: any;
export let theme: string = "default";
export let depth: number;
export let collapsed = depth > 4;
</script>
<div class="json-node inline" {theme}>
{#if value instanceof Array}
{#if collapsed}
<button
on:click={() => {
collapsed = false;
}}
>
[+{value.length} children]
</button>
{:else}
[
<div class="json-children pl-4">
{#each value as node, i}
<div class="json-item">
{i}: <svelte:self value={node} depth={depth + 1} {theme} />
{#if i !== value.length - 1}
,
{/if}
</div>
{/each}
</div>
]
{/if}
{:else if value instanceof Object}
{#if collapsed}
<button
on:click={() => {
collapsed = false;
}}
>
&#123;+{Object.keys(value).length} items&#125;
</button>
{:else}
&#123;
<div class="json-children pl-4">
{#each Object.entries(value) as node, i}
<div class="json-item">
{node[0]}: <svelte:self
value={node[1]}
depth={depth + 1}
key={i}
{theme}
/><!--
-->{#if i !== Object.keys(value).length - 1}<!--
-->,
{/if}
</div>
{/each}
</div>
&#125;
{/if}
{:else if value === null}
<div
class="json-item inline text-gray-500 dark:text-gray-400"
item-type="null"
>
null
</div>
{:else if typeof value === "string"}
<div class="json-item inline text-green-500" item-type="string">
"{value}"
</div>
{:else if typeof value === "boolean"}
<div class="json-item inline text-red-500" item-type="boolean">
{value.toLocaleString()}
</div>
{:else if typeof value === "number"}
<div class="json-item inline text-blue-500" item-type="number">
{value}
</div>
{:else}
<div class="json-item inline" item-type="other">
{value}
</div>
{/if}
</div>

View File

@ -0,0 +1 @@
export { default as JSON } from "./JSON.svelte";

View File

@ -0,0 +1,11 @@
# `@gradio/button`
```html
<script>
import { Button } from "@gradio/button";
</script>
<button type="primary|secondary" href="string" on:click="{e.detail === href}">
content
</button>
```

View File

@ -0,0 +1,10 @@
{
"name": "@gradio/label",
"version": "0.0.1",
"description": "Gradio UI packages",
"type": "module",
"main": "src/index.ts",
"author": "",
"license": "ISC",
"private": true
}

View File

@ -0,0 +1,55 @@
<script lang="ts">
export let value: {
label: string;
confidences?: Array<{ label: string; confidence: number }>;
};
export let theme: string = "default";
</script>
<div class="output-label" {theme}>
<div
class="output-class font-bold text-2xl py-6 px-4 flex-grow flex items-center justify-center"
class:no-confidence={!("confidences" in value)}
>
{value.label}
</div>
{#if value.confidences}
<div class="confidence-intervals flex text-xl">
<div class="labels mr-2" style="maxWidth: 120px">
{#each value.confidences as confidence_set}
<div
class="label overflow-hidden whitespace-nowrap h-7 mb-2 overflow-ellipsis text-right"
title={confidence_set.label}
>
{confidence_set.label}
</div>
{/each}
</div>
<div class="confidences flex flex-grow flex-col items-baseline">
{#each value.confidences as confidence_set, i}
<div
class="confidence flex justify-end items-center overflow-hidden whitespace-nowrap h-7 mb-2 px-1"
style="min-width: calc(
{Math.round(confidence_set.confidence * 100)}% - 12px)"
>
{Math.round(confidence_set.confidence * 100)}%
</div>
{/each}
</div>
</div>
{/if}
</div>
<style lang="postcss">
.output-label[theme="default"] {
.label {
@apply text-base h-7;
}
.confidence {
@apply font-mono box-border border-b-2 border-gray-300 bg-gray-200 dark:bg-gray-500 dark:border-gray-600 text-sm h-7 font-semibold rounded;
}
.confidence:first-child {
@apply bg-amber-500 dark:bg-red-600 border-red-700 text-white;
}
}
</style>

View File

@ -0,0 +1 @@
export { default as Label } from "./Label.svelte";

View File

@ -0,0 +1 @@
# `@gradio/table`

View File

@ -0,0 +1,10 @@
{
"name": "@gradio/table",
"version": "0.0.1",
"description": "Gradio UI packages",
"type": "module",
"main": "src/index.ts",
"author": "",
"license": "ISC",
"private": true
}

View File

@ -0,0 +1,400 @@
<script lang="ts">
import { createEventDispatcher, tick } from "svelte";
export let headers: Array<string> = [];
export let values: Array<Array<string | number>> = [["", "", ""]];
// export let default_data: Array<Array<string | number>> = [];
if ($$props.default) values = $$props.default;
// export let setValue: (val: typeof values) => typeof values;
export let editable = true;
const dispatch = createEventDispatcher<{ change: typeof values }>();
let id = 0;
let editing: boolean | number = false;
let selected: boolean | number = false;
let els: Record<
string,
{ cell: null | HTMLTableCellElement; input: null | HTMLInputElement }
> = {};
type Headers = Array<{ value: string; id: number }>;
function make_headers(_h: Array<string>): Headers {
if (_h.length === 0) {
return values[0].map((_, i) => {
const _id = ++id;
els[_id] = { cell: null, input: null };
return { id: _id, value: JSON.stringify(i + 1) };
});
} else {
return _h.map((h) => {
const _id = ++id;
els[_id] = { cell: null, input: null };
return { id: _id, value: h };
});
}
}
let _headers = make_headers(headers);
let data = values.map((x) =>
x.map((n) => {
const _id = ++id;
els[id] = { input: null, cell: null };
return { value: n, id: _id };
})
) || [
Array(headers.length)
.fill(0)
.map((_) => {
const _id = ++id;
els[id] = { input: null, cell: null };
return { value: "", id: _id };
})
];
$: dispatch(
"change",
data.map((r) => r.map(({ value }) => value))
);
function get_sort_status(
name: string,
sort: number,
direction?: SortDirection
) {
if (!sort) return "none";
if (headers[sort] === name) {
if (direction === "asc") return "ascending";
if (direction === "des") return "descending";
}
}
async function start_edit(id: number) {
if (!editable) return;
editing = id;
await tick();
const { input } = els[id];
input?.focus();
}
function handle_keydown(
event: KeyboardEvent,
i: number,
j: number,
id: number
) {
let is_data;
switch (event.key) {
case "ArrowRight":
if (editing) break;
event.preventDefault();
is_data = data[i][j + 1];
selected = is_data ? is_data.id : selected;
break;
case "ArrowLeft":
if (editing) break;
event.preventDefault();
is_data = data[i][j - 1];
selected = is_data ? is_data.id : selected;
break;
case "ArrowDown":
if (editing) break;
event.preventDefault();
is_data = data[i + 1];
selected = is_data ? is_data[j].id : selected;
break;
case "ArrowUp":
if (editing) break;
event.preventDefault();
is_data = data[i - 1];
selected = is_data ? is_data[j].id : selected;
break;
case "Escape":
if (!editable) break;
event.preventDefault();
editing = false;
break;
case "Enter":
if (!editable) break;
event.preventDefault();
if (editing === id) {
editing = false;
} else {
editing = id;
}
break;
case "Backspace":
if (!editable) break;
if (!editing) {
event.preventDefault();
data[i][j].value = "";
}
break;
case "Delete":
if (!editable) break;
if (!editing) {
event.preventDefault();
data[i][j].value = "";
}
break;
default:
break;
}
}
async function handle_cell_click(id: number) {
editing = false;
selected = id;
}
async function set_focus(id: number | boolean, type: "edit" | "select") {
if (type === "edit" && typeof id == "number") {
await tick();
els[id].input?.focus();
}
if (
type === "edit" &&
typeof id == "boolean" &&
typeof selected === "number"
) {
let cell = els[selected]?.cell;
await tick();
cell?.focus();
}
if (type === "select" && typeof id == "number") {
const { cell } = els[id];
cell?.setAttribute("tabindex", "0");
await tick();
els[id].cell?.focus();
}
}
$: set_focus(editing, "edit");
$: set_focus(selected, "select");
type SortDirection = "asc" | "des";
let sort_direction: SortDirection;
let sort_by: number;
function sort(col: number, dir: SortDirection) {
if (dir === "asc") {
data = data.sort((a, b) => (a[col].value < b[col].value ? -1 : 1));
} else if (dir === "des") {
data = data.sort((a, b) => (a[col].value > b[col].value ? -1 : 1));
}
}
function handle_sort(col: number) {
if (typeof sort_by !== "number" || sort_by !== col) {
sort_direction = "asc";
sort_by = col;
} else {
if (sort_direction === "asc") {
sort_direction = "des";
} else if (sort_direction === "des") {
sort_direction = "asc";
}
}
sort(col, sort_direction);
}
let header_edit: number | boolean;
async function edit_header(_id: number, select?: boolean) {
if (!editable) return;
header_edit = _id;
await tick();
els[_id].input?.focus();
if (select) els[_id].input?.select();
}
function end_header_edit(event: KeyboardEvent) {
if (!editable) return;
switch (event.key) {
case "Escape":
event.preventDefault();
header_edit = false;
break;
case "Enter":
event.preventDefault();
header_edit = false;
}
}
function add_row() {
data.push(
headers.map(() => {
const _id = ++id;
els[_id] = { cell: null, input: null };
return { id: _id, value: "" };
})
);
data = data;
}
async function add_col() {
for (let i = 0; i < data.length; i++) {
const _id = ++id;
els[_id] = { cell: null, input: null };
data[i].push({ id: _id, value: "" });
}
const _id = ++id;
els[_id] = { cell: null, input: null };
_headers.push({ id: _id, value: `Header ${_headers.length + 1}` });
data = data;
_headers = _headers;
await tick();
edit_header(_id, true);
}
const double_click = (
node: HTMLElement,
{ click, dblclick }: { click: Function; dblclick: Function }
) => {
let timer: NodeJS.Timeout | undefined;
function handler(event: MouseEvent) {
if (timer) {
clearTimeout(timer);
timer = undefined;
dblclick(event);
} else {
timer = setTimeout(() => {
click(event);
timer = undefined;
}, 250);
}
}
node.addEventListener("click", handler);
return {
destroy: () => node.removeEventListener("click", handler)
};
};
</script>
<div class="shadow overflow-hidden border-gray-200 rounded-sm relative">
<table
id="grid"
role="grid"
aria-labelledby="title"
class="min-w-full divide-y divide-gray-200 "
>
<thead class="bg-gray-50">
<tr>
{#each _headers as { value, id }, i (id)}
<th
use:double_click={{
click: () => handle_sort(i),
dblclick: () => edit_header(id)
}}
aria-sort={get_sort_status(value, sort_by, sort_direction)}
class="after:absolute after:opacity-0 after:content-['▲'] after:ml-2 after:inset-y-0 after:h-[1.05rem] after:m-auto relative px-6 py-3 text-left text-xs font-medium text-gray-500 uppercase tracking-wider"
class:sorted={sort_by === i}
class:des={sort_by === i && sort_direction === "des"}
>
{#if header_edit === id}
<input
class="bg-transparent inset-y-0 left-6 outline-none absolute p-0 w-3/4 text-xs font-medium text-gray-500 uppercase tracking-wider"
tabindex="-1"
bind:value
bind:this={els[id].input}
on:keydown={end_header_edit}
on:blur={({ currentTarget }) =>
currentTarget.setAttribute("tabindex", "-1")}
/>
{/if}
<span
tabindex="-1"
role="button"
class="min-h-full"
class:opacity-0={header_edit === id}>{value}</span
>
</th>
{/each}
</tr></thead
><tbody class="bg-white divide-y divide-gray-200">
{#each data as row, i (row)}
<tr>
{#each row as { value, id }, j (id)}
<td
tabindex="-1"
class="p-0 whitespace-nowrap display-block outline-none relative "
on:dblclick={() => start_edit(id)}
on:click={() => handle_cell_click(id)}
on:keydown={(e) => handle_keydown(e, i, j, id)}
bind:this={els[id].cell}
on:blur={({ currentTarget }) =>
currentTarget.setAttribute("tabindex", "-1")}
>
<div
class:border-gray-600={selected === id}
class:border-transparent={selected !== id}
class="min-h-[3.3rem] px-5 py-3 border-[0.125rem]"
>
{#if editing === id}
<input
class="outline-none absolute p-0 w-3/4"
tabindex="-1"
bind:value
bind:this={els[id].input}
on:blur={({ currentTarget }) =>
currentTarget.setAttribute("tabindex", "-1")}
/>
{/if}
<span
class=" cursor-default w-full"
class:opacity-0={editing === id}
tabindex="-1"
role="button"
>
{value}
</span>
</div>
</td>
{/each}
</tr>
{/each}
</tbody>
</table>
</div>
{#if editable}
<div class="flex justify-end ">
<button
on:click={add_col}
class="hover:bg-gray-100 dark:hover:bg-gray-600 shadow py-1 px-3 rounded transition focus:outline-none m-2 mr-0"
>New Column</button
>
<button
on:click={add_row}
class="bg-amber-500 hover:bg-amber-400 dark:bg-red-700 dark:hover:bg-red-600 text-white shadow py-1 px-3 rounded transition focus:outline-none m-2 mr-0"
>New Row</button
>
</div>
{/if}
<style>
.sorted::after {
opacity: 1;
}
.des::after {
transform: rotate(180deg) translateY(1.5px);
}
</style>

View File

@ -0,0 +1 @@
export { default as Table } from "./Table.svelte";

View File

@ -6,8 +6,5 @@
"main": "src/index.ts",
"author": "",
"license": "ISC",
"private": true,
"dependencies": {
"@gradio/upload": "workspace:^0.0.1"
}
"private": true
}

View File

@ -0,0 +1,11 @@
# `@gradio/button`
```html
<script>
import { Button } from "@gradio/button";
</script>
<button type="primary|secondary" href="string" on:click="{e.detail === href}">
content
</button>
```

View File

@ -0,0 +1,10 @@
{
"name": "@gradio/tooltip",
"version": "0.0.1",
"description": "Gradio UI packages",
"type": "module",
"main": "src/index.ts",
"author": "",
"license": "ISC",
"private": true
}

View File

@ -0,0 +1,20 @@
<script lang="ts">
export let text: string;
export let x: number;
export let y: number;
export let color: string;
let w: number;
let h: number;
</script>
<div
class="bg-black bg-opacity-80 text-white border-r-2 p-1 absolute text-xs flex items-center justify-center"
bind:offsetWidth={w}
bind:offsetHeight={h}
style="
top: {y - h / 2}px;
left: {x - w - 7}px;"
>
<span class="inline-block w-3 h-3 mr-1" style="background: {color}" />{text}
</div>

View File

@ -0,0 +1 @@
export { tooltip } from "./tooltip";

View File

@ -0,0 +1,49 @@
import Tooltip from "./Tooltip.svelte";
interface ActionArgs {
color: string;
text: string;
}
export function tooltip(
element: HTMLElement | SVGElement,
{ color, text }: ActionArgs
) {
let tooltipComponent: Tooltip;
function mouse_over(event: MouseEvent) {
tooltipComponent = new Tooltip({
props: {
text,
x: event.pageX,
y: event.pageY,
color
},
target: document.body
});
return event;
}
function mouseMove(event: MouseEvent) {
tooltipComponent.$set({
x: event.pageX,
y: event.pageY
});
}
function mouseLeave() {
tooltipComponent.$destroy();
}
const el = element as HTMLElement;
el.addEventListener("mouseover", mouse_over);
el.addEventListener("mouseleave", mouseLeave);
el.addEventListener("mousemove", mouseMove);
return {
destroy() {
el.removeEventListener("mouseover", mouse_over);
el.removeEventListener("mouseleave", mouseLeave);
el.removeEventListener("mousemove", mouseMove);
}
};
}

View File

@ -1,4 +1,5 @@
<script lang="ts">
import type { FileData } from "./types";
import edit from "./edit.svg";
import clear from "./clear.svg";
@ -8,8 +9,7 @@
export let theme: string;
export let absolute = true;
const dispatch =
createEventDispatcher<{ edit: undefined; clear: undefined }>();
const dispatch = createEventDispatcher<{ edit: FileData; clear: null }>();
</script>
<div

View File

@ -1,17 +1,9 @@
<script lang="ts">
import { createEventDispatcher } from "svelte";
interface FileData {
name: string;
size: number;
data: string;
is_example: false;
}
import type { FileData } from "./types";
// export let load: (
// val: Array<string | FileData> | string | FileData | null
// ) => Array<string | FileData> | string | FileData | null;
export let filetype: string | undefined = undefined;
export let theme: string;
export let theme: string = "default";
export let single_file: boolean = true;
export let include_file_metadata = true;
let hidden_upload: HTMLInputElement;

View File

@ -1,2 +1,3 @@
export { default as Upload } from "./Upload.svelte";
export { default as ModifyUpload } from "./ModifyUpload.svelte";
export type { FileData } from "./types";

View File

@ -0,0 +1,6 @@
export interface FileData {
name: string;
size: number;
data: string;
is_example: false;
}

View File

@ -0,0 +1,11 @@
# `@gradio/button`
```html
<script>
import { Button } from "@gradio/button";
</script>
<button type="primary|secondary" href="string" on:click="{e.detail === href}">
content
</button>
```

View File

@ -0,0 +1,13 @@
{
"name": "@gradio/video",
"version": "0.0.1",
"description": "Gradio UI packages",
"type": "module",
"main": "src/index.ts",
"author": "",
"license": "ISC",
"private": true,
"dependencies": {
"@gradio/upload": "workspace:^0.0.1"
}
}

View File

@ -0,0 +1,62 @@
<script lang="ts">
import { createEventDispatcher } from "svelte";
import { Upload, ModifyUpload } from "@gradio/upload";
import type { FileData } from "@gradio/upload";
import { prettyBytes, playable } from "./utils";
export let value: FileData | null = null;
export let theme: string = "default";
export let source: string;
export let drop_text: string = "Drop a video file";
export let or_text: string = "or";
export let upload_text: string = "click to upload";
const dispatch = createEventDispatcher<{ change: FileData | null }>();
function handle_load({ detail }: CustomEvent<FileData | null>) {
dispatch("change", detail);
value = detail;
}
function handle_clear({ detail }: CustomEvent<FileData | null>) {
dispatch("change", null);
value = null;
}
</script>
<div
class="video-preview w-full h-60 object-contain flex justify-center items-center dark:bg-gray-600 relative"
class:bg-gray-200={value}
>
{#if value === null}
{#if source === "upload"}
<Upload
filetype="video/mp4,video/x-m4v,video/*"
on:load={handle_load}
{theme}
>
{drop_text}
<br />- {or_text} -<br />
{upload_text}
</Upload>
{/if}
{:else}
<ModifyUpload on:clear={handle_clear} {theme} />
{#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}
/>
{:else}
<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}
</div>

View File

@ -0,0 +1 @@
export { default as Video } from "./Video.svelte";

View File

@ -0,0 +1,17 @@
export const prettyBytes = (bytes: number): string => {
let units = ["B", "KB", "MB", "GB", "PB"];
let i = 0;
while (bytes > 1024) {
bytes /= 1024;
i++;
}
let unit = units[i];
return bytes.toFixed(1) + " " + unit;
};
export const playable = (filename: string): boolean => {
// let video_element = document.createElement("video");
// let mime_type = mime.lookup(filename);
// return video_element.canPlayType(mime_type) != "";
return true; // FIX BEFORE COMMIT - mime import causing issues
};

View File

@ -25,6 +25,19 @@
"dependencies": {
"@gradio/audio": "workspace:^0.0.1",
"@gradio/button": "workspace:^0.0.1",
"@gradio/theme": "workspace:^0.0.1"
"@gradio/carousel": "workspace:^0.0.1",
"@gradio/chart": "workspace:^0.0.1",
"@gradio/chatbot": "workspace:^0.0.1",
"@gradio/file": "workspace:^0.0.1",
"@gradio/form": "workspace:^0.0.1",
"@gradio/highlighted-text": "workspace:^0.0.1",
"@gradio/html": "workspace:^0.0.1",
"@gradio/image": "workspace:^0.0.1",
"@gradio/json": "workspace:^0.0.1",
"@gradio/label": "workspace:^0.0.1",
"@gradio/table": "workspace:^0.0.1",
"@gradio/theme": "workspace:^0.0.1",
"@gradio/upload": "workspace:^0.0.1",
"@gradio/video": "workspace:^0.0.1"
}
}

Binary file not shown.

After

Width:  |  Height:  |  Size: 20 KiB

View File

@ -0,0 +1,8 @@
time,value,price
1,1,4
2,3,8
3,6,12
4,10,16
5,15,20
6,21,24
7,28,28
1 time value price
2 1 1 4
3 2 3 8
4 3 6 12
5 4 10 16
6 5 15 20
7 6 21 24
8 7 28 28

View File

@ -3,7 +3,6 @@
const comp_routes = [
"Audio",
"Button",
"DataFrame",
"Carousel",
"Chatbot",
"Chart",
@ -14,13 +13,10 @@
"Image",
"JSON",
"Label",
"Markdown",
"Tooltip",
"Table",
"Upload",
"Video"
].map((n) => [n, n.toLowerCase()]);
$: console.log($page.url);
</script>
<nav class="inline-block">

View File

@ -1,6 +1,5 @@
<script lang="ts">
import { Audio } from "@gradio/audio";
import audio from "../assets/cantina.wav";
</script>
<h2>upload input</h2>

View File

@ -0,0 +1,13 @@
<script lang="ts">
import { Carousel, CarouselItem } from "@gradio/carousel";
import cheetah from "../assets/cheetah1.jpg";
</script>
<Carousel>
<CarouselItem>
<h1>hello</h1>
</CarouselItem>
<CarouselItem>
<img src={cheetah} alt="" />
</CarouselItem>
</Carousel>

View File

@ -0,0 +1,14 @@
<script lang="ts">
import { Chart } from "@gradio/chart";
const csv = `time,value,price
1,1,4
2,3,8
3,6,12
4,10,16
5,15,20
6,21,24
7,28,28`;
</script>
<Chart value={csv} />

View File

@ -0,0 +1,14 @@
<script lang="ts">
import { ChatBot } from "@gradio/chatbot";
let messages: Array<[string, string]> = [
["message one", "message two"],
["message three", "message four"]
];
setTimeout(() => {
messages = [...messages, ["message five", "message six"]];
}, 1000);
</script>
<ChatBot value={messages} />

View File

@ -0,0 +1,5 @@
<script lang="ts">
import { File } from "@gradio/file";
</script>
<File value={null} />

View File

@ -0,0 +1,31 @@
<script lang="ts">
import {
Checkbox,
CheckboxGroup,
Dropdown,
Radio,
TextBox,
Number
} from "@gradio/form";
</script>
<h2>TextBox</h2>
<TextBox on:change={({ detail }) => console.log(detail)} />
<h2>TextArea</h2>
<TextBox lines={5} on:change={({ detail }) => console.log(detail)} />
<h2>Number</h2>
<Number on:change={({ detail }) => console.log(detail)} />
<h2>Radio</h2>
<Radio choices={["true", "false"]} value={"true"} />
<h2>CheckBox</h2>
<Checkbox value={false} />
<h2>Checkbox Group</h2>
<CheckboxGroup choices={["one", "two"]} value={[]} />
<h2>Dropdown</h2>
<Dropdown label={"choose"} choices={["one", "two", "three"]} />

View File

@ -0,0 +1,51 @@
<script lang="ts">
import { HighlightedText } from "@gradio/highlighted-text";
</script>
<h2>With legend</h2>
<HighlightedText
show_legend={true}
value={[
["one", "1"],
["two", "2"],
["three", "3"],
["two", "2"],
["three", "3"]
]}
/>
<h2>Without legend</h2>
<HighlightedText
value={[
["one", "1"],
["two", "2"],
["three", "3"],
["two", "2"],
["three", "3"]
]}
/>
<h2>Custom color_map with legend</h2>
<HighlightedText
show_legend={true}
value={[
["one", "+"],
["two", "-"],
["three", "-"],
["two", "+"],
["three", "-"]
]}
color_map={{ "+": "limegreen", "-": "crimson" }}
/>
<h2>Custom color_map without legend</h2>
<HighlightedText
value={[
["one", "+"],
["two", "-"],
["three", "-"],
["two", "+"],
["three", "-"]
]}
color_map={{ "+": "limegreen", "-": "crimson" }}
/>

View File

@ -0,0 +1,7 @@
<script lang="ts">
import { HTML } from "@gradio/html";
const src = `<h1>hello</h1>`;
</script>
<HTML value={src} />

View File

@ -0,0 +1,20 @@
<script lang="ts">
import { browser } from "$app/env";
import { Image } from "@gradio/image";
const src = `<h1>hello</h1>`;
</script>
{#if browser}
<h2>Editor with upload</h2>
<Image value={null} source={"upload"} tool="editor" />
<h2>Editor with webcam</h2>
<Image value={null} source={"webcam"} tool="editor" />
<h2>Editor with sketch</h2>
<Image value={null} source={"canvas"} tool="editor" />
<h2>Cropper with upload</h2>
<Image value={null} source={"upload"} tool="select" />
{/if}

View File

@ -0,0 +1,34 @@
<script lang="ts">
import { JSON } from "@gradio/json";
const json = {
a: 1,
b: "two",
c: [
1,
"two",
[1, 2, 3],
{
a: 1,
b: "two",
c: [1, "two", []]
}
],
d: {
a: 1,
b: "two",
c: [
1,
"two",
[1, 2, 3],
{
a: 1,
b: "two",
c: [1, "two", []]
}
]
}
};
</script>
<JSON value={json} />

View File

@ -0,0 +1,20 @@
<script lang="ts">
import { Label } from "@gradio/label";
const data = {
label: "hello",
confidences: [
{ label: "hello", confidence: 0.8 },
{ label: "helooo", confidence: 0.4 },
{ label: "helloooo", confidence: 0.6 }
]
};
</script>
<h2>Without confidence</h2>
<Label value={{ label: "hello" }} />
<h2>With confidence</h2>
<Label value={data} />

View File

@ -0,0 +1,5 @@
<script lang="ts">
import { Table } from "@gradio/table";
</script>
<Table />

View File

@ -0,0 +1,7 @@
<script lang="ts">
import { Upload } from "@gradio/upload";
</script>
<Upload on:load={({ detail }) => console.log("change", detail)}
>drag or click</Upload
>

View File

@ -0,0 +1,5 @@
<script lang="ts">
import { Video } from "@gradio/video";
</script>
<Video value={null} source={"upload"} />

View File

@ -79,17 +79,113 @@ importers:
dependencies:
'@gradio/upload': link:../upload
packages/carousel:
specifiers:
'@gradio/upload': workspace:^0.0.1
dependencies:
'@gradio/upload': link:../upload
packages/chart:
specifiers:
'@gradio/tooltip': workspace:^0.0.1
d3-dsv: ^3.0.1
d3-scale: ^4.0.2
d3-shape: ^3.1.0
dependencies:
'@gradio/tooltip': link:../tooltip
d3-dsv: 3.0.1
d3-scale: 4.0.2
d3-shape: 3.1.0
packages/chatbot:
specifiers: {}
packages/components:
specifiers: {}
packages/file:
specifiers:
'@gradio/upload': workspace:^0.0.1
dependencies:
'@gradio/upload': link:../upload
packages/form:
specifiers:
'@gradio/upload': workspace:^0.0.1
dependencies:
'@gradio/upload': link:../upload
packages/highlighted-text:
specifiers:
'@gradio/upload': workspace:^0.0.1
dependencies:
'@gradio/upload': link:../upload
packages/html:
specifiers:
'@gradio/upload': workspace:^0.0.1
dependencies:
'@gradio/upload': link:../upload
packages/image:
specifiers:
'@gradio/upload': workspace:^0.0.1
cropperjs: ^1.5.12
lazy-brush: ^1.0.1
resize-observer-polyfill: ^1.5.1
tui-image-editor: ^3.15.2
dependencies:
'@gradio/upload': link:../upload
cropperjs: 1.5.12
lazy-brush: 1.0.1
resize-observer-polyfill: 1.5.1
tui-image-editor: 3.15.2
packages/table:
specifiers:
'@gradio/upload': workspace:^0.0.1
dependencies:
'@gradio/upload': link:../upload
packages/theme:
specifiers:
'@gradio/upload': workspace:^0.0.1
dependencies:
'@gradio/upload': link:../upload
packages/tooltip:
specifiers:
'@gradio/upload': workspace:^0.0.1
dependencies:
'@gradio/upload': link:../upload
packages/upload:
specifiers: {}
packages/video:
specifiers:
'@gradio/upload': workspace:^0.0.1
dependencies:
'@gradio/upload': link:../upload
packages/workbench:
specifiers:
'@gradio/audio': workspace:^0.0.1
'@gradio/button': workspace:^0.0.1
'@gradio/carousel': workspace:^0.0.1
'@gradio/chart': workspace:^0.0.1
'@gradio/chatbot': workspace:^0.0.1
'@gradio/file': workspace:^0.0.1
'@gradio/form': workspace:^0.0.1
'@gradio/highlighted-text': workspace:^0.0.1
'@gradio/html': workspace:^0.0.1
'@gradio/image': workspace:^0.0.1
'@gradio/json': workspace:^0.0.1
'@gradio/label': workspace:^0.0.1
'@gradio/table': workspace:^0.0.1
'@gradio/theme': workspace:^0.0.1
'@gradio/upload': workspace:^0.0.1
'@gradio/video': workspace:^0.0.1
'@sveltejs/adapter-auto': next
'@sveltejs/kit': next
autoprefixer: ^10.4.2
@ -104,10 +200,23 @@ importers:
dependencies:
'@gradio/audio': link:../audio
'@gradio/button': link:../button
'@gradio/carousel': link:../carousel
'@gradio/chart': link:../chart
'@gradio/chatbot': link:../chatbot
'@gradio/file': link:../file
'@gradio/form': link:../form
'@gradio/highlighted-text': link:../highlighted-text
'@gradio/html': link:../html
'@gradio/image': link:../image
'@gradio/json': link:../json
'@gradio/label': link:../label
'@gradio/table': link:../table
'@gradio/theme': link:../theme
'@gradio/upload': link:../upload
'@gradio/video': link:../video
devDependencies:
'@sveltejs/adapter-auto': 1.0.0-next.28
'@sveltejs/kit': 1.0.0-next.286_svelte@3.46.3
'@sveltejs/adapter-auto': 1.0.0-next.30
'@sveltejs/kit': 1.0.0-next.288_svelte@3.46.3
autoprefixer: 10.4.2_postcss@8.4.6
postcss: 8.4.6
postcss-load-config: 3.1.1
@ -221,12 +330,12 @@ packages:
picomatch: 2.3.1
dev: true
/@sveltejs/adapter-auto/1.0.0-next.28:
resolution: {integrity: sha512-MuJUghh7HYXeThS1btsKJFZBN//DM5BmfTXhSBRN3MgKwDMF1XYvadNegZI2nIVzb9RQTh/al3jGKKZfBVHGEg==}
/@sveltejs/adapter-auto/1.0.0-next.30:
resolution: {integrity: sha512-kKKDvv2bwH66l/A97u26973OG3Zh7V1WlTKgkOr95Koo1/Y6rBhBfkz0Jw+WLzsZ+hcTzgIrcegtWVt+GQRJpw==}
dependencies:
'@sveltejs/adapter-cloudflare': 1.0.0-next.14
'@sveltejs/adapter-netlify': 1.0.0-next.47
'@sveltejs/adapter-vercel': 1.0.0-next.44
'@sveltejs/adapter-netlify': 1.0.0-next.49
'@sveltejs/adapter-vercel': 1.0.0-next.45
dev: true
/@sveltejs/adapter-cloudflare/1.0.0-next.14:
@ -235,22 +344,22 @@ packages:
esbuild: 0.14.23
dev: true
/@sveltejs/adapter-netlify/1.0.0-next.47:
resolution: {integrity: sha512-fyJ2UP14ViusPFMtnuXbLRxE9bQ3dQ7Aj5HkAddN4fgV1A15tGWthrSUOH0iozYmOYLu6AWvUxx9o01OhJbfZQ==}
/@sveltejs/adapter-netlify/1.0.0-next.49:
resolution: {integrity: sha512-EYP0/eK1foC90fBNn6V9fP0ngrMF3MrkaNN+wCnMj0rHGKOKUzXlIeyPtGtQnDL9cqHac39pbPhSyMaMuWZF/w==}
dependencies:
'@iarna/toml': 2.2.5
esbuild: 0.14.23
tiny-glob: 0.2.9
dev: true
/@sveltejs/adapter-vercel/1.0.0-next.44:
resolution: {integrity: sha512-q0o7JG0pAam2lkkM5XiaLzYBGSRtOogjXpKYwpc7iiMuaSV4nzsnYlLxwbtib7ZJQzE1D32pPZQuvf5pAIqrmQ==}
/@sveltejs/adapter-vercel/1.0.0-next.45:
resolution: {integrity: sha512-WoOMu4FSWjVeRiPq2NKfdZhobfOLmDykObZmm8JHptMDb0/I5SB+6wstzAeaNtQr2ZbQkUy0k7EX95riJifEEQ==}
dependencies:
esbuild: 0.14.23
dev: true
/@sveltejs/kit/1.0.0-next.286_svelte@3.46.3:
resolution: {integrity: sha512-txWUYKLpZohHPCEYc3oYIByMnZe+d/FItMBiCNJbTLdKaDop+SfCOzBar+K9IgP2MTXSScILSkPOms845uhz0A==}
/@sveltejs/kit/1.0.0-next.288_svelte@3.46.3:
resolution: {integrity: sha512-6ky4CUFNGKoU1QV+fY2LOIB7atHdUCIMRx3pX21B2g9yZzQzkot0zHBrMMBSKF0/4Wx19PLEWrlGxlhakYmi8Q==}
engines: {node: '>=14.13'}
hasBin: true
peerDependencies: