@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/package.json CHANGED
@@ -1,67 +1,67 @@
1
1
  {
2
2
  "name": "@gradio/core",
3
- "version": "1.3.0",
3
+ "version": "1.4.1",
4
4
  "type": "module",
5
5
  "devDependencies": {
6
- "@gradio/annotatedimage": "^0.11.3",
7
- "@gradio/accordion": "^0.5.31",
8
- "@gradio/audio": "^0.22.3",
9
- "@gradio/atoms": "^0.22.0",
6
+ "@gradio/accordion": "^0.5.33",
7
+ "@gradio/atoms": "^0.22.2",
8
+ "@gradio/annotatedimage": "^0.11.5",
9
+ "@gradio/audio": "^0.23.0",
10
10
  "@gradio/box": "^0.2.30",
11
- "@gradio/browserstate": "^0.3.6",
12
- "@gradio/button": "^0.6.4",
13
- "@gradio/chatbot": "^0.29.4",
14
- "@gradio/checkbox": "^0.6.3",
15
- "@gradio/checkboxgroup": "^0.9.3",
11
+ "@gradio/browserstate": "^0.3.7",
12
+ "@gradio/button": "^0.6.6",
13
+ "@gradio/chatbot": "^0.29.6",
14
+ "@gradio/checkbox": "^0.6.5",
15
+ "@gradio/checkboxgroup": "^0.10.0",
16
+ "@gradio/code": "^0.17.5",
16
17
  "@gradio/client": "^2.1.0",
17
- "@gradio/colorpicker": "^0.5.6",
18
18
  "@gradio/column": "^0.3.2",
19
- "@gradio/datetime": "^0.4.3",
20
- "@gradio/code": "^0.17.3",
21
- "@gradio/downloadbutton": "^0.4.17",
22
- "@gradio/dropdown": "^0.11.4",
23
- "@gradio/dataset": "^0.5.4",
24
- "@gradio/fallback": "^0.4.34",
25
- "@gradio/file": "^0.14.3",
26
- "@gradio/fileexplorer": "^0.6.3",
27
- "@gradio/dataframe": "^0.21.6",
28
- "@gradio/form": "^0.3.0",
29
- "@gradio/group": "^0.3.2",
30
- "@gradio/gallery": "^0.17.1",
31
- "@gradio/highlightedtext": "^0.11.2",
32
- "@gradio/html": "^0.10.0",
19
+ "@gradio/dataframe": "^0.22.0",
20
+ "@gradio/dataset": "^0.5.6",
21
+ "@gradio/colorpicker": "^0.5.8",
22
+ "@gradio/datetime": "^0.4.5",
23
+ "@gradio/downloadbutton": "^0.4.18",
24
+ "@gradio/dropdown": "^0.11.6",
25
+ "@gradio/fallback": "^0.4.36",
26
+ "@gradio/file": "^0.14.5",
27
+ "@gradio/fileexplorer": "^0.6.5",
28
+ "@gradio/form": "^0.3.1",
29
+ "@gradio/gallery": "^0.17.4",
30
+ "@gradio/group": "^0.3.3",
31
+ "@gradio/highlightedtext": "^0.11.4",
32
+ "@gradio/html": "^0.12.0",
33
33
  "@gradio/icons": "^0.15.1",
34
- "@gradio/image": "^0.25.3",
35
- "@gradio/imageeditor": "^0.18.6",
36
- "@gradio/label": "^0.6.3",
37
- "@gradio/json": "^0.7.2",
38
- "@gradio/markdown": "^0.13.28",
39
- "@gradio/imageslider": "^0.4.3",
40
- "@gradio/model3d": "^0.16.4",
41
- "@gradio/multimodaltextbox": "^0.11.6",
42
- "@gradio/nativeplot": "^0.10.2",
43
- "@gradio/number": "^0.8.3",
44
- "@gradio/paramviewer": "^0.9.4",
45
- "@gradio/plot": "^0.10.4",
34
+ "@gradio/imageeditor": "^0.18.8",
35
+ "@gradio/image": "^0.26.0",
36
+ "@gradio/imageslider": "^0.4.5",
37
+ "@gradio/json": "^0.7.4",
38
+ "@gradio/model3d": "^0.16.6",
39
+ "@gradio/markdown": "^0.13.30",
40
+ "@gradio/multimodaltextbox": "^0.11.8",
41
+ "@gradio/label": "^0.6.5",
42
+ "@gradio/nativeplot": "^0.10.4",
43
+ "@gradio/number": "^0.8.5",
44
+ "@gradio/radio": "^0.10.0",
45
+ "@gradio/plot": "^0.10.6",
46
+ "@gradio/paramviewer": "^0.9.6",
46
47
  "@gradio/row": "^0.3.1",
47
- "@gradio/sidebar": "^0.2.3",
48
- "@gradio/simpledropdown": "^0.3.34",
49
- "@gradio/simpleimage": "^0.9.5",
50
- "@gradio/slider": "^0.7.6",
51
- "@gradio/simpletextbox": "^0.3.36",
52
- "@gradio/radio": "^0.9.3",
53
- "@gradio/state": "^0.2.2",
54
- "@gradio/statustracker": "^0.12.4",
55
- "@gradio/tabitem": "^0.6.5",
56
- "@gradio/tabs": "^0.5.7",
57
- "@gradio/textbox": "^0.13.4",
48
+ "@gradio/simpleimage": "^0.9.7",
49
+ "@gradio/simpledropdown": "^0.3.36",
50
+ "@gradio/simpletextbox": "^0.3.38",
51
+ "@gradio/sidebar": "^0.2.5",
52
+ "@gradio/state": "^0.2.3",
53
+ "@gradio/slider": "^0.7.8",
54
+ "@gradio/statustracker": "^0.13.0",
55
+ "@gradio/tabs": "^0.5.8",
56
+ "@gradio/tabitem": "^0.6.6",
57
+ "@gradio/textbox": "^0.13.6",
58
58
  "@gradio/theme": "^0.6.1",
59
- "@gradio/timer": "^0.4.8",
60
- "@gradio/upload": "^0.17.6",
61
- "@gradio/uploadbutton": "^0.9.17",
62
- "@gradio/utils": "^0.11.3",
63
- "@gradio/video": "^0.20.3",
64
- "@gradio/vibeeditor": "^0.3.5"
59
+ "@gradio/timer": "^0.4.9",
60
+ "@gradio/upload": "^0.17.7",
61
+ "@gradio/utils": "^0.12.1",
62
+ "@gradio/uploadbutton": "^0.9.18",
63
+ "@gradio/vibeeditor": "^0.3.7",
64
+ "@gradio/video": "^0.20.5"
65
65
  },
66
66
  "msw": {
67
67
  "workerDirectory": "public"
package/src/Blocks.svelte CHANGED
@@ -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}
@@ -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>
package/src/i18n.test.ts CHANGED
@@ -8,8 +8,31 @@ import {
8
8
  afterEach
9
9
  } from "vitest";
10
10
  import { Lang, process_langs } from "./i18n";
11
- import languagesByAnyCode from "wikidata-lang/indexes/by_any_code";
11
+ // wikidata-lang/indexes/by_any_code uses Node.js createRequire internally.
12
+ // Import the raw JSON data and build the index directly for browser compatibility.
13
+ import languages from "wikidata-lang/data/languages.json";
12
14
  import BCP47 from "./lang/BCP47_codes";
15
+
16
+ const languagesByAnyCode: Record<string, any[]> = {};
17
+ for (const langData of languages) {
18
+ for (const codeName of [
19
+ "wmCode",
20
+ "iso6391",
21
+ "iso6392",
22
+ "iso6393",
23
+ "iso6396"
24
+ ]) {
25
+ const codes = (langData as Record<string, any>)[codeName];
26
+ if (!codes) continue;
27
+ for (const code of codes) {
28
+ if (languagesByAnyCode[code] == null) {
29
+ languagesByAnyCode[code] = [langData];
30
+ } else if (!languagesByAnyCode[code].includes(langData)) {
31
+ languagesByAnyCode[code].push(langData);
32
+ }
33
+ }
34
+ }
35
+ }
13
36
  import {
14
37
  get_initial_locale,
15
38
  load_translations,
@@ -25,7 +48,10 @@ vi.mock("svelte-i18n", () => ({
25
48
  locale: { set: vi.fn() },
26
49
  _: vi.fn((key) => `translated_${key}`),
27
50
  addMessages: vi.fn(),
28
- init: vi.fn().mockResolvedValue(undefined)
51
+ init: vi.fn().mockResolvedValue(undefined),
52
+ getLocaleFromNavigator: vi.fn(() => "en"),
53
+ register: vi.fn(),
54
+ waitLocale: vi.fn().mockResolvedValue(undefined)
29
55
  }));
30
56
 
31
57
  const mock_translations: Record<string, string> = {
@@ -40,6 +40,20 @@ const type_map = {
40
40
  walkthrough: "tabs",
41
41
  walkthroughstep: "tabitem"
42
42
  };
43
+
44
+ export function get_api_url(config: Omit<AppConfig, "api_url">): string {
45
+ // Handle api_prefix correctly when app is mounted at a subpath.
46
+ // config.root may not include a trailing slash, so we normalize its pathname
47
+ // before appending api_prefix to ensure correct URL construction.
48
+ const rootUrl = new URL(config.root);
49
+ const rootPath = rootUrl.pathname.endsWith("/")
50
+ ? rootUrl.pathname
51
+ : rootUrl.pathname + "/";
52
+ const apiPrefix = config.api_prefix.startsWith("/")
53
+ ? config.api_prefix
54
+ : "/" + config.api_prefix;
55
+ return new URL(rootPath.slice(0, -1) + apiPrefix, rootUrl.origin).toString();
56
+ }
43
57
  export class AppTree {
44
58
  /** the raw component structure received from the backend */
45
59
  #component_payload: ComponentMeta[];
@@ -91,13 +105,15 @@ export class AppTree {
91
105
  this.ready_resolve = resolve;
92
106
  });
93
107
  this.reactive_formatter = reactive_formatter;
108
+ const api_url = get_api_url(config);
94
109
  this.#config = {
95
110
  ...config,
96
- api_url: new URL(config.api_prefix, config.root).toString()
111
+ api_url
97
112
  };
98
113
  this.#component_payload = components;
99
114
  this.#layout_payload = layout;
100
115
  this.#dependency_payload = dependencies;
116
+ this.#event_dispatcher = event_dispatcher;
101
117
  this.root = this.create_node(
102
118
  { id: layout.id, children: [] },
103
119
  new Map(),
@@ -131,7 +147,7 @@ export class AppTree {
131
147
  this.initial_tabs = {};
132
148
  gather_initial_tabs(this.root!, this.initial_tabs);
133
149
  this.postprocess(this.root!);
134
- this.#event_dispatcher = event_dispatcher;
150
+
135
151
  this.root_untracked = this.root;
136
152
  }
137
153
 
@@ -143,9 +159,10 @@ export class AppTree {
143
159
  ) {
144
160
  this.#layout_payload = layout;
145
161
  this.#component_payload = components;
162
+ const api_url = get_api_url(config);
146
163
  this.#config = {
147
164
  ...config,
148
- api_url: new URL(config.api_prefix, config.root).toString()
165
+ api_url
149
166
  };
150
167
  this.#dependency_payload = dependencies;
151
168
 
@@ -237,6 +254,7 @@ export class AppTree {
237
254
  node,
238
255
  this.components_to_register
239
256
  ),
257
+
240
258
  (node) => apply_initial_tabs(node, this.initial_tabs),
241
259
  (node) => this.find_attached_events(node, this.#dependency_payload),
242
260
  (node) =>
@@ -325,7 +343,8 @@ export class AppTree {
325
343
  props: {
326
344
  visible: true,
327
345
  root: "",
328
- theme_mode: "light"
346
+ theme_mode: "light",
347
+ scale: this.#config.fill_height ? 1 : null
329
348
  },
330
349
  component_class_id: "column",
331
350
  key: null
@@ -338,17 +357,30 @@ export class AppTree {
338
357
  if (reactive_formatter) {
339
358
  component.props.i18n = reactive_formatter;
340
359
  }
360
+
341
361
  const processed_props = gather_props(
342
362
  opts.id,
343
363
  component.props,
344
364
  [this.#input_ids, this.#output_ids],
345
365
  this.client,
346
366
  this.#config.api_url,
347
- { ...this.#config }
367
+ {
368
+ ...this.#config,
369
+ register_component: this.register_component.bind(this),
370
+ dispatcher: this.#event_dispatcher.bind(this)
371
+ }
348
372
  );
349
373
 
350
374
  const type =
351
375
  type_map[component.type as keyof typeof type_map] || component.type;
376
+ const loading_component =
377
+ processed_props.shared_props.visible !== false
378
+ ? get_component(
379
+ component.type,
380
+ component.component_class_id,
381
+ this.#config.api_url || ""
382
+ )
383
+ : null;
352
384
 
353
385
  const node = {
354
386
  id: opts.id,
@@ -359,12 +391,9 @@ export class AppTree {
359
391
  component_class_id: component.component_class_id || component.type,
360
392
  component:
361
393
  processed_props.shared_props.visible !== false
362
- ? get_component(
363
- component.type,
364
- component.component_class_id,
365
- this.#config.api_url || ""
366
- )
394
+ ? loading_component?.component || null
367
395
  : null,
396
+ runtime: loading_component?.runtime || (false as false),
368
397
  key: component.key,
369
398
  rendered_in: component.rendered_in,
370
399
  documentation: component.documentation,
@@ -398,20 +427,6 @@ export class AppTree {
398
427
  }
399
428
  n.children = subtree.children;
400
429
  }
401
-
402
- async update_visibility(
403
- node: ProcessedComponentMeta,
404
- new_state: any
405
- ): Promise<void> {
406
- node.children.forEach((child) => {
407
- const _set_data = this.#set_callbacks.get(child.id);
408
- if (_set_data) {
409
- _set_data(new_state);
410
- }
411
- this.update_visibility(child, new_state);
412
- });
413
- }
414
-
415
430
  /*
416
431
  * Updates the state of a component by its ID
417
432
  * @param id the ID of the component to update
@@ -480,6 +495,19 @@ export class AppTree {
480
495
  await this.update_visibility(node, new_state);
481
496
  }
482
497
 
498
+ async update_visibility(
499
+ node: ProcessedComponentMeta,
500
+ new_state: any
501
+ ): Promise<void> {
502
+ node.children.forEach((child) => {
503
+ const _set_data = this.#set_callbacks.get(child.id);
504
+ if (_set_data) {
505
+ _set_data(new_state);
506
+ }
507
+ this.update_visibility(child, new_state);
508
+ });
509
+ }
510
+
483
511
  /**
484
512
  * Gets the current state of a component by its ID
485
513
  * @param id the ID of the component to get the state of
@@ -641,6 +669,7 @@ function gather_props(
641
669
  for (const key in additional) {
642
670
  if (allowed_shared_props.includes(key as keyof SharedProps)) {
643
671
  const _key = key as keyof SharedProps;
672
+ //@ts-ignore
644
673
  _shared_props[_key] = additional[key];
645
674
  } else {
646
675
  _props[key] = additional[key];
@@ -658,8 +687,9 @@ function gather_props(
658
687
 
659
688
  _shared_props.load_component = (
660
689
  name: string,
661
- variant: "base" | "component" | "example"
662
- ) => get_component(name, "", api_url, variant) as LoadingComponent;
690
+ variant: "base" | "component" | "example",
691
+ component_class_id?: string
692
+ ) => get_component(name, component_class_id || "", api_url, variant);
663
693
 
664
694
  _shared_props.visible =
665
695
  _shared_props.visible === undefined ? true : _shared_props.visible;
@@ -674,9 +704,15 @@ function handle_visibility(
674
704
  ): ProcessedComponentMeta {
675
705
  // Check if the node is visible
676
706
  if (node.props.shared_props.visible && !node.component) {
707
+ const loading_component = get_component(
708
+ node.type,
709
+ node.component_class_id,
710
+ api_url
711
+ );
677
712
  const result: ProcessedComponentMeta = {
678
713
  ...node,
679
- component: get_component(node.type, node.component_class_id, api_url),
714
+ component: loading_component.component,
715
+
680
716
  children: []
681
717
  };
682
718
 
@@ -757,6 +793,7 @@ function untrack_children_of_closed_accordions_or_inactive_tabs(
757
793
  if (
758
794
  child.type === "tabitem" &&
759
795
  child.props.props.id !==
796
+ //@ts-ignore
760
797
  (node.props.props.selected || node.props.props.initial_tabs[0].id)
761
798
  ) {
762
799
  _untrack(child, components_to_register);