diff --git a/.changeset/itchy-goats-kiss.md b/.changeset/itchy-goats-kiss.md new file mode 100644 index 0000000000..9173c51de4 --- /dev/null +++ b/.changeset/itchy-goats-kiss.md @@ -0,0 +1,21 @@ +--- +"@gradio/annotatedimage": patch +"@gradio/audio": patch +"@gradio/chatbot": patch +"@gradio/code": patch +"@gradio/dataframe": patch +"@gradio/dataset": patch +"@gradio/dropdown": patch +"@gradio/file": patch +"@gradio/imageeditor": patch +"@gradio/markdown": patch +"@gradio/model3d": patch +"@gradio/nativeplot": patch +"@gradio/paramviewer": patch +"@gradio/utils": patch +"@gradio/wasm": patch +"@self/component-test": patch +"gradio": patch +--- + +feat:make all component SSR compatible diff --git a/js/annotatedimage/Index.svelte b/js/annotatedimage/Index.svelte index 456585719a..ec6b381517 100644 --- a/js/annotatedimage/Index.svelte +++ b/js/annotatedimage/Index.svelte @@ -229,7 +229,6 @@ display: block; width: 100%; height: auto; - position: absolute; } .container { display: flex; diff --git a/js/audio/Index.svelte b/js/audio/Index.svelte index 05846ebd08..fde97104bc 100644 --- a/js/audio/Index.svelte +++ b/js/audio/Index.svelte @@ -5,7 +5,7 @@ import type { FileData } from "@gradio/client"; import type { LoadingStatus } from "@gradio/statustracker"; - import { afterUpdate } from "svelte"; + import { afterUpdate, onMount } from "svelte"; import StaticAudio from "./static/StaticAudio.svelte"; import InteractiveAudio from "./interactive/InteractiveAudio.svelte"; @@ -95,14 +95,23 @@ let waveform_settings: Record; - let color_accent = getComputedStyle( - document.documentElement - ).getPropertyValue("--color-accent"); + let color_accent = "darkorange"; + + onMount(() => { + color_accent = getComputedStyle(document?.documentElement).getPropertyValue( + "--color-accent" + ); + set_trim_region_colour(); + waveform_settings.waveColor = waveform_options.waveform_color || "#9ca3af"; + waveform_settings.progressColor = + waveform_options.waveform_progress_color || color_accent; + waveform_settings.mediaControls = waveform_options.show_controls; + waveform_settings.sampleRate = waveform_options.sample_rate || 44100; + }); $: waveform_settings = { height: 50, - waveColor: waveform_options.waveform_color || "#9ca3af", - progressColor: waveform_options.waveform_progress_color || color_accent, + barWidth: 2, barGap: 3, cursorWidth: 2, @@ -111,9 +120,7 @@ barRadius: 10, dragToSeek: true, normalize: true, - minPxPerSec: 20, - mediaControls: waveform_options.show_controls, - sampleRate: waveform_options.sample_rate || 44100 + minPxPerSec: 20 }; const trim_region_settings = { @@ -129,8 +136,6 @@ ); } - set_trim_region_colour(); - function handle_error({ detail }: CustomEvent): void { const [level, status] = detail.includes("Invalid file type") ? ["warning", "complete"] diff --git a/js/audio/player/AudioPlayer.svelte b/js/audio/player/AudioPlayer.svelte index acee42e71f..59cf8b6d45 100644 --- a/js/audio/player/AudioPlayer.svelte +++ b/js/audio/player/AudioPlayer.svelte @@ -168,7 +168,11 @@ data-testid={label ? "waveform-" + label : "unlabelled-audio"} >
-
+
@@ -181,25 +185,25 @@
- {#if waveform} - - {/if} + + +
{/if} diff --git a/js/audio/shared/VolumeControl.svelte b/js/audio/shared/VolumeControl.svelte index 8b4c371e5e..55aa62660c 100644 --- a/js/audio/shared/VolumeControl.svelte +++ b/js/audio/shared/VolumeControl.svelte @@ -4,7 +4,7 @@ export let currentVolume = 1; export let show_volume_slider = false; - export let waveform: WaveSurfer; + export let waveform: WaveSurfer | undefined; let volumeElement: HTMLInputElement; @@ -37,7 +37,7 @@ on:input={(e) => { if (e.target instanceof HTMLInputElement) { currentVolume = parseFloat(e.target.value); - waveform.setVolume(currentVolume); + waveform?.setVolume(currentVolume); } }} /> diff --git a/js/audio/shared/WaveformControls.svelte b/js/audio/shared/WaveformControls.svelte index 75fa1c0142..bac5f2da40 100644 --- a/js/audio/shared/WaveformControls.svelte +++ b/js/audio/shared/WaveformControls.svelte @@ -10,7 +10,7 @@ import VolumeLevels from "./VolumeLevels.svelte"; import VolumeControl from "./VolumeControl.svelte"; - export let waveform: WaveSurfer; + export let waveform: WaveSurfer | undefined; export let audio_duration: number; export let i18n: I18nFormatter; export let playing: boolean; @@ -30,7 +30,7 @@ let playbackSpeeds = [0.5, 1, 1.5, 2]; let playbackSpeed = playbackSpeeds[1]; - let trimRegion: RegionsPlugin; + let trimRegion: RegionsPlugin | null = null; let activeRegion: Region | null = null; let leftRegionHandle: HTMLDivElement | null; @@ -39,7 +39,10 @@ let currentVolume = 1; - $: trimRegion = waveform.registerPlugin(RegionsPlugin.create()); + $: trimRegion = + container && waveform + ? waveform.registerPlugin(RegionsPlugin.create()) + : null; $: trimRegion?.on("region-out", (region) => { region.play(); @@ -56,7 +59,8 @@ }); const addTrimRegion = (): void => { - activeRegion = trimRegion.addRegion({ + if (!trimRegion) return; + activeRegion = trimRegion?.addRegion({ start: audio_duration / 4, end: audio_duration / 2, ...trim_region_settings @@ -190,7 +194,7 @@ (playbackSpeeds.indexOf(playbackSpeed) + 1) % playbackSpeeds.length ]; - waveform.setPlaybackRate(playbackSpeed); + waveform?.setPlaybackRate(playbackSpeed); }} > {playbackSpeed}x @@ -205,7 +209,7 @@ waveform_options.skip_length )} seconds`} on:click={() => - waveform.skip( + waveform?.skip( get_skip_rewind_amount(audio_duration, waveform_options.skip_length) * -1 )} @@ -214,7 +218,7 @@ @@ -219,6 +220,7 @@ type="table" selected={current_hover === i} index={i} + {root} /> {/if} diff --git a/js/dropdown/shared/Dropdown.svelte b/js/dropdown/shared/Dropdown.svelte index 7d09a8e220..5acb8948a8 100644 --- a/js/dropdown/shared/Dropdown.svelte +++ b/js/dropdown/shared/Dropdown.svelte @@ -95,6 +95,8 @@ $: choices, set_choice_names_values(); + const is_browser = typeof window !== "undefined"; + $: { if (choices !== old_choices) { if (!allow_custom_value) { @@ -105,7 +107,7 @@ if (!allow_custom_value && filtered_indices.length > 0) { active_index = filtered_indices[0]; } - if (filter_input == document.activeElement) { + if (is_browser && filter_input === document.activeElement) { show_options = true; } } diff --git a/js/file/shared/FilePreview.svelte b/js/file/shared/FilePreview.svelte index 2b024ff23c..a867287b2a 100644 --- a/js/file/shared/FilePreview.svelte +++ b/js/file/shared/FilePreview.svelte @@ -55,6 +55,8 @@ dispatch("delete", removed[0]); dispatch("change", normalized_files); } + + const is_browser = typeof window !== "undefined";
{@html file.size != null ? prettyBytes(file.size) diff --git a/js/imageeditor/Index.svelte b/js/imageeditor/Index.svelte index b39ff5802e..9f78fa3614 100644 --- a/js/imageeditor/Index.svelte +++ b/js/imageeditor/Index.svelte @@ -29,7 +29,7 @@ export let root: string; export let value_is_output = false; - export let height: number | undefined; + export let height: number | undefined = 400; export let width: number | undefined; export let _selectable = false; @@ -90,10 +90,12 @@ let dragging: boolean; $: value && handle_change(); + const is_browser = typeof window !== "undefined"; + const raf = is_browser ? window.requestAnimationFrame : () => {}; function wait_for_next_frame(): Promise { return new Promise((resolve) => { - requestAnimationFrame(() => requestAnimationFrame(() => resolve())); + raf(() => raf(() => resolve())); }); } @@ -192,6 +194,7 @@ {sources} {label} {show_label} + {height} on:save={(e) => handle_save()} on:edit={() => gradio.dispatch("edit")} on:clear={() => gradio.dispatch("clear")} diff --git a/js/imageeditor/shared/ImageEditor.svelte b/js/imageeditor/shared/ImageEditor.svelte index d4da1a74e2..371464a453 100644 --- a/js/imageeditor/shared/ImageEditor.svelte +++ b/js/imageeditor/shared/ImageEditor.svelte @@ -28,7 +28,7 @@ child_bottom: number; }>; active_tool: Writable; - toolbar_box: Writable; + toolbar_box: Writable>; crop: Writable<[number, number, number, number]>; position_spring: Spring<{ x: number; @@ -74,6 +74,7 @@ }>(); export let crop_constraint = false; export let canvas_size: [number, number] | undefined; + export let parent_height: number; $: orig_canvas_size = canvas_size; @@ -84,13 +85,13 @@ let editor_box: EditorContext["editor_box"] = writable({ parent_width: 0, - parent_height: 0, + parent_height: parent_height, parent_top: 0, parent_left: 0, parent_right: 0, parent_bottom: 0, child_width: 0, - child_height: 0, + child_height: parent_height, child_top: 0, child_left: 0, child_right: 0, @@ -118,6 +119,7 @@ $: { history = !!$current_history.previous || $active_tool !== "bg"; } + const is_browser = typeof window !== "undefined"; const active_tool: Writable = writable("bg"); const reset_context: Writable void>> = @@ -126,7 +128,9 @@ PartialRecord void> > = writable({}); const contexts: Writable = writable([]); - const toolbar_box: Writable = writable(new DOMRect()); + const toolbar_box: Writable> = writable( + is_browser ? new DOMRect() : {} + ); const sort_order = ["bg", "layers", "crop", "draw", "erase"] as const; const editor_context = setContext(EDITOR_KEY, { diff --git a/js/imageeditor/shared/InteractiveImageEditor.svelte b/js/imageeditor/shared/InteractiveImageEditor.svelte index 15e16ba2b1..a54ef6216e 100644 --- a/js/imageeditor/shared/InteractiveImageEditor.svelte +++ b/js/imageeditor/shared/InteractiveImageEditor.svelte @@ -51,6 +51,7 @@ export let stream_handler: Client["stream"]; export let dragging: boolean; export let placeholder: string | undefined = undefined; + export let height = 400; const dispatch = createEventDispatcher<{ clear?: never; @@ -198,7 +199,7 @@ } let active_mode: "webcam" | "color" | null = null; - let editor_height = 0; + let editor_height = height - 100; $: [heading, paragraph] = placeholder ? inject(placeholder) : [false, false]; @@ -213,6 +214,7 @@ crop_size={Array.isArray(crop_size) ? crop_size : undefined} bind:this={editor} bind:height={editor_height} + parent_height={height} {changeable} on:save on:change={handle_change} diff --git a/js/imageeditor/shared/tools/Brush.svelte b/js/imageeditor/shared/tools/Brush.svelte index 5a9d165da8..5a64641b55 100644 --- a/js/imageeditor/shared/tools/Brush.svelte +++ b/js/imageeditor/shared/tools/Brush.svelte @@ -187,12 +187,12 @@ toggle_listeners("off"); } }); + const toggle_options = debounce_toggle(); + const unregister = register_tool(mode, { + cb: toggle_options + }); onMount(() => { - const unregister = register_tool(mode, { - cb: toggle_options - }); - return () => { unregister(); toggle_listeners("off"); @@ -230,8 +230,6 @@ timeout = setTimeout(later, 100); }; } - - const toggle_options = debounce_toggle(); ; export let show_swatch: boolean; let color_picker = false; diff --git a/js/imageeditor/shared/tools/Crop.svelte b/js/imageeditor/shared/tools/Crop.svelte index 8db440ef07..b16b961aa4 100644 --- a/js/imageeditor/shared/tools/Crop.svelte +++ b/js/imageeditor/shared/tools/Crop.svelte @@ -170,7 +170,8 @@ $: $editor_box && get_measurements(); - onMount(() => register_tool("crop")); + const unregister = register_tool("crop"); + onDestroy(unregister); {#if $active_tool === "crop" && measured} diff --git a/js/markdown/Example.svelte b/js/markdown/Example.svelte index 40f17abb05..d529a2773c 100644 --- a/js/markdown/Example.svelte +++ b/js/markdown/Example.svelte @@ -11,6 +11,7 @@ right: string; display: boolean; }[]; + export let root: string;
diff --git a/js/markdown/Index.svelte b/js/markdown/Index.svelte index c3a0ea2dbb..48a5306070 100644 --- a/js/markdown/Index.svelte +++ b/js/markdown/Index.svelte @@ -65,6 +65,7 @@ {header_links} {height} {show_copy_button} + root={gradio.root} />
diff --git a/js/markdown/package.json b/js/markdown/package.json index ade45fd39f..f75f303cf5 100644 --- a/js/markdown/package.json +++ b/js/markdown/package.json @@ -29,8 +29,8 @@ "@types/dompurify": "^3.0.2", "@types/katex": "^0.16.0", "@types/prismjs": "1.26.4", - "dompurify": "^3.0.3", "github-slugger": "^2.0.0", + "isomorphic-dompurify": "^2.14.0", "katex": "^0.16.7", "marked": "^12.0.0", "marked-gfm-heading-id": "^3.1.2", diff --git a/js/markdown/shared/Markdown.svelte b/js/markdown/shared/Markdown.svelte index 8f58ab904b..ee8d7ed98a 100644 --- a/js/markdown/shared/Markdown.svelte +++ b/js/markdown/shared/Markdown.svelte @@ -21,6 +21,7 @@ export let header_links = false; export let height: number | string | undefined = undefined; export let show_copy_button = false; + export let root: string; let copied = false; let timer: NodeJS.Timeout; @@ -82,6 +83,7 @@ {line_breaks} chatbot={false} {header_links} + {root} /> diff --git a/js/markdown/shared/MarkdownCode.svelte b/js/markdown/shared/MarkdownCode.svelte index 8fa69d9820..db600bc6c7 100644 --- a/js/markdown/shared/MarkdownCode.svelte +++ b/js/markdown/shared/MarkdownCode.svelte @@ -1,6 +1,6 @@ {#if !interactive} @@ -63,7 +64,7 @@ on:clear_status={() => gradio.dispatch("clear_status", loading_status)} /> - {#if value} + {#if value && is_browser} { + resizeObserver = new ResizeObserver((el) => { + if (!el[0].target || !(el[0].target instanceof HTMLElement)) return; if ( old_width === 0 && chart_element.offsetWidth !== 0 && @@ -153,11 +157,12 @@ // a bug where when a nominal chart is first loaded, the width is 0, it doesn't resize load_chart(); } else { - view.signal("width", chart_element.offsetWidth).run(); + view.signal("width", el[0].target.offsetWidth).run(); } }); vegaEmbed(chart_element, spec, { actions: false }).then(function (result) { view = result.view; + resizeObserver.observe(chart_element); var debounceTimeout: NodeJS.Timeout; view.addEventListener("dblclick", () => { @@ -217,6 +222,16 @@ release_callback = null; } }); + + return () => { + mounted = false; + if (view) { + view.finalize(); + } + if (resizeObserver) { + resizeObserver.disconnect(); + } + }; }); $: title, @@ -234,10 +249,12 @@ caption, sort, value, - mounted && load_chart(); + mounted, + chart_element, + computed_style && requestAnimationFrame(load_chart); function create_vega_lite_spec(): Spec | null { - if (!value) return null; + if (!value || !computed_style) return null; let accent_color = computed_style.getPropertyValue("--color-accent"); let body_text_color = computed_style.getPropertyValue("--body-text-color"); let borderColorPrimary = computed_style.getPropertyValue( @@ -491,8 +508,9 @@ /> {/if} {label} -
- {#if value} + {#if value && is_browser} +
+ {#if caption}

{caption}

{/if} diff --git a/js/paramviewer/ParamViewer.svelte b/js/paramviewer/ParamViewer.svelte index 059d998338..e5c0fdb140 100644 --- a/js/paramviewer/ParamViewer.svelte +++ b/js/paramviewer/ParamViewer.svelte @@ -21,11 +21,7 @@ let _docs: Param[]; let all_open = false; - $: { - setTimeout(() => { - _docs = highlight_code(docs, lang); - }, 0); - } + $: _docs = highlight_code(docs, lang); function highlight(code: string, lang: "python" | "typescript"): string { let highlighted = Prism.highlight(code, Prism.languages[lang], lang); diff --git a/js/utils/package.json b/js/utils/package.json index 3bfdb360ba..125a6e9bf1 100644 --- a/js/utils/package.json +++ b/js/utils/package.json @@ -3,7 +3,7 @@ "version": "0.6.0", "description": "Gradio UI packages", "type": "module", - "main": "src/index.ts", + "main": "./src/index.ts", "author": "", "license": "ISC", "dependencies": { @@ -25,7 +25,6 @@ "./package.json": "./package.json" }, "scripts": { - "package": "svelte-package --input=. --cwd=../../.config/", - "build": "esbuild src/index.ts --format=esm --outfile=dist/src/index.js --sourcemap --platform=node" + "package": "svelte-package --input=. --cwd=../../.config/" } } diff --git a/js/wasm/svelte/DownloadLink.svelte b/js/wasm/svelte/DownloadLink.svelte index 609f66f1ab..9ac06f3adf 100644 --- a/js/wasm/svelte/DownloadLink.svelte +++ b/js/wasm/svelte/DownloadLink.svelte @@ -1,6 +1,6 @@