@gradio/core 0.28.0 → 0.29.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/package.json CHANGED
@@ -1,69 +1,68 @@
1
1
  {
2
2
  "name": "@gradio/core",
3
- "version": "0.28.0",
3
+ "version": "0.29.0",
4
4
  "type": "module",
5
5
  "devDependencies": {
6
- "@gradio/accordion": "^0.5.23",
7
- "@gradio/annotatedimage": "^0.9.30",
8
- "@gradio/atoms": "^0.17.0",
9
- "@gradio/audio": "^0.18.0",
6
+ "@gradio/annotatedimage": "^0.10.0",
7
+ "@gradio/accordion": "^0.5.24",
8
+ "@gradio/atoms": "^0.18.0",
9
+ "@gradio/box": "^0.2.25",
10
10
  "@gradio/browserstate": "^0.3.2",
11
- "@gradio/box": "^0.2.24",
12
- "@gradio/button": "^0.5.12",
13
- "@gradio/chatbot": "^0.26.24",
14
- "@gradio/checkbox": "^0.4.29",
15
- "@gradio/checkboxgroup": "^0.6.28",
16
- "@gradio/client": "^1.18.0",
17
- "@gradio/code": "^0.14.16",
18
- "@gradio/colorpicker": "^0.4.28",
19
- "@gradio/dataframe": "^0.19.2",
20
- "@gradio/dataset": "^0.4.33",
21
- "@gradio/datetime": "^0.3.21",
22
- "@gradio/downloadbutton": "^0.4.11",
23
- "@gradio/dropdown": "^0.10.3",
24
- "@gradio/fallback": "^0.4.28",
25
- "@gradio/column": "^0.2.1",
26
- "@gradio/file": "^0.12.29",
27
- "@gradio/fileexplorer": "^0.5.40",
28
- "@gradio/form": "^0.2.24",
29
- "@gradio/highlightedtext": "^0.9.11",
30
- "@gradio/group": "^0.2.0",
31
- "@gradio/html": "^0.7.1",
32
- "@gradio/gallery": "^0.15.32",
11
+ "@gradio/audio": "^0.19.0",
12
+ "@gradio/button": "^0.5.13",
13
+ "@gradio/chatbot": "^0.27.0",
14
+ "@gradio/checkbox": "^0.4.30",
15
+ "@gradio/checkboxgroup": "^0.7.0",
16
+ "@gradio/code": "^0.15.0",
17
+ "@gradio/colorpicker": "^0.4.29",
18
+ "@gradio/client": "^1.19.0",
19
+ "@gradio/column": "^0.2.2",
20
+ "@gradio/dataset": "^0.4.34",
21
+ "@gradio/downloadbutton": "^0.4.12",
22
+ "@gradio/dataframe": "^0.19.3",
23
+ "@gradio/datetime": "^0.3.22",
24
+ "@gradio/fallback": "^0.4.29",
25
+ "@gradio/dropdown": "^0.10.4",
26
+ "@gradio/file": "^0.13.0",
27
+ "@gradio/fileexplorer": "^0.5.41",
28
+ "@gradio/form": "^0.2.25",
29
+ "@gradio/gallery": "^0.15.33",
30
+ "@gradio/highlightedtext": "^0.9.12",
31
+ "@gradio/group": "^0.2.1",
32
+ "@gradio/html": "^0.7.2",
33
+ "@gradio/image": "^0.23.0",
33
34
  "@gradio/icons": "^0.14.0",
34
- "@gradio/imageeditor": "^0.16.6",
35
- "@gradio/imageslider": "^0.2.14",
36
- "@gradio/image": "^0.22.18",
37
- "@gradio/json": "^0.5.30",
38
- "@gradio/label": "^0.5.20",
39
- "@gradio/multimodaltextbox": "^0.10.18",
40
- "@gradio/nativeplot": "^0.7.5",
41
- "@gradio/model3d": "^0.14.26",
42
- "@gradio/markdown": "^0.13.21",
43
- "@gradio/number": "^0.7.0",
44
- "@gradio/paramviewer": "^0.7.16",
45
- "@gradio/row": "^0.2.1",
46
- "@gradio/simpleimage": "^0.8.40",
47
- "@gradio/sidebar": "^0.1.21",
48
- "@gradio/plot": "^0.9.23",
49
- "@gradio/simpledropdown": "^0.3.28",
50
- "@gradio/simpletextbox": "^0.3.29",
51
- "@gradio/sketchbox": "^0.6.16",
52
- "@gradio/slider": "^0.6.17",
35
+ "@gradio/imageslider": "^0.3.0",
36
+ "@gradio/imageeditor": "^0.17.0",
37
+ "@gradio/label": "^0.5.21",
38
+ "@gradio/json": "^0.5.31",
39
+ "@gradio/markdown": "^0.13.22",
40
+ "@gradio/model3d": "^0.15.0",
41
+ "@gradio/multimodaltextbox": "^0.10.19",
42
+ "@gradio/paramviewer": "^0.8.0",
43
+ "@gradio/number": "^0.7.1",
44
+ "@gradio/nativeplot": "^0.7.6",
45
+ "@gradio/plot": "^0.9.24",
46
+ "@gradio/radio": "^0.7.12",
47
+ "@gradio/simpledropdown": "^0.3.29",
48
+ "@gradio/sidebar": "^0.1.22",
49
+ "@gradio/simpleimage": "^0.9.0",
50
+ "@gradio/row": "^0.2.2",
51
+ "@gradio/simpletextbox": "^0.3.30",
52
+ "@gradio/slider": "^0.6.18",
53
+ "@gradio/sketchbox": "^0.6.17",
53
54
  "@gradio/state": "^0.1.2",
54
- "@gradio/statustracker": "^0.11.0",
55
- "@gradio/tabitem": "^0.6.0",
56
- "@gradio/radio": "^0.7.11",
57
- "@gradio/tabs": "^0.5.0",
58
- "@gradio/textbox": "^0.11.0",
59
- "@gradio/timer": "^0.4.5",
55
+ "@gradio/tabitem": "^0.6.1",
56
+ "@gradio/tabs": "^0.5.1",
57
+ "@gradio/statustracker": "^0.11.1",
58
+ "@gradio/textbox": "^0.11.1",
60
59
  "@gradio/theme": "^0.4.0",
61
- "@gradio/uploadbutton": "^0.9.11",
60
+ "@gradio/timer": "^0.4.5",
61
+ "@gradio/upload": "^0.17.0",
62
+ "@gradio/vibeeditor": "^0.2.4",
63
+ "@gradio/uploadbutton": "^0.9.12",
62
64
  "@gradio/utils": "^0.10.2",
63
- "@gradio/upload": "^0.16.17",
64
- "@gradio/vibeeditor": "^0.2.3",
65
- "@gradio/video": "^0.15.1",
66
- "@gradio/wasm": "^0.18.1"
65
+ "@gradio/video": "^0.16.0"
67
66
  },
68
67
  "msw": {
69
68
  "workerDirectory": "public"
package/src/Blocks.svelte CHANGED
@@ -1066,18 +1066,21 @@
1066
1066
  return container.children[container.children.length - 1] as HTMLElement;
1067
1067
  }
1068
1068
 
1069
+ function handle_resize(): void {
1070
+ if ("parentIFrame" in window) {
1071
+ const box = root_node?.getBoundingClientRect();
1072
+ if (!box) return;
1073
+ window.parentIFrame?.size(box.bottom + footer_height + 32);
1074
+ }
1075
+ }
1076
+
1069
1077
  onMount(() => {
1070
1078
  if ("parentIFrame" in window) {
1071
1079
  window.parentIFrame?.autoResize(false);
1072
1080
  }
1073
1081
 
1074
- const mut = new MutationObserver((mutations) => {
1075
- if ("parentIFrame" in window) {
1076
- const box = root_node?.getBoundingClientRect();
1077
- if (!box) return;
1078
- window.parentIFrame?.size(box.bottom + footer_height + 32);
1079
- }
1080
- });
1082
+ const mut = new MutationObserver(handle_resize);
1083
+ const res = new ResizeObserver(handle_resize);
1081
1084
 
1082
1085
  mut.observe(root_container, {
1083
1086
  childList: true,
@@ -1085,8 +1088,11 @@
1085
1088
  attributes: true
1086
1089
  });
1087
1090
 
1091
+ res.observe(root_container);
1092
+
1088
1093
  return () => {
1089
1094
  mut.disconnect();
1095
+ res.disconnect();
1090
1096
  };
1091
1097
  });
1092
1098
  </script>
package/src/Embed.svelte CHANGED
@@ -9,20 +9,16 @@
9
9
  export let initial_height: string;
10
10
  export let fill_width: boolean;
11
11
  export let is_embed: boolean;
12
- export let is_lite: boolean;
13
12
 
14
13
  export let space: string | null;
15
14
  export let display: boolean;
16
15
  export let info: boolean;
17
16
  export let loaded: boolean;
18
- export let pages: [string, string][] = [];
17
+ export let pages: [string, string, boolean][] = [];
19
18
  export let current_page = "";
20
19
  export let root: string;
21
20
  export let components: any[] = [];
22
21
 
23
- const set_page: ((page: string) => void) | undefined =
24
- getContext("set_lite_page");
25
-
26
22
  let navbar_component = components.find((c) => c.type === "navbar");
27
23
  let navbar: {
28
24
  visible: boolean;
@@ -52,16 +48,25 @@
52
48
  pages.length > 1 && (navbar === null || navbar.visible !== false);
53
49
 
54
50
  $: effective_pages = (() => {
51
+ let visible_pages = pages.filter(([route, label, show], index) => {
52
+ if (index === 0 && route === "") {
53
+ return navbar?.main_page_name !== false;
54
+ }
55
+ return show !== false;
56
+ });
57
+
55
58
  let base_pages =
56
59
  navbar &&
57
60
  navbar.main_page_name !== false &&
58
61
  navbar.main_page_name !== "Home"
59
- ? pages.map(([route, label], index) =>
62
+ ? visible_pages.map(([route, label, show], index) =>
60
63
  index === 0 && route === "" && label === "Home"
61
64
  ? ([route, navbar!.main_page_name] as [string, string])
62
65
  : ([route, label] as [string, string])
63
66
  )
64
- : pages;
67
+ : visible_pages.map(
68
+ ([route, label]) => [route, label] as [string, string]
69
+ );
65
70
 
66
71
  if (navbar?.value && navbar.value.length > 0) {
67
72
  const existing_routes = new Set(base_pages.map(([route]) => route));
@@ -91,32 +96,20 @@
91
96
  <div class="nav-holder">
92
97
  <nav class="fillable" class:fill_width>
93
98
  {#each effective_pages as [route, label], i}
94
- {#if is_lite}
95
- <button
96
- class:active={route === current_page}
97
- on:click={(e) => {
98
- e.preventDefault();
99
- set_page?.(route);
100
- }}
101
- >{label}
102
- </button>
103
- {:else}
104
- <a
105
- href={route.startsWith("http://") || route.startsWith("https://")
106
- ? route
107
- : `${root}/${route}`}
108
- class:active={route === current_page}
109
- data-sveltekit-reload
110
- target={route.startsWith("http://") ||
111
- route.startsWith("https://")
112
- ? "_blank"
113
- : "_self"}
114
- rel={route.startsWith("http://") || route.startsWith("https://")
115
- ? "noopener noreferrer"
116
- : ""}
117
- >{label}
118
- </a>
119
- {/if}
99
+ <a
100
+ href={route.startsWith("http://") || route.startsWith("https://")
101
+ ? route
102
+ : `${root}/${route}`}
103
+ class:active={route === current_page}
104
+ data-sveltekit-reload
105
+ target={route.startsWith("http://") || route.startsWith("https://")
106
+ ? "_blank"
107
+ : "_self"}
108
+ rel={route.startsWith("http://") || route.startsWith("https://")
109
+ ? "noopener noreferrer"
110
+ : ""}
111
+ >{label}
112
+ </a>
120
113
  {/each}
121
114
  </nav>
122
115
  </div>
@@ -162,16 +155,14 @@
162
155
  margin: 0 auto;
163
156
  padding: 0 var(--size-8);
164
157
  }
165
- nav a,
166
- button {
158
+ nav a {
167
159
  padding: var(--size-1) var(--size-2);
168
160
  border-radius: var(--block-radius);
169
161
  border-width: var(--block-border-width);
170
162
  border-color: transparent;
171
163
  color: var(--body-text-color-subdued);
172
164
  }
173
- nav a.active,
174
- button.active {
165
+ nav a.active {
175
166
  color: var(--body-text-color);
176
167
  border-color: var(--block-border-color);
177
168
  background-color: var(--block-background-fill);
package/src/Render.svelte CHANGED
@@ -54,13 +54,20 @@
54
54
 
55
55
  $: {
56
56
  if (node && node.type === "form") {
57
- if (
58
- node.children?.every(
59
- (c) => typeof c.props.visible === "boolean" && !c.props.visible
60
- )
61
- ) {
62
- node.props.visible = false;
57
+ // Check if all children are invisible (false or "hidden")
58
+ const allChildrenInvisible = node.children?.every(
59
+ (c) => c.props.visible === false || c.props.visible === "hidden"
60
+ );
61
+
62
+ if (allChildrenInvisible) {
63
+ // Check if any child is "hidden" vs false
64
+ const hasHiddenChild = node.children?.some(
65
+ (c) => c.props.visible === "hidden"
66
+ );
67
+ // If any child is "hidden", form should be "hidden", otherwise false
68
+ node.props.visible = hasHiddenChild ? "hidden" : false;
63
69
  } else {
70
+ // If any child is visible, form should be visible
64
71
  node.props.visible = true;
65
72
  }
66
73
  }
@@ -94,7 +101,8 @@
94
101
  {...node.props}
95
102
  {theme_mode}
96
103
  {root}
97
- visible={typeof node.props.visible === "boolean"
104
+ visible={typeof node.props.visible === "boolean" ||
105
+ node.props.visible === "hidden"
98
106
  ? node.props.visible
99
107
  : true}
100
108
  >
@@ -17,7 +17,7 @@
17
17
  export let elem_id: string;
18
18
  export let elem_classes: string[];
19
19
  export let _id: number;
20
- export let visible: boolean;
20
+ export let visible: boolean | "hidden";
21
21
 
22
22
  const s = (id: number, p: string, v: any): CustomEvent =>
23
23
  new CustomEvent("prop_change", { detail: { id, prop: p, value: v } });
@@ -58,13 +58,13 @@
58
58
  class="highlight">import</span
59
59
  > Client{#if has_file_path}, handle_file{/if}
60
60
 
61
- client = Client(<span class="token string">"{space_id || root}"</span
61
+ client = Client(<span class="token string">"{space_id || root}"</span
62
62
  >{#if username !== null}, auth=("{username}", **password**){/if})
63
- result = client.<span class="highlight">predict</span
63
+ result = client.<span class="highlight">predict</span
64
64
  >(<!--
65
- -->{#each endpoint_parameters as { python_type, example_input, parameter_name, parameter_has_default, parameter_default }, i}<!--
66
- -->
67
- {parameter_name
65
+ -->{#each endpoint_parameters as { python_type, example_input, parameter_name, parameter_has_default, parameter_default }, i}<!--
66
+ -->
67
+ {parameter_name
68
68
  ? parameter_name + "="
69
69
  : ""}<span
70
70
  >{represent_value(
@@ -74,11 +74,11 @@
74
74
  )}</span
75
75
  >,{/each}<!--
76
76
 
77
- -->
78
- api_name=<span class="api-name">"/{dependency.api_name}"</span><!--
79
- -->
80
- )
81
- <span class="highlight">print</span>(result)</pre>
77
+ -->
78
+ api_name=<span class="api-name">"/{dependency.api_name}"</span><!--
79
+ -->
80
+ )
81
+ <span class="highlight">print</span>(result)</pre>
82
82
  </div>
83
83
  </code>
84
84
  </Block>
package/src/i18n.ts CHANGED
@@ -155,6 +155,23 @@ export let all_common_keys: Set<string> = new Set();
155
155
  let i18n_initialized = false;
156
156
  let previous_translations: Record<string, Record<string, string>> | undefined;
157
157
 
158
+ function get_lang_from_preferred_locale(header: string): string | null {
159
+ const options = header
160
+ .split(",")
161
+ .map((value) =>
162
+ value.includes(";") ? value.split(";").slice(0, 2) : [value, 1]
163
+ );
164
+ options.sort(
165
+ (a, b) => parseFloat(b[1] as string) - parseFloat(a[1] as string)
166
+ );
167
+ for (const [lang, _] of options) {
168
+ if (available_locales.includes(lang as string)) {
169
+ return lang as string;
170
+ }
171
+ }
172
+ return null;
173
+ }
174
+
158
175
  export async function setupi18n(
159
176
  custom_translations?: Record<string, Record<string, string>>,
160
177
  preferred_locale?: string
@@ -173,12 +190,16 @@ export async function setupi18n(
173
190
  custom_translations: custom_translations ?? {}
174
191
  });
175
192
 
176
- const browser_locale = preferred_locale ?? getLocaleFromNavigator();
177
-
178
- let initial_locale =
179
- browser_locale && available_locales.includes(browser_locale)
180
- ? browser_locale
181
- : null;
193
+ let initial_locale: string | null = null;
194
+ const browser_locale = getLocaleFromNavigator();
195
+ if (preferred_locale) {
196
+ initial_locale = get_lang_from_preferred_locale(preferred_locale);
197
+ } else {
198
+ initial_locale =
199
+ browser_locale && available_locales.includes(browser_locale)
200
+ ? browser_locale
201
+ : null;
202
+ }
182
203
 
183
204
  if (!initial_locale) {
184
205
  const normalized_locale = browser_locale?.split("-")[0];
package/src/init.ts CHANGED
@@ -89,7 +89,6 @@ export function create_components(
89
89
  value_change_cb = cb;
90
90
  }
91
91
 
92
- // Store current layout and root for dynamic visibility recalculation
93
92
  let current_layout: LayoutNode;
94
93
  let current_root: string;
95
94
 
@@ -123,15 +122,12 @@ export function create_components(
123
122
  fill_height: boolean;
124
123
  };
125
124
  }): Promise<void> {
126
- // make sure the state is settled before proceeding
127
125
  flush();
128
126
  app = _app;
129
127
 
130
128
  if (instance_map) {
131
- // re-render in reload mode
132
129
  components.forEach((c) => {
133
130
  if (c.props.value == null && c.key) {
134
- // If the component has a key, we preserve its value by finding a matching instance with the same key
135
131
  const matching_instance = Object.values(instance_map).find(
136
132
  (instance) => instance.key === c.key
137
133
  );
@@ -150,14 +146,17 @@ export function create_components(
150
146
  _component_map = new Map();
151
147
  instance_map = {};
152
148
 
153
- // Store current layout and root for dynamic visibility recalculation
154
149
  current_layout = layout;
155
150
  current_root = root;
156
151
 
157
152
  _rootNode = {
158
153
  id: layout.id,
159
154
  type: "column",
160
- props: { interactive: false, scale: options.fill_height ? 1 : null },
155
+ props: {
156
+ interactive: false,
157
+ scale: options.fill_height ? 1 : null,
158
+ visible: true
159
+ },
161
160
  has_modes: false,
162
161
  instance: null as unknown as ComponentMeta["instance"],
163
162
  component: null as unknown as ComponentMeta["component"],
@@ -410,7 +409,10 @@ export function create_components(
410
409
  label: child.props.label.includes(i18n_marker) ? "" : child.props.label,
411
410
  id: child.props.id,
412
411
  visible:
413
- typeof child.props.visible === "boolean" ? child.props.visible : true,
412
+ typeof child.props.visible === "boolean" ||
413
+ child.props.visible === "hidden"
414
+ ? child.props.visible
415
+ : true,
414
416
  interactive: child.props.interactive,
415
417
  order: child.props.order
416
418
  }));
@@ -446,7 +448,6 @@ export function create_components(
446
448
  for (const component of components_to_load) {
447
449
  const constructor_key = component.component_class_id || component.type;
448
450
 
449
- // Only load if not already loaded
450
451
  if (!constructor_map.has(constructor_key)) {
451
452
  const { component: loadable_component, example_components } =
452
453
  get_component(
@@ -464,7 +465,6 @@ export function create_components(
464
465
  }
465
466
  }
466
467
 
467
- // Load the component if it doesn't exist yet
468
468
  if (!component.component) {
469
469
  component.component = (await loadable_component)?.default;
470
470
  }
@@ -487,10 +487,8 @@ export function create_components(
487
487
  const instance = instance_map?.[update.id];
488
488
  if (!instance) return false;
489
489
 
490
- // Check for visibility property changes
491
490
  if (update.prop === "visible") return true;
492
491
 
493
- // Check for selected tab changes in tabs components
494
492
  if (update.prop === "selected" && instance.type === "tabs") return true;
495
493
 
496
494
  return false;
@@ -505,7 +503,6 @@ export function create_components(
505
503
  ? [..._component_map.values()]
506
504
  : _components;
507
505
 
508
- // Capture current visibility state before applying updates
509
506
  if (had_visibility_changes && current_layout) {
510
507
  previous_visible_ids = determine_visible_components(
511
508
  current_layout,
@@ -541,10 +538,10 @@ export function create_components(
541
538
  }
542
539
  }
543
540
  }
541
+
544
542
  return layout;
545
543
  });
546
544
 
547
- // After applying updates, check if we need to load new components
548
545
  if (had_visibility_changes && current_layout && previous_visible_ids) {
549
546
  raf(async () => {
550
547
  const new_visible_ids = determine_visible_components(
@@ -553,17 +550,14 @@ export function create_components(
553
550
  );
554
551
  const newly_visible_ids = new Set<number>();
555
552
 
556
- // Find components that are now visible but weren't before
557
553
  for (const id of new_visible_ids) {
558
554
  if (!previous_visible_ids!.has(id)) {
559
555
  newly_visible_ids.add(id);
560
556
  }
561
557
  }
562
558
 
563
- // Load the newly visible components
564
559
  await load_newly_visible_components(newly_visible_ids, all_components);
565
560
 
566
- // Trigger a layout update to render the newly loaded components
567
561
  if (newly_visible_ids.size > 0) {
568
562
  layout_store.update((layout) => layout);
569
563
  }
@@ -906,13 +900,11 @@ function get_selected_tab_id(
906
900
  layout: LayoutNode,
907
901
  components: ComponentMeta[]
908
902
  ): string | number | undefined {
909
- // Check if selected prop is a string or number
910
903
  const selected = component.props.selected;
911
904
  if (typeof selected === "string" || typeof selected === "number") {
912
905
  return selected;
913
906
  }
914
907
 
915
- // If no tab is explicitly selected, find the first visible and interactive tab
916
908
  if (layout.children) {
917
909
  for (const child of layout.children) {
918
910
  const child_component = components.find((c) => c.id === child.id);
@@ -975,27 +967,42 @@ function determine_visible_components(
975
967
  parent_tabs_context?: { selected_tab_id?: string | number }
976
968
  ): Set<number> {
977
969
  const visible_components: Set<number> = new Set();
970
+
978
971
  const component = components.find((c) => c.id === layout.id);
979
972
 
980
973
  if (!component) {
981
974
  return visible_components;
982
975
  }
983
976
 
984
- // Check if the component itself is visible
985
977
  const component_visible =
986
- parent_visible &&
987
- (typeof component.props.visible === "boolean"
988
- ? component.props.visible
989
- : true);
978
+ component.props.visible !== false &&
979
+ component.props.visible !== "hidden" &&
980
+ parent_visible;
981
+
982
+ const should_load = component.props.visible === "hidden" || component_visible;
983
+
984
+ if (!should_load) {
985
+ return visible_components;
986
+ }
987
+
988
+ if (component.type === "tabs") {
989
+ const selected_tab_id = get_selected_tab_id(component, layout, components);
990
+ const tabs_context = { selected_tab_id };
991
+
992
+ visible_components.add(layout.id);
990
993
 
991
- // Handle tab_item special case
992
- if (component.type === "tabitem") {
994
+ const child_visible = process_children_visibility(
995
+ layout,
996
+ components,
997
+ tabs_context
998
+ );
999
+ child_visible.forEach((id) => visible_components.add(id));
1000
+ } else if (component.type === "tabitem") {
993
1001
  if (
994
1002
  is_tab_item_visible(component, component_visible, parent_tabs_context)
995
1003
  ) {
996
- visible_components.add(component.id);
1004
+ visible_components.add(layout.id);
997
1005
 
998
- // Process children if this tab item is visible
999
1006
  const child_visible = process_children_visibility(
1000
1007
  layout,
1001
1008
  components,
@@ -1003,36 +1010,9 @@ function determine_visible_components(
1003
1010
  );
1004
1011
  child_visible.forEach((id) => visible_components.add(id));
1005
1012
  }
1006
- // If tab item is not visible, none of its children should be loaded
1007
- return visible_components;
1008
- }
1009
-
1010
- // Handle tabs component
1011
- if (component.type === "tabs") {
1012
- if (component_visible) {
1013
- visible_components.add(component.id);
1014
-
1015
- // Determine which tab should be selected
1016
- const selected_tab_id = get_selected_tab_id(
1017
- component,
1018
- layout,
1019
- components
1020
- );
1021
-
1022
- // Process children with tabs context
1023
- const child_visible = process_children_visibility(layout, components, {
1024
- selected_tab_id
1025
- });
1026
- child_visible.forEach((id) => visible_components.add(id));
1027
- }
1028
- return visible_components;
1029
- }
1030
-
1031
- // For regular components
1032
- if (component_visible) {
1033
- visible_components.add(component.id);
1013
+ } else {
1014
+ visible_components.add(layout.id);
1034
1015
 
1035
- // Process children if this component is visible
1036
1016
  const child_visible = process_children_visibility(
1037
1017
  layout,
1038
1018
  components,
@@ -1040,7 +1020,6 @@ function determine_visible_components(
1040
1020
  );
1041
1021
  child_visible.forEach((id) => visible_components.add(id));
1042
1022
  }
1043
- // If component is not visible, don't process children
1044
1023
 
1045
1024
  return visible_components;
1046
1025
  }
@@ -1059,13 +1038,11 @@ export function preload_visible_components(
1059
1038
  ): Map<ComponentMeta["type"], LoadingComponent> {
1060
1039
  let constructor_map: Map<ComponentMeta["type"], LoadingComponent> = new Map();
1061
1040
 
1062
- // Determine which components should be visible
1063
1041
  const visible_component_ids = determine_visible_components(
1064
1042
  layout,
1065
1043
  components
1066
1044
  );
1067
1045
 
1068
- // Only preload visible components
1069
1046
  components.forEach((c) => {
1070
1047
  if (visible_component_ids.has(c.id)) {
1071
1048
  const { component, example_components } = get_component(
@@ -1121,6 +1098,9 @@ export function preload_all_components(
1121
1098
  }
1122
1099
 
1123
1100
  function is_visible(component: ComponentMeta): boolean {
1101
+ if (component.props.visible === "hidden") {
1102
+ return true;
1103
+ }
1124
1104
  if (
1125
1105
  typeof component.props.visible === "boolean" &&
1126
1106
  component.props.visible === false