@gradio/core 1.3.0 → 1.4.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/CHANGELOG.md CHANGED
@@ -1,5 +1,72 @@
1
1
  # @gradio/core
2
2
 
3
+ ## 1.4.1
4
+
5
+ ### Fixes
6
+
7
+ - [#12566](https://github.com/gradio-app/gradio/pull/12566) [`7760161`](https://github.com/gradio-app/gradio/commit/7760161258abe6329b754dd6d2511fc3b61fed95) - Fix custom components in SSR Mode + Custom Component Examples. Thanks @freddyaboulton!
8
+ - [#12803](https://github.com/gradio-app/gradio/pull/12803) [`f4c3a6d`](https://github.com/gradio-app/gradio/commit/f4c3a6dcb45218722d3150baef953c731d3eccf2) - fix: gradio_api path in mount_gradio_app. Thanks @shandowc!
9
+
10
+ ### Dependency updates
11
+
12
+ - @gradio/utils@0.12.1
13
+ - @gradio/statustracker@0.13.0
14
+ - @gradio/gallery@0.17.4
15
+ - @gradio/plot@0.10.6
16
+ - @gradio/textbox@0.13.6
17
+ - @gradio/html@0.12.0
18
+ - @gradio/button@0.6.6
19
+ - @gradio/code@0.17.5
20
+ - @gradio/paramviewer@0.9.6
21
+ - @gradio/checkbox@0.6.5
22
+ - @gradio/image@0.26.0
23
+ - @gradio/video@0.20.5
24
+ - @gradio/file@0.14.5
25
+ - @gradio/audio@0.23.0
26
+ - @gradio/column@0.3.2
27
+ - @gradio/dropdown@0.11.6
28
+
29
+ ## 1.4.0
30
+
31
+ ### Features
32
+
33
+ - [#12879](https://github.com/gradio-app/gradio/pull/12879) [`c498688`](https://github.com/gradio-app/gradio/commit/c4986883b267570d76b442899c6fc09d14e3e222) - Ensure svelte version mismatches do not break custom components. Thanks @pngwn!
34
+
35
+ ### Fixes
36
+
37
+ - [#12970](https://github.com/gradio-app/gradio/pull/12970) [`7326ea3`](https://github.com/gradio-app/gradio/commit/7326ea312bee7ccdaf4a1e4e11ace8f11b607ca5) - remove new console logs. Thanks @hannahblair!
38
+ - [#12968](https://github.com/gradio-app/gradio/pull/12968) [`fe95534`](https://github.com/gradio-app/gradio/commit/fe955348f24115744015d85639e170b8518b28c1) - Fix custom component reload mode. Thanks @freddyaboulton!
39
+ - [#12956](https://github.com/gradio-app/gradio/pull/12956) [`e8dadd6`](https://github.com/gradio-app/gradio/commit/e8dadd648483b6016913a9b7fa2580dbc08cb823) - Fix fill_height not working after Svelte 5 migration. Thanks @hysts!
40
+
41
+ ### Dependency updates
42
+
43
+ - @gradio/button@0.6.5
44
+ - @gradio/code@0.17.4
45
+ - @gradio/html@0.11.1
46
+ - @gradio/paramviewer@0.9.5
47
+ - @gradio/statustracker@0.12.5
48
+ - @gradio/tabitem@0.6.6
49
+ - @gradio/tabs@0.5.8
50
+ - @gradio/utils@0.12.0
51
+ - @gradio/column@0.3.2
52
+ - @gradio/atoms@0.22.2
53
+ - @gradio/upload@0.17.7
54
+ - @gradio/image@0.25.4
55
+ - @gradio/gallery@0.17.3
56
+ - @gradio/plot@0.10.5
57
+ - @gradio/checkbox@0.6.4
58
+ - @gradio/textbox@0.13.5
59
+ - @gradio/dropdown@0.11.5
60
+ - @gradio/file@0.14.4
61
+ - @gradio/video@0.20.4
62
+ - @gradio/audio@0.22.4
63
+
64
+ ## 1.3.0
65
+
66
+ ### Dependency updates
67
+
68
+ - @gradio/html@0.11.0
69
+
3
70
  ## 1.3.0
4
71
 
5
72
  ### Features
@@ -4,18 +4,15 @@
4
4
  import { Client } from "@gradio/client";
5
5
  import { writable } from "svelte/store";
6
6
 
7
- // import type { LoadingStatus, LoadingStatusCollection } from "./stores";
8
-
9
7
  import type {
10
8
  ComponentMeta,
11
9
  Dependency as IDependency,
12
10
  LayoutNode
13
11
  } from "./types";
14
- // import type { UpdateTransaction } from "./_init";
15
12
  import type { ThemeMode, Payload } from "./types";
16
13
  import { Toast } from "@gradio/statustracker";
17
14
  import type { ToastMessage } from "@gradio/statustracker";
18
- import { type ShareData, type ValueData, GRADIO_ROOT } from "@gradio/utils";
15
+ import { type ShareData, GRADIO_ROOT } from "@gradio/utils";
19
16
 
20
17
  import MountComponents from "./MountComponents.svelte";
21
18
  import { prefix_css } from "./css";
@@ -24,18 +21,13 @@
24
21
  import type ApiDocsInterface from "./api_docs/ApiDocs.svelte";
25
22
  import type ApiRecorderInterface from "./api_docs/ApiRecorder.svelte";
26
23
  import type SettingsInterface from "./api_docs/Settings.svelte";
27
- // import type { ComponentType } from "svelte";
28
24
 
29
25
  import logo from "./images/logo.svg";
30
26
  import api_logo from "./api_docs/img/api-logo.svg";
31
27
  import settings_logo from "./api_docs/img/settings-logo.svg";
32
28
  import record_stop from "./api_docs/img/record-stop.svg";
33
29
  import { AppTree } from "./init.svelte";
34
- // import type {
35
- // LogMessage,
36
- // RenderMessage,
37
- // StatusMessage,
38
- // } from "@gradio/client";
30
+
39
31
  import * as screen_recorder from "./screen_recorder";
40
32
 
41
33
  import { DependencyManager } from "./dependency";
@@ -171,7 +163,8 @@
171
163
  version,
172
164
  api_prefix,
173
165
  max_file_size,
174
- autoscroll
166
+ autoscroll,
167
+ fill_height
175
168
  },
176
169
  app,
177
170
  $reactive_formatter,
@@ -191,11 +184,6 @@
191
184
  });
192
185
  }
193
186
 
194
- setContext(GRADIO_ROOT, {
195
- register: app_tree.register_component.bind(app_tree),
196
- dispatcher: gradio_event_dispatcher
197
- });
198
-
199
187
  let api_calls: Payload[] = $state([]);
200
188
  let last_api_call: Payload | null = $state(null);
201
189
  // We need a callback to add to api_calls from the DependencyManager
@@ -256,7 +244,8 @@
256
244
  version,
257
245
  api_prefix,
258
246
  max_file_size,
259
- autoscroll
247
+ autoscroll,
248
+ fill_height
260
249
  });
261
250
  dep_manager.reload(
262
251
  dependencies,
@@ -1,12 +1,13 @@
1
1
  <script lang="ts">
2
2
  import Self from "./MountComponents.svelte";
3
- let { node } = $props();
3
+ import MountCustomComponent from "./MountCustomComponent.svelte";
4
+ let { node, ...rest } = $props();
4
5
 
5
6
  let component = $derived(await node.component);
6
7
  </script>
7
8
 
8
9
  {#if node && component}
9
- {#if node.props.shared_props.visible}
10
+ {#if node.props.shared_props.visible && !node.runtime}
10
11
  <svelte:component
11
12
  this={component.default}
12
13
  shared_props={node.props.shared_props}
@@ -18,5 +19,13 @@
18
19
  {/each}
19
20
  {/if}
20
21
  </svelte:component>
22
+ {:else if node.props.shared_props.visible && node.runtime}
23
+ <MountCustomComponent {...rest} {node}>
24
+ {#if node.children && node.children.length}
25
+ {#each node.children as _node}
26
+ <Self node={_node} />
27
+ {/each}
28
+ {/if}
29
+ </MountCustomComponent>
21
30
  {/if}
22
31
  {/if}
@@ -1,5 +1,5 @@
1
1
  declare const MountComponents: import("svelte").Component<{
2
2
  node: any;
3
- }, {}, "">;
3
+ } & Record<string, any>, {}, "">;
4
4
  type MountComponents = ReturnType<typeof MountComponents>;
5
5
  export default MountComponents;
@@ -0,0 +1,38 @@
1
+ <script lang="ts">
2
+ let { node, children, ...rest } = $props();
3
+
4
+ let component = $derived(await node.component);
5
+ let runtime = $derived(
6
+ (await node.runtime) as {
7
+ mount: typeof import("svelte").mount;
8
+ unmount: typeof import("svelte").unmount;
9
+ }
10
+ );
11
+ let el: HTMLElement = $state(null);
12
+
13
+ $effect(() => {
14
+ if (!el || !runtime || !component) return;
15
+
16
+ // Read prop references so the effect re-runs when the node is
17
+ // replaced during a dev reload (new objects are created by
18
+ // app_tree.reload).
19
+ const _shared_props = node.props.shared_props;
20
+ const _props = node.props.props;
21
+ const _runtime = runtime;
22
+
23
+ const mounted = _runtime.mount(component.default, {
24
+ target: el,
25
+ props: {
26
+ shared_props: _shared_props,
27
+ props: _props,
28
+ children
29
+ }
30
+ });
31
+
32
+ return () => {
33
+ _runtime.unmount(mounted);
34
+ };
35
+ });
36
+ </script>
37
+
38
+ <span bind:this={el}></span>
@@ -0,0 +1,6 @@
1
+ declare const MountCustomComponent: import("svelte").Component<{
2
+ node: any;
3
+ children: any;
4
+ } & Record<string, any>, {}, "">;
5
+ type MountCustomComponent = ReturnType<typeof MountCustomComponent>;
6
+ export default MountCustomComponent;
@@ -15,6 +15,7 @@ type Tab = {
15
15
  order?: number;
16
16
  component_id: number;
17
17
  };
18
+ export declare function get_api_url(config: Omit<AppConfig, "api_url">): string;
18
19
  export declare class AppTree {
19
20
  #private;
20
21
  /** Need this to set i18n in re-render */
@@ -61,8 +62,8 @@ export declare class AppTree {
61
62
  */
62
63
  create_node(opts: LayoutNode, component_map: Map<number, ComponentMeta>, root?: boolean, reactive_formatter?: (str: string) => string): ProcessedComponentMeta;
63
64
  rerender(components: ComponentMeta[], layout: LayoutNode): void;
64
- update_visibility(node: ProcessedComponentMeta, new_state: any): Promise<void>;
65
65
  update_state(id: number, new_state: Partial<SharedProps> & Record<string, unknown>, check_visibility?: boolean): Promise<void>;
66
+ update_visibility(node: ProcessedComponentMeta, new_state: any): Promise<void>;
66
67
  /**
67
68
  * Gets the current state of a component by its ID
68
69
  * @param id the ID of the component to get the state of
@@ -8,6 +8,19 @@ const type_map = {
8
8
  walkthrough: "tabs",
9
9
  walkthroughstep: "tabitem"
10
10
  };
11
+ export function get_api_url(config) {
12
+ // Handle api_prefix correctly when app is mounted at a subpath.
13
+ // config.root may not include a trailing slash, so we normalize its pathname
14
+ // before appending api_prefix to ensure correct URL construction.
15
+ const rootUrl = new URL(config.root);
16
+ const rootPath = rootUrl.pathname.endsWith("/")
17
+ ? rootUrl.pathname
18
+ : rootUrl.pathname + "/";
19
+ const apiPrefix = config.api_prefix.startsWith("/")
20
+ ? config.api_prefix
21
+ : "/" + config.api_prefix;
22
+ return new URL(rootPath.slice(0, -1) + apiPrefix, rootUrl.origin).toString();
23
+ }
11
24
  export class AppTree {
12
25
  /** the raw component structure received from the backend */
13
26
  #component_payload;
@@ -45,13 +58,15 @@ export class AppTree {
45
58
  this.ready_resolve = resolve;
46
59
  });
47
60
  this.reactive_formatter = reactive_formatter;
61
+ const api_url = get_api_url(config);
48
62
  this.#config = {
49
63
  ...config,
50
- api_url: new URL(config.api_prefix, config.root).toString()
64
+ api_url
51
65
  };
52
66
  this.#component_payload = components;
53
67
  this.#layout_payload = layout;
54
68
  this.#dependency_payload = dependencies;
69
+ this.#event_dispatcher = event_dispatcher;
55
70
  this.root = this.create_node({ id: layout.id, children: [] }, new Map(), true);
56
71
  for (const comp of components) {
57
72
  if (comp.props.visible != false)
@@ -71,15 +86,15 @@ export class AppTree {
71
86
  this.initial_tabs = {};
72
87
  gather_initial_tabs(this.root, this.initial_tabs);
73
88
  this.postprocess(this.root);
74
- this.#event_dispatcher = event_dispatcher;
75
89
  this.root_untracked = this.root;
76
90
  }
77
91
  reload(components, layout, dependencies, config) {
78
92
  this.#layout_payload = layout;
79
93
  this.#component_payload = components;
94
+ const api_url = get_api_url(config);
80
95
  this.#config = {
81
96
  ...config,
82
- api_url: new URL(config.api_prefix, config.root).toString()
97
+ api_url
83
98
  };
84
99
  this.#dependency_payload = dependencies;
85
100
  this.root = this.create_node({ id: layout.id, children: [] }, new Map(), true);
@@ -205,7 +220,8 @@ export class AppTree {
205
220
  props: {
206
221
  visible: true,
207
222
  root: "",
208
- theme_mode: "light"
223
+ theme_mode: "light",
224
+ scale: this.#config.fill_height ? 1 : null
209
225
  },
210
226
  component_class_id: "column",
211
227
  key: null
@@ -217,8 +233,15 @@ export class AppTree {
217
233
  if (reactive_formatter) {
218
234
  component.props.i18n = reactive_formatter;
219
235
  }
220
- const processed_props = gather_props(opts.id, component.props, [this.#input_ids, this.#output_ids], this.client, this.#config.api_url, { ...this.#config });
236
+ const processed_props = gather_props(opts.id, component.props, [this.#input_ids, this.#output_ids], this.client, this.#config.api_url, {
237
+ ...this.#config,
238
+ register_component: this.register_component.bind(this),
239
+ dispatcher: this.#event_dispatcher.bind(this)
240
+ });
221
241
  const type = type_map[component.type] || component.type;
242
+ const loading_component = processed_props.shared_props.visible !== false
243
+ ? get_component(component.type, component.component_class_id, this.#config.api_url || "")
244
+ : null;
222
245
  const node = {
223
246
  id: opts.id,
224
247
  type: type,
@@ -227,8 +250,9 @@ export class AppTree {
227
250
  show_progress_on: null,
228
251
  component_class_id: component.component_class_id || component.type,
229
252
  component: processed_props.shared_props.visible !== false
230
- ? get_component(component.type, component.component_class_id, this.#config.api_url || "")
253
+ ? loading_component?.component || null
231
254
  : null,
255
+ runtime: loading_component?.runtime || false,
232
256
  key: component.key,
233
257
  rendered_in: component.rendered_in,
234
258
  documentation: component.documentation,
@@ -253,15 +277,6 @@ export class AppTree {
253
277
  }
254
278
  n.children = subtree.children;
255
279
  }
256
- async update_visibility(node, new_state) {
257
- node.children.forEach((child) => {
258
- const _set_data = this.#set_callbacks.get(child.id);
259
- if (_set_data) {
260
- _set_data(new_state);
261
- }
262
- this.update_visibility(child, new_state);
263
- });
264
- }
265
280
  /*
266
281
  * Updates the state of a component by its ID
267
282
  * @param id the ID of the component to update
@@ -325,6 +340,15 @@ export class AppTree {
325
340
  // @ts-ignore
326
341
  await this.update_visibility(node, new_state);
327
342
  }
343
+ async update_visibility(node, new_state) {
344
+ node.children.forEach((child) => {
345
+ const _set_data = this.#set_callbacks.get(child.id);
346
+ if (_set_data) {
347
+ _set_data(new_state);
348
+ }
349
+ this.update_visibility(child, new_state);
350
+ });
351
+ }
328
352
  /**
329
353
  * Gets the current state of a component by its ID
330
354
  * @param id the ID of the component to get the state of
@@ -450,6 +474,7 @@ function gather_props(id, props, dependencies, client, api_url, additional = {})
450
474
  for (const key in additional) {
451
475
  if (allowed_shared_props.includes(key)) {
452
476
  const _key = key;
477
+ //@ts-ignore
453
478
  _shared_props[_key] = additional[key];
454
479
  }
455
480
  else {
@@ -459,7 +484,7 @@ function gather_props(id, props, dependencies, client, api_url, additional = {})
459
484
  _shared_props.client = client;
460
485
  _shared_props.id = id;
461
486
  _shared_props.interactive = determine_interactivity(id, _shared_props.interactive, _props.value, dependencies);
462
- _shared_props.load_component = (name, variant) => get_component(name, "", api_url, variant);
487
+ _shared_props.load_component = (name, variant, component_class_id) => get_component(name, component_class_id || "", api_url, variant);
463
488
  _shared_props.visible =
464
489
  _shared_props.visible === undefined ? true : _shared_props.visible;
465
490
  _shared_props.loading_status = {};
@@ -468,9 +493,10 @@ function gather_props(id, props, dependencies, client, api_url, additional = {})
468
493
  function handle_visibility(node, api_url) {
469
494
  // Check if the node is visible
470
495
  if (node.props.shared_props.visible && !node.component) {
496
+ const loading_component = get_component(node.type, node.component_class_id, api_url);
471
497
  const result = {
472
498
  ...node,
473
- component: get_component(node.type, node.component_class_id, api_url),
499
+ component: loading_component.component,
474
500
  children: []
475
501
  };
476
502
  if (node.children) {
@@ -526,6 +552,7 @@ function untrack_children_of_closed_accordions_or_inactive_tabs(node, components
526
552
  node.children.forEach((child) => {
527
553
  if (child.type === "tabitem" &&
528
554
  child.props.props.id !==
555
+ //@ts-ignore
529
556
  (node.props.props.selected || node.props.props.initial_tabs[0].id)) {
530
557
  _untrack(child, components_to_register);
531
558
  mark_component_invisible_if_visible(child, hidden_on_startup);
@@ -0,0 +1 @@
1
+ export {};