@gradio/tabs 0.5.8 → 0.5.10
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 +22 -0
- package/dist/shared/Tabs.svelte +48 -30
- package/package.json +3 -3
- package/shared/Tabs.svelte +48 -30
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,27 @@
|
|
|
1
1
|
# @gradio/tabs
|
|
2
2
|
|
|
3
|
+
## 0.5.10
|
|
4
|
+
|
|
5
|
+
### Fixes
|
|
6
|
+
|
|
7
|
+
- [#13303](https://github.com/gradio-app/gradio/pull/13303) [`79c5776`](https://github.com/gradio-app/gradio/commit/79c577680978adfb5eeaa01944635e14dc67e5f1) - Rework `Dataframe` wrapping, truncation, and column width sizing. Thanks @pngwn!
|
|
8
|
+
|
|
9
|
+
## 0.5.9
|
|
10
|
+
|
|
11
|
+
### Fixes
|
|
12
|
+
|
|
13
|
+
- [#13048](https://github.com/gradio-app/gradio/pull/13048) [`a5d4096`](https://github.com/gradio-app/gradio/commit/a5d40965bba21a832da522127048926b71c1a6dd) - Fix Tab Interactive Bug. Thanks @freddyaboulton!
|
|
14
|
+
|
|
15
|
+
### Dependency updates
|
|
16
|
+
|
|
17
|
+
- @gradio/utils@0.12.2
|
|
18
|
+
|
|
19
|
+
## 0.5.8
|
|
20
|
+
|
|
21
|
+
### Dependency updates
|
|
22
|
+
|
|
23
|
+
- @gradio/utils@0.12.1
|
|
24
|
+
|
|
3
25
|
## 0.5.8
|
|
4
26
|
|
|
5
27
|
### Dependency updates
|
package/dist/shared/Tabs.svelte
CHANGED
|
@@ -30,6 +30,25 @@
|
|
|
30
30
|
let overflow_menu_open = false;
|
|
31
31
|
let overflow_menu: HTMLElement;
|
|
32
32
|
|
|
33
|
+
// Track which tab orders have been registered by mounted TabItem components.
|
|
34
|
+
// Once a TabItem mounts and calls register_tab, it manages its own tab entry
|
|
35
|
+
// via _set_data -> register_tab, so _sync_tabs should not overwrite it.
|
|
36
|
+
let mounted_tab_orders: Set<number> = new Set();
|
|
37
|
+
|
|
38
|
+
// When initial_tabs changes (e.g. a non-mounted tab's props were updated),
|
|
39
|
+
// sync the internal tabs array so the tab buttons reflect the new state.
|
|
40
|
+
// Using a function call so the $: dependency is only on initial_tabs,
|
|
41
|
+
// not on tabs (which would cause a loop with register_tab).
|
|
42
|
+
$: _sync_tabs(initial_tabs);
|
|
43
|
+
|
|
44
|
+
function _sync_tabs(new_tabs: Tab[]): void {
|
|
45
|
+
for (let i = 0; i < new_tabs.length; i++) {
|
|
46
|
+
if (new_tabs[i] && !mounted_tab_orders.has(i)) {
|
|
47
|
+
tabs[i] = new_tabs[i];
|
|
48
|
+
}
|
|
49
|
+
}
|
|
50
|
+
}
|
|
51
|
+
|
|
33
52
|
$: has_tabs = tabs.length > 0;
|
|
34
53
|
|
|
35
54
|
let tab_nav_el: HTMLDivElement;
|
|
@@ -51,14 +70,16 @@
|
|
|
51
70
|
|
|
52
71
|
onMount(() => {
|
|
53
72
|
if (!tab_nav_el) return;
|
|
54
|
-
const
|
|
73
|
+
const ro = new ResizeObserver(() => {
|
|
55
74
|
handle_menu_overflow();
|
|
56
75
|
});
|
|
57
|
-
|
|
76
|
+
ro.observe(tab_nav_el);
|
|
77
|
+
return () => ro.disconnect();
|
|
58
78
|
});
|
|
59
79
|
|
|
60
80
|
setContext(TABS, {
|
|
61
81
|
register_tab: (tab: Tab, order: number) => {
|
|
82
|
+
mounted_tab_orders.add(order);
|
|
62
83
|
tabs[order] = tab;
|
|
63
84
|
|
|
64
85
|
if ($selected_tab === false && tab.visible !== false && tab.interactive) {
|
|
@@ -68,6 +89,7 @@
|
|
|
68
89
|
return order;
|
|
69
90
|
},
|
|
70
91
|
unregister_tab: (tab: Tab, order: number) => {
|
|
92
|
+
mounted_tab_orders.delete(order);
|
|
71
93
|
if ($selected_tab === tab.id) {
|
|
72
94
|
$selected_tab = tabs[0]?.id || false;
|
|
73
95
|
}
|
|
@@ -107,33 +129,42 @@
|
|
|
107
129
|
}
|
|
108
130
|
}
|
|
109
131
|
|
|
132
|
+
// approximate width of the "..." overflow button including margin
|
|
133
|
+
const OVERFLOW_BTN_RESERVE = 48;
|
|
134
|
+
|
|
110
135
|
async function handle_menu_overflow(): Promise<void> {
|
|
111
136
|
if (!tab_nav_el) return;
|
|
112
137
|
|
|
113
138
|
await tick();
|
|
114
|
-
|
|
139
|
+
await new Promise((r) => requestAnimationFrame(r));
|
|
115
140
|
|
|
116
|
-
|
|
117
|
-
const tab_sizes = get_tab_sizes(tabs, tab_els);
|
|
118
|
-
let last_visible_index = 0;
|
|
119
|
-
const offset = tab_nav_size.left;
|
|
141
|
+
const available = tab_nav_el.clientWidth;
|
|
120
142
|
|
|
121
|
-
|
|
143
|
+
let cumulative = 0;
|
|
144
|
+
let split_index = tabs.length;
|
|
145
|
+
|
|
146
|
+
for (let i = 0; i < tabs.length; i++) {
|
|
122
147
|
const tab = tabs[i];
|
|
123
|
-
if (!tab) continue;
|
|
124
|
-
const
|
|
125
|
-
if (!
|
|
126
|
-
|
|
127
|
-
|
|
148
|
+
if (!tab || tab.visible === false || tab.visible === "hidden") continue;
|
|
149
|
+
const el = tab_els[tab.id];
|
|
150
|
+
if (!el) continue;
|
|
151
|
+
cumulative += el.getBoundingClientRect().width;
|
|
152
|
+
const has_more = tabs
|
|
153
|
+
.slice(i + 1)
|
|
154
|
+
.some((t) => t && t.visible !== false && t.visible !== "hidden");
|
|
155
|
+
const limit = has_more ? available - OVERFLOW_BTN_RESERVE : available;
|
|
156
|
+
if (cumulative > limit) {
|
|
157
|
+
split_index = i;
|
|
128
158
|
break;
|
|
129
159
|
}
|
|
130
160
|
}
|
|
131
161
|
|
|
132
|
-
|
|
133
|
-
|
|
162
|
+
visible_tabs = tabs.slice(0, split_index);
|
|
163
|
+
overflow_tabs = tabs.slice(split_index);
|
|
134
164
|
|
|
135
165
|
overflow_has_selected_tab = handle_overflow_has_selected_tab($selected_tab);
|
|
136
|
-
is_overflowing =
|
|
166
|
+
is_overflowing =
|
|
167
|
+
overflow_tabs.filter((t) => t && t.visible !== false).length > 0;
|
|
137
168
|
}
|
|
138
169
|
|
|
139
170
|
$: overflow_has_selected_tab =
|
|
@@ -146,18 +177,6 @@
|
|
|
146
177
|
return overflow_tabs.some((t) => t?.id === selected_tab);
|
|
147
178
|
}
|
|
148
179
|
|
|
149
|
-
function get_tab_sizes(
|
|
150
|
-
tabs: (Tab | null)[],
|
|
151
|
-
tab_els: Record<string | number, HTMLElement>
|
|
152
|
-
): Record<string | number, DOMRect> {
|
|
153
|
-
const tab_sizes: Record<string | number, DOMRect> = {};
|
|
154
|
-
tabs.forEach((tab) => {
|
|
155
|
-
if (!tab) return;
|
|
156
|
-
tab_sizes[tab.id] = tab_els[tab.id]?.getBoundingClientRect();
|
|
157
|
-
});
|
|
158
|
-
return tab_sizes;
|
|
159
|
-
}
|
|
160
|
-
|
|
161
180
|
$: tab_scale =
|
|
162
181
|
tabs[$selected_tab_index >= 0 ? $selected_tab_index : 0]?.scale;
|
|
163
182
|
</script>
|
|
@@ -256,9 +275,7 @@
|
|
|
256
275
|
<style>
|
|
257
276
|
.tabs {
|
|
258
277
|
position: relative;
|
|
259
|
-
display: flex;
|
|
260
278
|
flex-direction: column;
|
|
261
|
-
gap: var(--layout-gap);
|
|
262
279
|
}
|
|
263
280
|
|
|
264
281
|
.hide {
|
|
@@ -276,6 +293,7 @@
|
|
|
276
293
|
position: relative;
|
|
277
294
|
height: var(--size-8);
|
|
278
295
|
padding-bottom: var(--size-2);
|
|
296
|
+
margin-bottom: var(--layout-gap);
|
|
279
297
|
}
|
|
280
298
|
|
|
281
299
|
.tab-container {
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@gradio/tabs",
|
|
3
|
-
"version": "0.5.
|
|
3
|
+
"version": "0.5.10",
|
|
4
4
|
"description": "Gradio UI packages",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"author": "",
|
|
@@ -17,10 +17,10 @@
|
|
|
17
17
|
"./package.json": "./package.json"
|
|
18
18
|
},
|
|
19
19
|
"dependencies": {
|
|
20
|
-
"@gradio/utils": "^0.12.
|
|
20
|
+
"@gradio/utils": "^0.12.2"
|
|
21
21
|
},
|
|
22
22
|
"devDependencies": {
|
|
23
|
-
"@gradio/preview": "^0.16.
|
|
23
|
+
"@gradio/preview": "^0.16.2"
|
|
24
24
|
},
|
|
25
25
|
"peerDependencies": {
|
|
26
26
|
"svelte": "^5.48.0"
|
package/shared/Tabs.svelte
CHANGED
|
@@ -30,6 +30,25 @@
|
|
|
30
30
|
let overflow_menu_open = false;
|
|
31
31
|
let overflow_menu: HTMLElement;
|
|
32
32
|
|
|
33
|
+
// Track which tab orders have been registered by mounted TabItem components.
|
|
34
|
+
// Once a TabItem mounts and calls register_tab, it manages its own tab entry
|
|
35
|
+
// via _set_data -> register_tab, so _sync_tabs should not overwrite it.
|
|
36
|
+
let mounted_tab_orders: Set<number> = new Set();
|
|
37
|
+
|
|
38
|
+
// When initial_tabs changes (e.g. a non-mounted tab's props were updated),
|
|
39
|
+
// sync the internal tabs array so the tab buttons reflect the new state.
|
|
40
|
+
// Using a function call so the $: dependency is only on initial_tabs,
|
|
41
|
+
// not on tabs (which would cause a loop with register_tab).
|
|
42
|
+
$: _sync_tabs(initial_tabs);
|
|
43
|
+
|
|
44
|
+
function _sync_tabs(new_tabs: Tab[]): void {
|
|
45
|
+
for (let i = 0; i < new_tabs.length; i++) {
|
|
46
|
+
if (new_tabs[i] && !mounted_tab_orders.has(i)) {
|
|
47
|
+
tabs[i] = new_tabs[i];
|
|
48
|
+
}
|
|
49
|
+
}
|
|
50
|
+
}
|
|
51
|
+
|
|
33
52
|
$: has_tabs = tabs.length > 0;
|
|
34
53
|
|
|
35
54
|
let tab_nav_el: HTMLDivElement;
|
|
@@ -51,14 +70,16 @@
|
|
|
51
70
|
|
|
52
71
|
onMount(() => {
|
|
53
72
|
if (!tab_nav_el) return;
|
|
54
|
-
const
|
|
73
|
+
const ro = new ResizeObserver(() => {
|
|
55
74
|
handle_menu_overflow();
|
|
56
75
|
});
|
|
57
|
-
|
|
76
|
+
ro.observe(tab_nav_el);
|
|
77
|
+
return () => ro.disconnect();
|
|
58
78
|
});
|
|
59
79
|
|
|
60
80
|
setContext(TABS, {
|
|
61
81
|
register_tab: (tab: Tab, order: number) => {
|
|
82
|
+
mounted_tab_orders.add(order);
|
|
62
83
|
tabs[order] = tab;
|
|
63
84
|
|
|
64
85
|
if ($selected_tab === false && tab.visible !== false && tab.interactive) {
|
|
@@ -68,6 +89,7 @@
|
|
|
68
89
|
return order;
|
|
69
90
|
},
|
|
70
91
|
unregister_tab: (tab: Tab, order: number) => {
|
|
92
|
+
mounted_tab_orders.delete(order);
|
|
71
93
|
if ($selected_tab === tab.id) {
|
|
72
94
|
$selected_tab = tabs[0]?.id || false;
|
|
73
95
|
}
|
|
@@ -107,33 +129,42 @@
|
|
|
107
129
|
}
|
|
108
130
|
}
|
|
109
131
|
|
|
132
|
+
// approximate width of the "..." overflow button including margin
|
|
133
|
+
const OVERFLOW_BTN_RESERVE = 48;
|
|
134
|
+
|
|
110
135
|
async function handle_menu_overflow(): Promise<void> {
|
|
111
136
|
if (!tab_nav_el) return;
|
|
112
137
|
|
|
113
138
|
await tick();
|
|
114
|
-
|
|
139
|
+
await new Promise((r) => requestAnimationFrame(r));
|
|
115
140
|
|
|
116
|
-
|
|
117
|
-
const tab_sizes = get_tab_sizes(tabs, tab_els);
|
|
118
|
-
let last_visible_index = 0;
|
|
119
|
-
const offset = tab_nav_size.left;
|
|
141
|
+
const available = tab_nav_el.clientWidth;
|
|
120
142
|
|
|
121
|
-
|
|
143
|
+
let cumulative = 0;
|
|
144
|
+
let split_index = tabs.length;
|
|
145
|
+
|
|
146
|
+
for (let i = 0; i < tabs.length; i++) {
|
|
122
147
|
const tab = tabs[i];
|
|
123
|
-
if (!tab) continue;
|
|
124
|
-
const
|
|
125
|
-
if (!
|
|
126
|
-
|
|
127
|
-
|
|
148
|
+
if (!tab || tab.visible === false || tab.visible === "hidden") continue;
|
|
149
|
+
const el = tab_els[tab.id];
|
|
150
|
+
if (!el) continue;
|
|
151
|
+
cumulative += el.getBoundingClientRect().width;
|
|
152
|
+
const has_more = tabs
|
|
153
|
+
.slice(i + 1)
|
|
154
|
+
.some((t) => t && t.visible !== false && t.visible !== "hidden");
|
|
155
|
+
const limit = has_more ? available - OVERFLOW_BTN_RESERVE : available;
|
|
156
|
+
if (cumulative > limit) {
|
|
157
|
+
split_index = i;
|
|
128
158
|
break;
|
|
129
159
|
}
|
|
130
160
|
}
|
|
131
161
|
|
|
132
|
-
|
|
133
|
-
|
|
162
|
+
visible_tabs = tabs.slice(0, split_index);
|
|
163
|
+
overflow_tabs = tabs.slice(split_index);
|
|
134
164
|
|
|
135
165
|
overflow_has_selected_tab = handle_overflow_has_selected_tab($selected_tab);
|
|
136
|
-
is_overflowing =
|
|
166
|
+
is_overflowing =
|
|
167
|
+
overflow_tabs.filter((t) => t && t.visible !== false).length > 0;
|
|
137
168
|
}
|
|
138
169
|
|
|
139
170
|
$: overflow_has_selected_tab =
|
|
@@ -146,18 +177,6 @@
|
|
|
146
177
|
return overflow_tabs.some((t) => t?.id === selected_tab);
|
|
147
178
|
}
|
|
148
179
|
|
|
149
|
-
function get_tab_sizes(
|
|
150
|
-
tabs: (Tab | null)[],
|
|
151
|
-
tab_els: Record<string | number, HTMLElement>
|
|
152
|
-
): Record<string | number, DOMRect> {
|
|
153
|
-
const tab_sizes: Record<string | number, DOMRect> = {};
|
|
154
|
-
tabs.forEach((tab) => {
|
|
155
|
-
if (!tab) return;
|
|
156
|
-
tab_sizes[tab.id] = tab_els[tab.id]?.getBoundingClientRect();
|
|
157
|
-
});
|
|
158
|
-
return tab_sizes;
|
|
159
|
-
}
|
|
160
|
-
|
|
161
180
|
$: tab_scale =
|
|
162
181
|
tabs[$selected_tab_index >= 0 ? $selected_tab_index : 0]?.scale;
|
|
163
182
|
</script>
|
|
@@ -256,9 +275,7 @@
|
|
|
256
275
|
<style>
|
|
257
276
|
.tabs {
|
|
258
277
|
position: relative;
|
|
259
|
-
display: flex;
|
|
260
278
|
flex-direction: column;
|
|
261
|
-
gap: var(--layout-gap);
|
|
262
279
|
}
|
|
263
280
|
|
|
264
281
|
.hide {
|
|
@@ -276,6 +293,7 @@
|
|
|
276
293
|
position: relative;
|
|
277
294
|
height: var(--size-8);
|
|
278
295
|
padding-bottom: var(--size-2);
|
|
296
|
+
margin-bottom: var(--layout-gap);
|
|
279
297
|
}
|
|
280
298
|
|
|
281
299
|
.tab-container {
|