@gradio/core 0.20.0 → 0.21.0

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/dist/src/init.js CHANGED
@@ -26,6 +26,9 @@ export function create_components(initial_layout) {
26
26
  let app;
27
27
  let keys_per_render_id = {};
28
28
  let _rootNode;
29
+ // Store current layout and root for dynamic visibility recalculation
30
+ let current_layout;
31
+ let current_root;
29
32
  function set_event_specific_args(dependencies) {
30
33
  dependencies.forEach((dep) => {
31
34
  dep.targets.forEach((target) => {
@@ -57,6 +60,9 @@ export function create_components(initial_layout) {
57
60
  constructor_map = new Map();
58
61
  _component_map = new Map();
59
62
  instance_map = {};
63
+ // Store current layout and root for dynamic visibility recalculation
64
+ current_layout = layout;
65
+ current_root = root;
60
66
  _rootNode = {
61
67
  id: layout.id,
62
68
  type: "column",
@@ -75,7 +81,7 @@ export function create_components(initial_layout) {
75
81
  get_inputs_outputs(dep, inputs, outputs);
76
82
  });
77
83
  target_map.set(_target_map);
78
- constructor_map = preload_all_components(components, root);
84
+ constructor_map = preload_visible_components(components, layout, root);
79
85
  instance_map = components.reduce((acc, c) => {
80
86
  acc[c.id] = c;
81
87
  return acc;
@@ -88,6 +94,9 @@ export function create_components(initial_layout) {
88
94
  * Rerender the layout when the config has been modified to attach new components
89
95
  */
90
96
  function rerender_layout({ render_id, components, layout, root, dependencies }) {
97
+ // Update current layout and root for dynamic visibility recalculation
98
+ current_layout = layout;
99
+ current_root = root;
91
100
  components.forEach((c) => {
92
101
  for (const prop in c.props) {
93
102
  if (c.props[prop] === null) {
@@ -105,7 +114,7 @@ export function create_components(initial_layout) {
105
114
  replacement_components.push(c);
106
115
  }
107
116
  });
108
- let _constructor_map = preload_all_components(new_components, root);
117
+ let _constructor_map = preload_visible_components(new_components, layout, root);
109
118
  _constructor_map.forEach((v, k) => {
110
119
  constructor_map.set(k, v);
111
120
  });
@@ -167,9 +176,19 @@ export function create_components(initial_layout) {
167
176
  async function walk_layout(node, root, components, parent) {
168
177
  const instance = instance_map[node.id];
169
178
  if (!instance.component) {
170
- instance.component = (await constructor_map.get(instance.component_class_id || instance.type))?.default;
179
+ const constructor_key = instance.component_class_id || instance.type;
180
+ let component_constructor = constructor_map.get(constructor_key);
181
+ // Only load component if it was preloaded (i.e., it's visible)
182
+ if (component_constructor) {
183
+ instance.component = (await component_constructor)?.default;
184
+ }
185
+ // If component wasn't preloaded, leave it unloaded for now
186
+ // It will be loaded later when/if it becomes visible
171
187
  }
172
188
  instance.parent = parent;
189
+ // if (instance.type === "timer") {
190
+ // console.log("timer", instance, constructor_map);
191
+ // }
173
192
  if (instance.type === "dataset") {
174
193
  instance.props.component_map = get_component(instance.type, instance.component_class_id, root, components, instance.props.components).example_components;
175
194
  }
@@ -199,7 +218,7 @@ export function create_components(initial_layout) {
199
218
  instance.props.initial_tabs = child_tab_items?.map((child) => ({
200
219
  label: child.props.label,
201
220
  id: child.props.id,
202
- visible: child.props.visible,
221
+ visible: typeof child.props.visible === "boolean" ? child.props.visible : true,
203
222
  interactive: child.props.interactive,
204
223
  order: child.props.order
205
224
  }));
@@ -214,7 +233,63 @@ export function create_components(initial_layout) {
214
233
  }
215
234
  let update_scheduled = false;
216
235
  let update_scheduled_store = writable(false);
236
+ /**
237
+ * Load newly visible components after visibility changes
238
+ * @param newly_visible_ids Set of component IDs that are now visible
239
+ */
240
+ async function load_newly_visible_components(newly_visible_ids) {
241
+ if (newly_visible_ids.size === 0)
242
+ return;
243
+ const components_to_load = _components.filter((c) => newly_visible_ids.has(c.id));
244
+ for (const component of components_to_load) {
245
+ const constructor_key = component.component_class_id || component.type;
246
+ // Only load if not already loaded
247
+ if (!constructor_map.has(constructor_key)) {
248
+ const { component: loadable_component, example_components } = get_component(component.type, component.component_class_id, current_root, _components);
249
+ constructor_map.set(constructor_key, loadable_component);
250
+ if (example_components) {
251
+ for (const [name, example_component] of example_components) {
252
+ constructor_map.set(name, example_component);
253
+ }
254
+ }
255
+ // Load the component if it doesn't exist yet
256
+ if (!component.component) {
257
+ component.component = (await loadable_component)?.default;
258
+ }
259
+ }
260
+ else {
261
+ component.component =
262
+ (await constructor_map.get(constructor_key))?.default ??
263
+ component.component;
264
+ }
265
+ }
266
+ }
267
+ /**
268
+ * Check if any visibility-affecting properties have changed
269
+ * @param updates Array of update transactions
270
+ * @returns True if visibility might have changed
271
+ */
272
+ function has_visibility_changes(updates) {
273
+ return updates.some((update_batch) => update_batch.some((update) => {
274
+ const instance = instance_map[update.id];
275
+ if (!instance)
276
+ return false;
277
+ // Check for visibility property changes
278
+ if (update.prop === "visible")
279
+ return true;
280
+ // Check for selected tab changes in tabs components
281
+ if (update.prop === "selected" && instance.type === "tabs")
282
+ return true;
283
+ return false;
284
+ }));
285
+ }
217
286
  function flush() {
287
+ const had_visibility_changes = has_visibility_changes(pending_updates);
288
+ let previous_visible_ids;
289
+ // Capture current visibility state before applying updates
290
+ if (had_visibility_changes && current_layout) {
291
+ previous_visible_ids = determine_visible_components(current_layout, _components);
292
+ }
218
293
  layout_store.update((layout) => {
219
294
  for (let i = 0; i < pending_updates.length; i++) {
220
295
  for (let j = 0; j < pending_updates[i].length; j++) {
@@ -242,6 +317,25 @@ export function create_components(initial_layout) {
242
317
  }
243
318
  return layout;
244
319
  });
320
+ // After applying updates, check if we need to load new components
321
+ if (had_visibility_changes && current_layout && previous_visible_ids) {
322
+ raf(async () => {
323
+ const new_visible_ids = determine_visible_components(current_layout, _components);
324
+ const newly_visible_ids = new Set();
325
+ // Find components that are now visible but weren't before
326
+ for (const id of new_visible_ids) {
327
+ if (!previous_visible_ids.has(id)) {
328
+ newly_visible_ids.add(id);
329
+ }
330
+ }
331
+ // Load the newly visible components
332
+ await load_newly_visible_components(newly_visible_ids);
333
+ // Trigger a layout update to render the newly loaded components
334
+ if (newly_visible_ids.size > 0) {
335
+ layout_store.update((layout) => layout);
336
+ }
337
+ });
338
+ }
245
339
  pending_updates = [];
246
340
  update_scheduled = false;
247
341
  update_scheduled_store.set(false);
@@ -475,7 +569,141 @@ export function get_component(type, class_id, root, components, example_componen
475
569
  };
476
570
  }
477
571
  /**
478
- * Preload all components
572
+ * Check if a tab item should be visible based on selection state
573
+ * @param component The tab item component
574
+ * @param component_visible Whether the component is visible
575
+ * @param parent_tabs_context Tab context from parent
576
+ * @returns Whether the tab item should be visible
577
+ */
578
+ function is_tab_item_visible(component, component_visible, parent_tabs_context) {
579
+ const is_selected_tab = parent_tabs_context?.selected_tab_id === component.id ||
580
+ parent_tabs_context?.selected_tab_id === component.props.id;
581
+ return component_visible && is_selected_tab;
582
+ }
583
+ /**
584
+ * Determine the selected tab ID for a tabs component
585
+ * @param component The tabs component
586
+ * @param layout The layout node
587
+ * @param components All components
588
+ * @returns The selected tab ID
589
+ */
590
+ function get_selected_tab_id(component, layout, components) {
591
+ // Check if selected prop is a string or number
592
+ const selected = component.props.selected;
593
+ if (typeof selected === "string" || typeof selected === "number") {
594
+ return selected;
595
+ }
596
+ // If no tab is explicitly selected, find the first visible and interactive tab
597
+ if (layout.children) {
598
+ for (const child of layout.children) {
599
+ const child_component = components.find((c) => c.id === child.id);
600
+ if (child_component?.type === "tabitem" &&
601
+ child_component.props.visible !== false &&
602
+ child_component.props.interactive !== false) {
603
+ return (child_component.id || child_component.props.id);
604
+ }
605
+ }
606
+ }
607
+ return undefined;
608
+ }
609
+ /**
610
+ * Process children components for visibility
611
+ * @param layout The layout node
612
+ * @param components All components
613
+ * @param parent_tabs_context Tab context
614
+ * @returns Set of visible child component IDs
615
+ */
616
+ function process_children_visibility(layout, components, parent_tabs_context) {
617
+ const visible_components = new Set();
618
+ if (layout.children) {
619
+ for (const child of layout.children) {
620
+ const child_visible = determine_visible_components(child, components, true, parent_tabs_context);
621
+ child_visible.forEach((id) => visible_components.add(id));
622
+ }
623
+ }
624
+ return visible_components;
625
+ }
626
+ /**
627
+ * Determine which components should be visible based on layout structure and visibility rules
628
+ * @param layout The layout tree
629
+ * @param components All component metadata
630
+ * @param parent_visible Whether the parent component is visible
631
+ * @param parent_tabs_context Information about parent tabs if any
632
+ * @returns Set of component IDs that should be visible
633
+ */
634
+ function determine_visible_components(layout, components, parent_visible = true, parent_tabs_context) {
635
+ const visible_components = new Set();
636
+ const component = components.find((c) => c.id === layout.id);
637
+ if (!component) {
638
+ return visible_components;
639
+ }
640
+ // Check if the component itself is visible
641
+ const component_visible = parent_visible &&
642
+ (typeof component.props.visible === "boolean"
643
+ ? component.props.visible
644
+ : true);
645
+ // Handle tab_item special case
646
+ if (component.type === "tabitem") {
647
+ if (is_tab_item_visible(component, component_visible, parent_tabs_context)) {
648
+ visible_components.add(component.id);
649
+ // Process children if this tab item is visible
650
+ const child_visible = process_children_visibility(layout, components, parent_tabs_context);
651
+ child_visible.forEach((id) => visible_components.add(id));
652
+ }
653
+ // If tab item is not visible, none of its children should be loaded
654
+ return visible_components;
655
+ }
656
+ // Handle tabs component
657
+ if (component.type === "tabs") {
658
+ if (component_visible) {
659
+ visible_components.add(component.id);
660
+ // Determine which tab should be selected
661
+ const selected_tab_id = get_selected_tab_id(component, layout, components);
662
+ // Process children with tabs context
663
+ const child_visible = process_children_visibility(layout, components, {
664
+ selected_tab_id
665
+ });
666
+ child_visible.forEach((id) => visible_components.add(id));
667
+ }
668
+ return visible_components;
669
+ }
670
+ // For regular components
671
+ if (component_visible) {
672
+ visible_components.add(component.id);
673
+ // Process children if this component is visible
674
+ const child_visible = process_children_visibility(layout, components, parent_tabs_context);
675
+ child_visible.forEach((id) => visible_components.add(id));
676
+ }
677
+ // If component is not visible, don't process children
678
+ return visible_components;
679
+ }
680
+ /**
681
+ * Preload only visible components
682
+ * @param components A list of component metadata
683
+ * @param layout The layout tree to determine visibility
684
+ * @param root The root url of the app
685
+ * @returns A map of component ids to their constructors
686
+ */
687
+ export function preload_visible_components(components, layout, root) {
688
+ let constructor_map = new Map();
689
+ // Determine which components should be visible
690
+ const visible_component_ids = determine_visible_components(layout, components);
691
+ // Only preload visible components
692
+ components.forEach((c) => {
693
+ if (visible_component_ids.has(c.id)) {
694
+ const { component, example_components } = get_component(c.type, c.component_class_id, root, components);
695
+ constructor_map.set(c.component_class_id || c.type, component);
696
+ if (example_components) {
697
+ for (const [name, example_component] of example_components) {
698
+ constructor_map.set(name, example_component);
699
+ }
700
+ }
701
+ }
702
+ });
703
+ return constructor_map;
704
+ }
705
+ /**
706
+ * Preload all components (legacy function, kept for backwards compatibility)
479
707
  * @param components A list of component metadata
480
708
  * @param root The root url of the app
481
709
  * @returns A map of component ids to their constructors
@@ -0,0 +1 @@
1
+ export {};
@@ -0,0 +1,23 @@
1
+ //@ts-nocheck
2
+ import fs from "fs";
3
+ import path from "path";
4
+ import { fileURLToPath } from "url";
5
+
6
+ const __filename = fileURLToPath(import.meta.url);
7
+ const __dirname = path.dirname(__filename);
8
+
9
+ const langs = fs.readdirSync(path.join(__dirname, "..", "lang"));
10
+
11
+ let lang_names = {};
12
+ for (const lang of langs) {
13
+ if (lang.endsWith(".json")) {
14
+ const lang_text = fs.readFileSync(
15
+ path.join(__dirname, "..", "lang", lang),
16
+ "utf8"
17
+ );
18
+ const lang_data = JSON.parse(lang_text.trim());
19
+ lang_names[lang.split(".")[0]] = lang_data._name;
20
+ }
21
+ }
22
+
23
+ console.log(lang_names);
package/package.json CHANGED
@@ -1,68 +1,68 @@
1
1
  {
2
2
  "name": "@gradio/core",
3
- "version": "0.20.0",
3
+ "version": "0.21.0",
4
4
  "type": "module",
5
5
  "devDependencies": {
6
- "@gradio/accordion": "^0.5.18",
7
- "@gradio/annotatedimage": "^0.9.23",
8
- "@gradio/audio": "^0.17.19",
9
- "@gradio/box": "^0.2.20",
10
- "@gradio/button": "^0.5.5",
11
- "@gradio/atoms": "^0.16.2",
12
- "@gradio/chatbot": "^0.26.16",
13
- "@gradio/checkbox": "^0.4.24",
14
- "@gradio/client": "^1.15.4",
15
- "@gradio/checkboxgroup": "^0.6.23",
16
- "@gradio/code": "^0.14.9",
17
- "@gradio/colorpicker": "^0.4.23",
18
- "@gradio/dataset": "^0.4.25",
19
- "@gradio/dataframe": "^0.18.0",
20
- "@gradio/datetime": "^0.3.16",
21
- "@gradio/downloadbutton": "^0.4.5",
6
+ "@gradio/accordion": "^0.5.19",
7
+ "@gradio/atoms": "^0.16.3",
8
+ "@gradio/audio": "^0.17.20",
9
+ "@gradio/box": "^0.2.21",
10
+ "@gradio/annotatedimage": "^0.9.24",
11
+ "@gradio/button": "^0.5.6",
12
+ "@gradio/chatbot": "^0.26.17",
13
+ "@gradio/checkbox": "^0.4.25",
14
+ "@gradio/checkboxgroup": "^0.6.24",
15
+ "@gradio/client": "^1.15.5",
16
+ "@gradio/colorpicker": "^0.4.24",
17
+ "@gradio/code": "^0.14.10",
22
18
  "@gradio/column": "^0.2.1",
23
- "@gradio/dropdown": "^0.9.23",
24
- "@gradio/file": "^0.12.22",
25
- "@gradio/fileexplorer": "^0.5.33",
26
- "@gradio/fallback": "^0.4.23",
27
- "@gradio/form": "^0.2.20",
19
+ "@gradio/dataframe": "^0.18.1",
20
+ "@gradio/dataset": "^0.4.26",
21
+ "@gradio/datetime": "^0.3.17",
22
+ "@gradio/downloadbutton": "^0.4.6",
23
+ "@gradio/dropdown": "^0.9.24",
24
+ "@gradio/fallback": "^0.4.24",
25
+ "@gradio/file": "^0.12.23",
26
+ "@gradio/fileexplorer": "^0.5.34",
27
+ "@gradio/gallery": "^0.15.26",
28
+ "@gradio/form": "^0.2.21",
28
29
  "@gradio/group": "^0.2.0",
29
- "@gradio/highlightedtext": "^0.9.6",
30
- "@gradio/gallery": "^0.15.25",
31
- "@gradio/html": "^0.6.15",
32
30
  "@gradio/icons": "^0.12.0",
33
- "@gradio/image": "^0.22.11",
34
- "@gradio/imageeditor": "^0.15.5",
35
- "@gradio/imageslider": "^0.2.7",
36
- "@gradio/json": "^0.5.25",
37
- "@gradio/label": "^0.5.15",
31
+ "@gradio/highlightedtext": "^0.9.7",
32
+ "@gradio/html": "^0.6.16",
33
+ "@gradio/image": "^0.22.12",
34
+ "@gradio/imageeditor": "^0.16.0",
35
+ "@gradio/imageslider": "^0.2.8",
36
+ "@gradio/label": "^0.5.16",
37
+ "@gradio/json": "^0.5.26",
38
+ "@gradio/markdown": "^0.13.17",
39
+ "@gradio/model3d": "^0.14.19",
38
40
  "@gradio/browserstate": "^0.3.2",
39
- "@gradio/model3d": "^0.14.18",
40
- "@gradio/markdown": "^0.13.16",
41
- "@gradio/multimodaltextbox": "^0.10.11",
42
- "@gradio/nativeplot": "^0.7.0",
43
- "@gradio/paramviewer": "^0.7.11",
44
- "@gradio/number": "^0.6.0",
45
- "@gradio/plot": "^0.9.18",
46
- "@gradio/radio": "^0.7.6",
41
+ "@gradio/multimodaltextbox": "^0.10.12",
42
+ "@gradio/nativeplot": "^0.7.1",
43
+ "@gradio/number": "^0.6.1",
44
+ "@gradio/paramviewer": "^0.7.12",
45
+ "@gradio/plot": "^0.9.19",
47
46
  "@gradio/row": "^0.2.1",
48
- "@gradio/sidebar": "^0.1.16",
49
- "@gradio/simpledropdown": "^0.3.23",
50
- "@gradio/simpletextbox": "^0.3.24",
47
+ "@gradio/radio": "^0.7.7",
48
+ "@gradio/sidebar": "^0.1.17",
49
+ "@gradio/simpleimage": "^0.8.34",
50
+ "@gradio/simpledropdown": "^0.3.24",
51
+ "@gradio/simpletextbox": "^0.3.25",
52
+ "@gradio/sketchbox": "^0.6.12",
53
+ "@gradio/slider": "^0.6.13",
54
+ "@gradio/tabitem": "^0.5.0",
51
55
  "@gradio/state": "^0.1.2",
52
- "@gradio/simpleimage": "^0.8.33",
53
- "@gradio/slider": "^0.6.12",
54
- "@gradio/statustracker": "^0.10.13",
56
+ "@gradio/textbox": "^0.10.16",
55
57
  "@gradio/tabs": "^0.4.5",
56
- "@gradio/tabitem": "^0.4.6",
57
- "@gradio/sketchbox": "^0.6.11",
58
58
  "@gradio/theme": "^0.4.0",
59
- "@gradio/textbox": "^0.10.15",
60
59
  "@gradio/timer": "^0.4.5",
61
- "@gradio/upload": "^0.16.9",
62
- "@gradio/uploadbutton": "^0.9.5",
60
+ "@gradio/upload": "^0.16.10",
61
+ "@gradio/uploadbutton": "^0.9.6",
62
+ "@gradio/statustracker": "^0.10.14",
63
63
  "@gradio/utils": "^0.10.2",
64
- "@gradio/wasm": "^0.18.1",
65
- "@gradio/video": "^0.14.19"
64
+ "@gradio/video": "^0.14.20",
65
+ "@gradio/wasm": "^0.18.1"
66
66
  },
67
67
  "msw": {
68
68
  "workerDirectory": "public"
package/src/Blocks.svelte CHANGED
@@ -9,7 +9,6 @@
9
9
  import type { ComponentMeta, Dependency, LayoutNode } from "./types";
10
10
  import type { UpdateTransaction } from "./init";
11
11
  import { setupi18n } from "./i18n";
12
- import { ApiDocs, ApiRecorder, Settings } from "./api_docs/";
13
12
  import type { ThemeMode, Payload } from "./types";
14
13
  import { Toast } from "@gradio/statustracker";
15
14
  import type { ToastMessage } from "@gradio/statustracker";
@@ -17,6 +16,11 @@
17
16
  import MountComponents from "./MountComponents.svelte";
18
17
  import { prefix_css } from "./css";
19
18
 
19
+ import type ApiDocs from "./api_docs/ApiDocs.svelte";
20
+ import type ApiRecorder from "./api_docs/ApiRecorder.svelte";
21
+ import type Settings from "./api_docs/Settings.svelte";
22
+ import type { ComponentType } from "svelte";
23
+
20
24
  import logo from "./images/logo.svg";
21
25
  import api_logo from "./api_docs/img/api-logo.svg";
22
26
  import settings_logo from "./api_docs/img/settings-logo.svg";
@@ -107,8 +111,39 @@
107
111
  let allow_zoom = true;
108
112
  let allow_video_trim = true;
109
113
 
110
- function set_api_docs_visible(visible: boolean): void {
114
+ // Lazy component loading state
115
+ let ApiDocs: ComponentType<ApiDocs> | null = null;
116
+ let ApiRecorder: ComponentType<ApiRecorder> | null = null;
117
+ let Settings: ComponentType<Settings> | null = null;
118
+
119
+ async function loadApiDocs(): Promise<void> {
120
+ if (!ApiDocs || !ApiRecorder) {
121
+ const api_docs_module = await import("./api_docs/ApiDocs.svelte");
122
+ const api_recorder_module = await import("./api_docs/ApiRecorder.svelte");
123
+ if (!ApiDocs) ApiDocs = api_docs_module.default;
124
+ if (!ApiRecorder) ApiRecorder = api_recorder_module.default;
125
+ }
126
+ }
127
+
128
+ async function loadApiRecorder(): Promise<void> {
129
+ if (!ApiRecorder) {
130
+ const api_recorder_module = await import("./api_docs/ApiRecorder.svelte");
131
+ ApiRecorder = api_recorder_module.default;
132
+ }
133
+ }
134
+
135
+ async function loadSettings(): Promise<void> {
136
+ if (!Settings) {
137
+ const settings_module = await import("./api_docs/Settings.svelte");
138
+ Settings = settings_module.default;
139
+ }
140
+ }
141
+
142
+ async function set_api_docs_visible(visible: boolean): Promise<void> {
111
143
  api_recorder_visible = false;
144
+ if (visible) {
145
+ await loadApiDocs();
146
+ }
112
147
  api_docs_visible = visible;
113
148
  let params = new URLSearchParams(window.location.search);
114
149
  if (visible) {
@@ -119,7 +154,10 @@
119
154
  history.replaceState(null, "", "?" + params.toString());
120
155
  }
121
156
 
122
- function set_settings_visible(visible: boolean): void {
157
+ async function set_settings_visible(visible: boolean): Promise<void> {
158
+ if (visible) {
159
+ await loadSettings();
160
+ }
123
161
  let params = new URLSearchParams(window.location.search);
124
162
  if (visible) {
125
163
  params.set("view", "settings");
@@ -831,6 +869,17 @@
831
869
  $is_screen_recording = isRecording;
832
870
  }
833
871
  );
872
+
873
+ // Load components if they should be visible on initial page load
874
+ if (api_docs_visible) {
875
+ loadApiDocs();
876
+ }
877
+ if (api_recorder_visible) {
878
+ loadApiRecorder();
879
+ }
880
+ if (settings_visible) {
881
+ loadSettings();
882
+ }
834
883
  });
835
884
 
836
885
  function screen_recording(): void {
@@ -840,11 +889,6 @@
840
889
  screen_recorder.startRecording();
841
890
  }
842
891
  }
843
-
844
- let i18n_ready = false;
845
- setupi18n(app.config?.i18n_translations ?? undefined).then(() => {
846
- i18n_ready = true;
847
- });
848
892
  </script>
849
893
 
850
894
  <svelte:head>
@@ -858,7 +902,7 @@
858
902
 
859
903
  <div class="wrap" style:min-height={app_mode ? "100%" : "auto"}>
860
904
  <div class="contain" style:flex-grow={app_mode ? "1" : "auto"}>
861
- {#if $_layout && app.config && i18n_ready}
905
+ {#if $_layout && app.config}
862
906
  <MountComponents
863
907
  rootNode={$_layout}
864
908
  {root}
@@ -880,6 +924,10 @@
880
924
  on:click={() => {
881
925
  set_api_docs_visible(!api_docs_visible);
882
926
  }}
927
+ on:mouseenter={() => {
928
+ loadApiDocs();
929
+ loadApiRecorder();
930
+ }}
883
931
  class="show-api"
884
932
  >
885
933
  {#if app.config?.mcp_server}
@@ -916,6 +964,9 @@
916
964
  on:click={() => {
917
965
  set_settings_visible(!settings_visible);
918
966
  }}
967
+ on:mouseenter={() => {
968
+ loadSettings();
969
+ }}
919
970
  class="settings"
920
971
  >
921
972
  {$_("common.settings")}
@@ -925,7 +976,7 @@
925
976
  {/if}
926
977
  </div>
927
978
 
928
- {#if api_recorder_visible}
979
+ {#if api_recorder_visible && ApiRecorder}
929
980
  <!-- TODO: fix -->
930
981
  <!-- svelte-ignore a11y-click-events-have-key-events-->
931
982
  <!-- svelte-ignore a11y-no-static-element-interactions-->
@@ -936,11 +987,11 @@
936
987
  api_recorder_visible = false;
937
988
  }}
938
989
  >
939
- <ApiRecorder {api_calls} {dependencies} />
990
+ <svelte:component this={ApiRecorder} {api_calls} {dependencies} />
940
991
  </div>
941
992
  {/if}
942
993
 
943
- {#if api_docs_visible && $_layout}
994
+ {#if api_docs_visible && $_layout && ApiDocs}
944
995
  <div class="api-docs">
945
996
  <!-- TODO: fix -->
946
997
  <!-- svelte-ignore a11y-click-events-have-key-events-->
@@ -952,12 +1003,14 @@
952
1003
  }}
953
1004
  />
954
1005
  <div class="api-docs-wrap">
955
- <ApiDocs
1006
+ <svelte:component
1007
+ this={ApiDocs}
956
1008
  root_node={$_layout}
957
1009
  on:close={(event) => {
958
1010
  set_api_docs_visible(false);
959
1011
  api_calls = [];
960
- api_recorder_visible = event.detail?.api_recorder_visible;
1012
+ api_recorder_visible = api_recorder_visible =
1013
+ event.detail?.api_recorder_visible;
961
1014
  }}
962
1015
  {dependencies}
963
1016
  {root}
@@ -970,7 +1023,7 @@
970
1023
  </div>
971
1024
  {/if}
972
1025
 
973
- {#if settings_visible && $_layout && app.config}
1026
+ {#if settings_visible && $_layout && app.config && Settings}
974
1027
  <div class="api-docs">
975
1028
  <!-- TODO: fix -->
976
1029
  <!-- svelte-ignore a11y-click-events-have-key-events-->
@@ -982,13 +1035,14 @@
982
1035
  }}
983
1036
  />
984
1037
  <div class="api-docs-wrap">
985
- <Settings
1038
+ <svelte:component
1039
+ this={Settings}
986
1040
  bind:allow_zoom
987
1041
  bind:allow_video_trim
988
- on:close={(event) => {
1042
+ on:close={() => {
989
1043
  set_settings_visible(false);
990
1044
  }}
991
- on:start_recording={(event) => {
1045
+ on:start_recording={() => {
992
1046
  screen_recording();
993
1047
  }}
994
1048
  pwa_enabled={app.config.pwa}