@gradio/core 0.22.0 → 0.23.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,47 @@
1
1
  # @gradio/core
2
2
 
3
+ ## 0.23.1
4
+
5
+ ### Features
6
+
7
+ - [#11619](https://github.com/gradio-app/gradio/pull/11619) [`33c5d2b`](https://github.com/gradio-app/gradio/commit/33c5d2bb8214c0d7a90daca0f1eaf96411a52e79) - Add a query param for the selected language & make MCP the default option when `mcp_server` is enabled. Thanks @abidlabs!
8
+ - [#11615](https://github.com/gradio-app/gradio/pull/11615) [`e2b66d7`](https://github.com/gradio-app/gradio/commit/e2b66d718f3a8f57b6ee224502849ee737b1b120) - fix change events for hidden components. Thanks @pngwn!
9
+
10
+ ### Fixes
11
+
12
+ - [#11599](https://github.com/gradio-app/gradio/pull/11599) [`c39d373`](https://github.com/gradio-app/gradio/commit/c39d3739bf2494ad13556174757cdd56060f033e) - Ensure component visibility is correctly propagated to all components. Thanks @copilot-swe-agent!
13
+
14
+ ## 0.23.0
15
+
16
+ ### Features
17
+
18
+ - [#11578](https://github.com/gradio-app/gradio/pull/11578) [`872798a`](https://github.com/gradio-app/gradio/commit/872798a780dd81c834a44b05277f6c9ebe09de8b) - Add an `api_description` parameter for API and MCP server. Thanks @abidlabs!
19
+ - [#11543](https://github.com/gradio-app/gradio/pull/11543) [`ac95ac0`](https://github.com/gradio-app/gradio/commit/ac95ac0d8c2e65d1632376e632fb7d16131334b6) - Connection handling messaging. Thanks @aliabid94!
20
+ - [#11508](https://github.com/gradio-app/gradio/pull/11508) [`f5a6fa8`](https://github.com/gradio-app/gradio/commit/f5a6fa8c52bcb8f508e10ea54a3427f3dab8e3f8) - Handle uploading files in mcp server automatically. Thanks @freddyaboulton!
21
+ - [#11515](https://github.com/gradio-app/gradio/pull/11515) [`2c24ca7`](https://github.com/gradio-app/gradio/commit/2c24ca709396291a344d981c19ed1655028b5d64) - Making it easier for MCP developers call APIs with user credentials. Thanks @freddyaboulton!
22
+ - [#11584](https://github.com/gradio-app/gradio/pull/11584) [`78428cb`](https://github.com/gradio-app/gradio/commit/78428cb29bf6dc66d583b7cf93dd404aef737e75) - Fix reload mode. Thanks @aliabid94!
23
+
24
+ ### Fixes
25
+
26
+ - [#11590](https://github.com/gradio-app/gradio/pull/11590) [`33b6057`](https://github.com/gradio-app/gradio/commit/33b6057dc5cbdfdab15b1ee000b0f0b3d9f3fff6) - Add Gradio File Input keyword to gradio file inputs. Thanks @freddyaboulton!
27
+
28
+ ### Dependency updates
29
+
30
+ - @gradio/video@0.14.21
31
+ - @gradio/client@1.15.6
32
+ - @gradio/statustracker@0.10.15
33
+ - @gradio/button@0.5.7
34
+ - @gradio/upload@0.16.11
35
+ - @gradio/checkbox@0.4.26
36
+ - @gradio/image@0.22.13
37
+ - @gradio/gallery@0.15.27
38
+ - @gradio/plot@0.9.20
39
+ - @gradio/textbox@0.10.17
40
+ - @gradio/file@0.12.24
41
+ - @gradio/code@0.14.11
42
+ - @gradio/paramviewer@0.7.13
43
+ - @gradio/column@0.2.1
44
+
3
45
  ## 0.22.0
4
46
 
5
47
  ### Features
@@ -35,6 +35,7 @@ export let api_prefix = "";
35
35
  export let max_file_size = void 0;
36
36
  export let initial_layout = void 0;
37
37
  export let css = null;
38
+ let broken_connection = false;
38
39
  let {
39
40
  layout: _layout,
40
41
  targets,
@@ -46,8 +47,11 @@ let {
46
47
  loading_status,
47
48
  scheduled_updates,
48
49
  create_layout,
49
- rerender_layout
50
- } = create_components(initial_layout);
50
+ rerender_layout,
51
+ value_change
52
+ } = create_components({
53
+ initial_layout
54
+ });
51
55
  $:
52
56
  components, layout, dependencies, root, app, fill_height, target, run();
53
57
  $: {
@@ -203,11 +207,13 @@ export function add_new_message(title2, message, type) {
203
207
  messages = [new_message(title2, message, -1, type), ...messages];
204
208
  }
205
209
  let _error_id = -1;
206
- let user_left_page = false;
207
210
  const MESSAGE_QUOTE_RE = /^'([^]+)'$/;
208
211
  const DUPLICATE_MESSAGE = $_("blocks.long_requests_queue");
209
212
  const MOBILE_QUEUE_WARNING = $_("blocks.connection_can_break");
210
- const MOBILE_RECONNECT_MESSAGE = $_("blocks.lost_connection");
213
+ const LOST_CONNECTION_MESSAGE = "Connection to the server was lost. Attempting reconnection...";
214
+ const CHANGED_CONNECTION_MESSAGE = "Reconnected to server, but the server has changed. You may need to <a href=''>refresh the page</a>.";
215
+ const RECONNECTION_MESSAGE = "Connection re-established.";
216
+ const SESSION_NOT_FOUND_MESSAGE = "Session not found - this is likely because the machine you were connected to has changed. <a href=''>Refresh the page</a> to continue.";
211
217
  const WAITING_FOR_INPUTS_MESSAGE = $_("blocks.waiting_for_inputs");
212
218
  const SHOW_DUPLICATE_MESSAGE_ON_ETA = 15;
213
219
  const SHOW_MOBILE_QUEUE_WARNING_ON_ETA = 10;
@@ -322,6 +328,42 @@ async function trigger_api_call(dep_index, trigger_id = null, event_data = null)
322
328
  }
323
329
  }
324
330
  }
331
+ async function reconnect() {
332
+ const connection_status = await app.reconnect();
333
+ if (connection_status === "broken") {
334
+ setTimeout(reconnect, 1e3);
335
+ } else if (connection_status === "changed") {
336
+ broken_connection = false;
337
+ messages = [
338
+ new_message(
339
+ "Changed Connection",
340
+ CHANGED_CONNECTION_MESSAGE,
341
+ -1,
342
+ "info",
343
+ 3,
344
+ true
345
+ ),
346
+ ...messages.map(
347
+ (m) => m.message === LOST_CONNECTION_MESSAGE ? { ...m, visible: false } : m
348
+ )
349
+ ];
350
+ } else if (connection_status === "connected") {
351
+ broken_connection = false;
352
+ messages = [
353
+ new_message(
354
+ "Reconnected",
355
+ RECONNECTION_MESSAGE,
356
+ -1,
357
+ "success",
358
+ null,
359
+ true
360
+ ),
361
+ ...messages.map(
362
+ (m) => m.message === LOST_CONNECTION_MESSAGE ? { ...m, visible: false } : m
363
+ )
364
+ ];
365
+ }
366
+ }
325
367
  async function make_prediction(payload2, streaming = false) {
326
368
  if (allow_video_trim) {
327
369
  screen_recorder.markRemoveSegmentStart();
@@ -439,6 +481,34 @@ async function trigger_api_call(dep_index, trigger_id = null, event_data = null)
439
481
  }
440
482
  }
441
483
  function handle_status_update(message) {
484
+ if (message.broken && !broken_connection) {
485
+ messages = [
486
+ new_message(
487
+ "Broken Connection",
488
+ LOST_CONNECTION_MESSAGE,
489
+ -1,
490
+ "error",
491
+ null,
492
+ true
493
+ ),
494
+ ...messages
495
+ ];
496
+ broken_connection = true;
497
+ setTimeout(reconnect, 1e3);
498
+ }
499
+ if (message.session_not_found) {
500
+ messages = [
501
+ new_message(
502
+ "Session Not Found",
503
+ SESSION_NOT_FOUND_MESSAGE,
504
+ -1,
505
+ "error",
506
+ null,
507
+ true
508
+ ),
509
+ ...messages
510
+ ];
511
+ }
442
512
  const { fn_index, ...status } = message;
443
513
  if (status.stage === "streaming" && status.time_limit) {
444
514
  dep.inputs.forEach((id) => {
@@ -492,16 +562,7 @@ async function trigger_api_call(dep_index, trigger_id = null, event_data = null)
492
562
  });
493
563
  submit_map.delete(dep_index);
494
564
  }
495
- if (status.broken && is_mobile_device && user_left_page) {
496
- window.setTimeout(() => {
497
- messages = [
498
- new_message("Error", MOBILE_RECONNECT_MESSAGE, fn_index, "error"),
499
- ...messages
500
- ];
501
- }, 0);
502
- wait_then_trigger_api_call(dep.id, payload2.trigger_id, event_data);
503
- user_left_page = false;
504
- } else if (status.stage === "error") {
565
+ if (status.stage === "error" && !broken_connection && !message.session_not_found) {
505
566
  if (status.message) {
506
567
  const _message = status.message.replace(
507
568
  MESSAGE_QUOTE_RE,
@@ -616,6 +677,14 @@ async function handle_mount() {
616
677
  });
617
678
  render_complete = true;
618
679
  }
680
+ value_change((id, value) => {
681
+ const deps = $targets[id]?.["change"];
682
+ deps?.forEach((dep_id) => {
683
+ requestAnimationFrame(() => {
684
+ wait_then_trigger_api_call(dep_id, id, value);
685
+ });
686
+ });
687
+ });
619
688
  const handle_load_triggers = () => {
620
689
  dependencies.forEach((dep) => {
621
690
  if (dep.targets.some((dep2) => dep2[1] === "load")) {
@@ -672,11 +741,6 @@ function isCustomEvent(event) {
672
741
  }
673
742
  let is_screen_recording = writable(false);
674
743
  onMount(() => {
675
- document.addEventListener("visibilitychange", function() {
676
- if (document.visibilityState === "hidden") {
677
- user_left_page = true;
678
- }
679
- });
680
744
  is_mobile_device = /Android|webOS|iPhone|iPad|iPod|BlackBerry|IEMobile|Opera Mini/i.test(
681
745
  navigator.userAgent
682
746
  );
@@ -65,6 +65,7 @@ $:
65
65
  {elem_id}
66
66
  {elem_classes}
67
67
  {target}
68
+ {visible}
68
69
  {...$$restProps}
69
70
  {theme_mode}
70
71
  {root}
@@ -35,6 +35,18 @@ if (!root.endsWith("/")) {
35
35
  }
36
36
  export let api_calls = [];
37
37
  let current_language = "python";
38
+ function set_query_param(key, value) {
39
+ const url = new URL(window.location.href);
40
+ url.searchParams.set(key, value);
41
+ history.replaceState(null, "", url.toString());
42
+ }
43
+ function get_query_param(key) {
44
+ const url = new URL(window.location.href);
45
+ return url.searchParams.get(key);
46
+ }
47
+ function is_valid_language(lang) {
48
+ return ["python", "javascript", "bash", "mcp"].includes(lang ?? "");
49
+ }
38
50
  const langs = [
39
51
  ["python", "Python", python],
40
52
  ["javascript", "JavaScript", javascript],
@@ -65,16 +77,83 @@ get_js_info().then((js_api_info) => {
65
77
  const dispatch = createEventDispatcher();
66
78
  const mcp_server_url = `${root}gradio_api/mcp/sse`;
67
79
  let tools = [];
80
+ let headers = [];
81
+ let mcp_json_sse;
82
+ let mcp_json_stdio;
83
+ let file_data_present = false;
84
+ const upload_file_mcp_server = {
85
+ command: "uvx",
86
+ args: [
87
+ "--from",
88
+ "gradio[mcp]",
89
+ "gradio",
90
+ "upload-mcp",
91
+ root,
92
+ "<UPLOAD_DIRECTORY>"
93
+ ]
94
+ };
68
95
  async function fetchMcpTools() {
69
96
  try {
70
97
  const response = await fetch(`${root}gradio_api/mcp/schema`);
71
98
  const schema = await response.json();
99
+ file_data_present = schema.map((tool) => tool.meta?.file_data_present).some((present) => present);
72
100
  tools = schema.map((tool) => ({
73
101
  name: tool.name,
74
102
  description: tool.description || "",
75
103
  parameters: tool.inputSchema?.properties || {},
76
104
  expanded: false
77
105
  }));
106
+ headers = schema.map((tool) => tool.meta?.headers || []).flat();
107
+ if (headers.length > 0) {
108
+ mcp_json_sse = {
109
+ mcpServers: {
110
+ gradio: {
111
+ url: mcp_server_url,
112
+ headers: headers.reduce((accumulator, current_key) => {
113
+ accumulator[current_key] = "<YOUR_HEADER_VALUE>";
114
+ return accumulator;
115
+ }, {})
116
+ }
117
+ }
118
+ };
119
+ mcp_json_stdio = {
120
+ mcpServers: {
121
+ gradio: {
122
+ command: "npx",
123
+ args: [
124
+ "mcp-remote",
125
+ mcp_server_url,
126
+ "--transport",
127
+ "sse-only",
128
+ ...headers.map((header) => [
129
+ "--header",
130
+ `${header}: <YOUR_HEADER_VALUE>`
131
+ ]).flat()
132
+ ]
133
+ }
134
+ }
135
+ };
136
+ } else {
137
+ mcp_json_sse = {
138
+ mcpServers: {
139
+ gradio: {
140
+ url: mcp_server_url
141
+ }
142
+ }
143
+ };
144
+ mcp_json_stdio = {
145
+ mcpServers: {
146
+ gradio: {
147
+ command: "npx",
148
+ args: ["mcp-remote", mcp_server_url, "--transport", "sse-only"]
149
+ }
150
+ }
151
+ };
152
+ if (file_data_present) {
153
+ mcp_json_sse.mcpServers.upload_files_to_gradio = upload_file_mcp_server;
154
+ mcp_json_stdio.mcpServers.upload_files_to_gradio = upload_file_mcp_server;
155
+ }
156
+ }
78
157
  } catch (error) {
79
158
  console.error("Failed to fetch MCP tools:", error);
80
159
  tools = [];
@@ -85,10 +164,21 @@ onMount(() => {
85
164
  if ("parentIFrame" in window) {
86
165
  window.parentIFrame?.scrollTo(0, 0);
87
166
  }
167
+ const lang_param = get_query_param("lang");
168
+ if (is_valid_language(lang_param)) {
169
+ current_language = lang_param;
170
+ }
88
171
  fetch(mcp_server_url).then((response) => {
89
172
  mcp_server_active = response.ok;
90
173
  if (mcp_server_active) {
91
174
  fetchMcpTools();
175
+ if (!is_valid_language(lang_param)) {
176
+ current_language = "mcp";
177
+ }
178
+ } else {
179
+ if (!is_valid_language(lang_param)) {
180
+ current_language = "python";
181
+ }
92
182
  }
93
183
  }).catch(() => {
94
184
  mcp_server_active = false;
@@ -122,7 +212,10 @@ onMount(() => {
122
212
  <li
123
213
  class="snippet
124
214
  {current_language === language ? 'current-lang' : 'inactive-lang'}"
125
- on:click={() => (current_language = language)}
215
+ on:click={() => {
216
+ current_language = language;
217
+ set_query_param("lang", language);
218
+ }}
126
219
  >
127
220
  <img src={img} alt="" />
128
221
  {display_name}
@@ -180,7 +273,7 @@ onMount(() => {
180
273
  <div class="mcp-url">
181
274
  <label
182
275
  ><span class="status-indicator active">●</span>MCP Server
183
- URL</label
276
+ URL (SSE)</label
184
277
  >
185
278
  <div class="textbox">
186
279
  <input type="text" readonly value={mcp_server_url} />
@@ -239,45 +332,42 @@ onMount(() => {
239
332
  </div>
240
333
  <p>&nbsp;</p>
241
334
 
242
- <strong>Integration</strong>: To add this MCP to clients that
335
+ <strong>SSE Transport</strong>: To add this MCP to clients that
243
336
  support SSE (e.g. Cursor, Windsurf, Cline), simply add the
244
- following configuration to your MCP config:
337
+ following configuration to your MCP config.
245
338
  <p>&nbsp;</p>
246
339
  <Block>
247
340
  <code>
248
341
  <div class="copy">
249
342
  <CopyButton
250
- code={JSON.stringify(
251
- {
252
- mcpServers: {
253
- gradio: {
254
- url: mcp_server_url
255
- }
256
- }
257
- },
258
- null,
259
- 2
260
- )}
343
+ code={JSON.stringify(mcp_json_sse, null, 2)}
261
344
  />
262
345
  </div>
263
346
  <div>
264
- <pre>{JSON.stringify(
265
- {
266
- mcpServers: {
267
- gradio: {
268
- url: mcp_server_url
269
- }
270
- }
271
- },
272
- null,
273
- 2
274
- )}</pre>
347
+ <pre>{JSON.stringify(mcp_json_sse, null, 2)}</pre>
275
348
  </div>
276
349
  </code>
277
350
  </Block>
278
- <p>&nbsp;</p>
279
- <em>Experimental stdio support</em>: For clients that only
280
- support stdio, first
351
+ {#if file_data_present}
352
+ <p>&nbsp;</p>
353
+ <em>Note about files</em>: Gradio MCP servers that have files
354
+ as inputs need the files as URLs, so the
355
+ <code>upload_files_to_gradio</code>
356
+ tool is included for your convenience. This tool can upload files
357
+ located in the specified <code>UPLOAD_DIRECTORY</code>
358
+ argument (an absolute path in your local machine) or any of its
359
+ subdirectories to the Gradio app. You can omit this tool if you
360
+ are fine manually uploading files yourself and providing the URLs.
361
+ Before using this tool, you must have
362
+ <a
363
+ href="https://docs.astral.sh/uv/getting-started/installation/"
364
+ target="_blank">uv installed</a
365
+ >.
366
+ <p>&nbsp;</p>
367
+ {/if}
368
+
369
+ <strong>STDIO Transport</strong>: For clients that only support
370
+ stdio (e.g. Claude Desktop), first
281
371
  <a href="https://nodejs.org/en/download/" target="_blank"
282
372
  >install Node.js</a
283
373
  >. Then, you can use the following command:
@@ -286,43 +376,11 @@ onMount(() => {
286
376
  <code>
287
377
  <div class="copy">
288
378
  <CopyButton
289
- code={JSON.stringify(
290
- {
291
- mcpServers: {
292
- gradio: {
293
- command: "npx",
294
- args: [
295
- "mcp-remote",
296
- mcp_server_url,
297
- "--transport",
298
- "sse-only"
299
- ]
300
- }
301
- }
302
- },
303
- null,
304
- 2
305
- )}
379
+ code={JSON.stringify(mcp_json_stdio, null, 2)}
306
380
  />
307
381
  </div>
308
382
  <div>
309
- <pre>{JSON.stringify(
310
- {
311
- mcpServers: {
312
- gradio: {
313
- command: "npx",
314
- args: [
315
- "mcp-remote",
316
- mcp_server_url,
317
- "--transport",
318
- "sse-only"
319
- ]
320
- }
321
- }
322
- },
323
- null,
324
- 2
325
- )}</pre>
383
+ <pre>{JSON.stringify(mcp_json_stdio, null, 2)}</pre>
326
384
  </div>
327
385
  </code>
328
386
  </Block>
@@ -398,21 +456,22 @@ onMount(() => {
398
456
  {/if}
399
457
 
400
458
  {#if current_language !== "mcp"}
401
- {#each dependencies as dependency, dependency_index}
459
+ {#each dependencies as dependency}
402
460
  {#if dependency.show_api && info.named_endpoints["/" + dependency.api_name]}
403
461
  <div class="endpoint-container">
404
462
  <CodeSnippet
405
- named={true}
406
463
  endpoint_parameters={info.named_endpoints[
407
464
  "/" + dependency.api_name
408
465
  ].parameters}
409
466
  {dependency}
410
- {dependency_index}
411
467
  {current_language}
412
468
  {root}
413
469
  {space_id}
414
470
  {username}
415
471
  api_prefix={app.api_prefix}
472
+ api_description={info.named_endpoints[
473
+ "/" + dependency.api_name
474
+ ].description}
416
475
  />
417
476
 
418
477
  <ParametersSnippet
@@ -3,14 +3,13 @@ import { represent_value, is_potentially_nested_file_data } from "./utils";
3
3
  import { Block } from "@gradio/atoms";
4
4
  import EndpointDetail from "./EndpointDetail.svelte";
5
5
  export let dependency;
6
- export let dependency_index;
7
6
  export let root;
8
7
  export let api_prefix;
9
8
  export let space_id;
10
9
  export let endpoint_parameters;
11
- export let named;
12
10
  export let username;
13
11
  export let current_language;
12
+ export let api_description = null;
14
13
  let python_code;
15
14
  let js_code;
16
15
  let bash_post_code;
@@ -29,11 +28,10 @@ $:
29
28
  </script>
30
29
 
31
30
  <div class="container">
32
- {#if named}
33
- <EndpointDetail {named} api_name={dependency.api_name} />
34
- {:else}
35
- <EndpointDetail {named} fn_index={dependency_index} />
36
- {/if}
31
+ <EndpointDetail
32
+ api_name={dependency.api_name}
33
+ description={api_description}
34
+ />
37
35
  {#if current_language === "python"}
38
36
  <Block>
39
37
  <code>
@@ -86,9 +84,9 @@ const example{component} = await response_{i}.blob();
86
84
  const client = await Client.connect(<span class="token string"
87
85
  >"{space_id || root}"</span
88
86
  >{#if username !== null}, &lbrace;auth: ["{username}", **password**]&rbrace;{/if});
89
- const result = await client.predict({#if named}<span class="api-name"
90
- >"/{dependency.api_name}"</span
91
- >{:else}{dependency_index}{/if}, &lbrace; <!--
87
+ const result = await client.predict(<span class="api-name"
88
+ >"/{dependency.api_name}"</span
89
+ >, &lbrace; <!--
92
90
  -->{#each endpoint_parameters as { label, parameter_name, type, python_type, component, example_input, serializer }, i}<!--
93
91
  -->{#if blob_components.includes(component)}<!--
94
92
  -->
@@ -3,14 +3,13 @@ import type { Dependency } from "../types";
3
3
  declare const __propDef: {
4
4
  props: {
5
5
  dependency: Dependency;
6
- dependency_index: number;
7
6
  root: string;
8
7
  api_prefix: string;
9
8
  space_id: string | null;
10
9
  endpoint_parameters: any;
11
- named: boolean;
12
10
  username: string | null;
13
11
  current_language: "python" | "javascript" | "bash";
12
+ api_description?: (string | null) | undefined;
14
13
  };
15
14
  events: {
16
15
  [evt: string]: CustomEvent<any>;
@@ -1,19 +1,12 @@
1
1
  <script>export let api_name = null;
2
- export let fn_index = null;
3
- export let named;
2
+ export let description = null;
4
3
  </script>
5
4
 
6
- {#if named}
7
- <h3>
8
- api_name:
9
- <span class="post">{"/" + api_name}</span>
10
- </h3>
11
- {:else}
12
- <h3>
13
- fn_index:
14
- <span class="post">{fn_index}</span>
15
- </h3>
16
- {/if}
5
+ <h3>
6
+ API name:
7
+ <span class="post">{"/" + api_name}</span>
8
+ <span class="desc">{description}</span>
9
+ </h3>
17
10
 
18
11
  <style>
19
12
  h3 {
@@ -33,4 +26,10 @@ export let named;
33
26
  color: var(--color-accent);
34
27
  font-weight: var(--weight-semibold);
35
28
  }
29
+
30
+ .desc {
31
+ color: var(--body-text-color-subdued);
32
+ font-size: var(--text-lg);
33
+ margin-top: var(--size-1);
34
+ }
36
35
  </style>
@@ -2,8 +2,7 @@ import { SvelteComponent } from "svelte";
2
2
  declare const __propDef: {
3
3
  props: {
4
4
  api_name?: (string | null) | undefined;
5
- fn_index?: (number | null) | undefined;
6
- named: boolean;
5
+ description?: (string | null) | undefined;
7
6
  };
8
7
  events: {
9
8
  [evt: string]: CustomEvent<any>;
@@ -7,7 +7,13 @@ export interface UpdateTransaction {
7
7
  value: any;
8
8
  prop: string;
9
9
  }
10
- export declare function create_components(initial_layout: ComponentMeta | undefined): {
10
+ /**
11
+ * Create a store with the layout and a map of targets
12
+ * @returns A store with the layout and a map of targets
13
+ */
14
+ export declare function create_components({ initial_layout }?: {
15
+ initial_layout: ComponentMeta | undefined;
16
+ }): {
11
17
  layout: Writable<ComponentMeta>;
12
18
  targets: Writable<TargetMap>;
13
19
  update_value: (updates: UpdateTransaction[]) => void;
@@ -34,6 +40,7 @@ export declare function create_components(initial_layout: ComponentMeta | undefi
34
40
  root: string;
35
41
  dependencies: Dependency[];
36
42
  }) => void;
43
+ value_change: (cb: (id: number, value: any) => void) => void;
37
44
  };
38
45
  /** An async version of 'new Function' */
39
46
  export declare const AsyncFunction: new (...args: string[]) => (...args: any[]) => Promise<any>;