@wandelbots/wandelbots-js-react-components 2.53.0 → 2.54.0-pr.fix-always-show-full-badge.399.7adae47
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/components/TabBar.d.ts +11 -0
- package/dist/components/TabBar.d.ts.map +1 -1
- package/dist/index.cjs +18 -18
- package/dist/index.cjs.map +1 -1
- package/dist/index.js +2347 -2273
- package/dist/index.js.map +1 -1
- package/package.json +6 -6
- package/src/components/TabBar.tsx +155 -38
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@wandelbots/wandelbots-js-react-components",
|
|
3
|
-
"version": "2.
|
|
3
|
+
"version": "2.54.0-pr.fix-always-show-full-badge.399.7adae47",
|
|
4
4
|
"description": "React UI toolkit for building applications on top of the Wandelbots platform",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"sideEffects": false,
|
|
@@ -59,9 +59,9 @@
|
|
|
59
59
|
"@rollup/plugin-node-resolve": "^16.0.0",
|
|
60
60
|
"@rollup/plugin-terser": "^0.4.4",
|
|
61
61
|
"@rollup/plugin-typescript": "^12.1.2",
|
|
62
|
-
"@storybook/addon-docs": "^
|
|
63
|
-
"@storybook/react-vite": "^
|
|
64
|
-
"@storybook/test-runner": "^0.
|
|
62
|
+
"@storybook/addon-docs": "^10.0.1",
|
|
63
|
+
"@storybook/react-vite": "^10.0.1",
|
|
64
|
+
"@storybook/test-runner": "^0.24.1",
|
|
65
65
|
"@svgr/rollup": "^8.1.0",
|
|
66
66
|
"@testing-library/jest-dom": "^6.6.3",
|
|
67
67
|
"@testing-library/react": "^16.3.0",
|
|
@@ -72,7 +72,7 @@
|
|
|
72
72
|
"@vitejs/plugin-react": "^4.3.4",
|
|
73
73
|
"@wandelbots/nova-js": "^2.1.0",
|
|
74
74
|
"add": "^2.0.6",
|
|
75
|
-
"eslint-plugin-storybook": "^
|
|
75
|
+
"eslint-plugin-storybook": "^10.0.1",
|
|
76
76
|
"glob": "^11.0.1",
|
|
77
77
|
"http-server": "^14.1.1",
|
|
78
78
|
"husky": "^9.1.7",
|
|
@@ -95,7 +95,7 @@
|
|
|
95
95
|
"rollup-plugin-peer-deps-external": "^2.2.4",
|
|
96
96
|
"rollup-plugin-postcss": "^4.0.2",
|
|
97
97
|
"semantic-release": "^24.2.3",
|
|
98
|
-
"storybook": "^
|
|
98
|
+
"storybook": "^10.0.1",
|
|
99
99
|
"storybook-preset-inline-svg": "^1.0.1",
|
|
100
100
|
"three": "^0.174.0",
|
|
101
101
|
"three-stdlib": "^2.35.14",
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import type { SxProps } from "@mui/material"
|
|
2
|
-
import { Box, Tab, Tabs } from "@mui/material"
|
|
2
|
+
import { Badge, Box, Tab, Tabs } from "@mui/material"
|
|
3
3
|
import { observer } from "mobx-react-lite"
|
|
4
4
|
import { useEffect, useState } from "react"
|
|
5
5
|
import { externalizeComponent } from "../externalizeComponent"
|
|
@@ -13,6 +13,24 @@ export interface TabItem {
|
|
|
13
13
|
content: React.ReactNode
|
|
14
14
|
/** Optional icon component to display with the tab */
|
|
15
15
|
icon?: React.ReactElement
|
|
16
|
+
/** Optional badge configuration */
|
|
17
|
+
badge?: {
|
|
18
|
+
/** Badge content (number or string) */
|
|
19
|
+
content: React.ReactNode
|
|
20
|
+
/** Badge color variant */
|
|
21
|
+
color?:
|
|
22
|
+
| "default"
|
|
23
|
+
| "primary"
|
|
24
|
+
| "secondary"
|
|
25
|
+
| "error"
|
|
26
|
+
| "info"
|
|
27
|
+
| "success"
|
|
28
|
+
| "warning"
|
|
29
|
+
/** Maximum number to display (e.g., 99+) */
|
|
30
|
+
max?: number
|
|
31
|
+
/** Show badge even when content is zero */
|
|
32
|
+
showZero?: boolean
|
|
33
|
+
}
|
|
16
34
|
}
|
|
17
35
|
|
|
18
36
|
export interface TabBarProps {
|
|
@@ -71,6 +89,8 @@ export const TabBar = externalizeComponent(
|
|
|
71
89
|
const [uncontrolledActiveTab, setUncontrolledActiveTab] =
|
|
72
90
|
useState(defaultActiveTab)
|
|
73
91
|
|
|
92
|
+
const currentValue = isControlled ? activeTab! : uncontrolledActiveTab
|
|
93
|
+
|
|
74
94
|
// Keep uncontrolled state in range when items change
|
|
75
95
|
useEffect(() => {
|
|
76
96
|
if (isControlled) return
|
|
@@ -83,8 +103,6 @@ export const TabBar = externalizeComponent(
|
|
|
83
103
|
}
|
|
84
104
|
}, [items.length, isControlled, uncontrolledActiveTab])
|
|
85
105
|
|
|
86
|
-
const currentValue = isControlled ? activeTab! : uncontrolledActiveTab
|
|
87
|
-
|
|
88
106
|
const handleTabChange = (
|
|
89
107
|
_event: React.SyntheticEvent,
|
|
90
108
|
newValue: number,
|
|
@@ -101,62 +119,161 @@ export const TabBar = externalizeComponent(
|
|
|
101
119
|
sx={{ height: "100%", display: "flex", flexDirection: "column", ...sx }}
|
|
102
120
|
>
|
|
103
121
|
{/* Tabs */}
|
|
104
|
-
<Box
|
|
122
|
+
<Box
|
|
123
|
+
sx={{
|
|
124
|
+
px: 0,
|
|
125
|
+
py: 0,
|
|
126
|
+
overflow: "visible",
|
|
127
|
+
position: "relative",
|
|
128
|
+
// Extra padding to prevent badge clipping
|
|
129
|
+
// Top: accommodates badge positioned at top: -6px with 20px height
|
|
130
|
+
// Right: accommodates badge positioned at right: -8px with 20px width
|
|
131
|
+
paddingTop: (theme) => theme.spacing(2), // 16px
|
|
132
|
+
paddingRight: (theme) => theme.spacing(2.5), // 20px
|
|
133
|
+
}}
|
|
134
|
+
>
|
|
105
135
|
<Tabs
|
|
106
136
|
value={currentValue}
|
|
107
137
|
onChange={handleTabChange}
|
|
108
138
|
sx={{
|
|
109
139
|
minHeight: "32px",
|
|
110
140
|
backgroundColor: "transparent",
|
|
141
|
+
overflow: "visible",
|
|
111
142
|
"& .MuiTabs-indicator": {
|
|
112
143
|
display: "none", // Hide the default indicator
|
|
113
144
|
},
|
|
114
145
|
"& .MuiTabs-flexContainer": {
|
|
115
146
|
gap: 2,
|
|
147
|
+
overflow: "visible",
|
|
148
|
+
paddingTop: 0,
|
|
149
|
+
paddingBottom: 0,
|
|
150
|
+
},
|
|
151
|
+
"& .MuiTabs-scroller": {
|
|
152
|
+
overflow: "visible !important",
|
|
153
|
+
},
|
|
154
|
+
"& .MuiTab-root": {
|
|
155
|
+
overflow: "visible",
|
|
116
156
|
},
|
|
117
157
|
}}
|
|
118
158
|
>
|
|
119
|
-
{items.map((item, index) =>
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
159
|
+
{items.map((item, index) => {
|
|
160
|
+
// Helper functions for badge logic
|
|
161
|
+
const getBadgeContent = () => {
|
|
162
|
+
if (!item.badge) return undefined
|
|
163
|
+
const content = item.badge.content
|
|
164
|
+
const max = item.badge.max
|
|
165
|
+
|
|
166
|
+
// Handle numeric content with max limit
|
|
167
|
+
if (typeof content === "number" && max && content > max) {
|
|
168
|
+
return `${max}+`
|
|
169
|
+
}
|
|
170
|
+
|
|
171
|
+
return content
|
|
172
|
+
}
|
|
173
|
+
|
|
174
|
+
const shouldShowBadge = () => {
|
|
175
|
+
if (!item.badge) return false
|
|
176
|
+
const content = item.badge.content
|
|
177
|
+
const showZero = item.badge.showZero
|
|
178
|
+
|
|
179
|
+
// If content is 0 and showZero is false, hide badge
|
|
180
|
+
if (content === 0 && !showZero) return false
|
|
181
|
+
|
|
182
|
+
return true
|
|
183
|
+
}
|
|
184
|
+
|
|
185
|
+
const badgeContent = getBadgeContent()
|
|
186
|
+
const showBadge = shouldShowBadge()
|
|
187
|
+
|
|
188
|
+
const handleTabClick = () => {
|
|
189
|
+
if (!isControlled) {
|
|
190
|
+
setUncontrolledActiveTab(index)
|
|
191
|
+
}
|
|
192
|
+
onTabChange?.(index)
|
|
193
|
+
}
|
|
194
|
+
|
|
195
|
+
const tab = (
|
|
196
|
+
<Tab
|
|
197
|
+
label={item.label}
|
|
198
|
+
icon={item.icon}
|
|
199
|
+
iconPosition="start"
|
|
200
|
+
disableRipple
|
|
201
|
+
onClick={handleTabClick}
|
|
202
|
+
sx={{
|
|
203
|
+
minHeight: "32px",
|
|
204
|
+
height: "32px",
|
|
205
|
+
padding: "0px 10px",
|
|
206
|
+
borderRadius: "12px",
|
|
142
207
|
backgroundColor: (theme) =>
|
|
143
208
|
theme.palette.backgroundPaperElevation?.[11] || "#32344B",
|
|
144
209
|
color: "text.primary",
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
210
|
+
opacity: currentValue === index ? 1 : 0.38,
|
|
211
|
+
fontSize: "13px",
|
|
212
|
+
transition: "all 0.2s ease-in-out",
|
|
213
|
+
position: "relative",
|
|
214
|
+
overflow: "visible",
|
|
215
|
+
"&:hover": {
|
|
216
|
+
opacity: currentValue === index ? 1 : 0.6,
|
|
217
|
+
},
|
|
218
|
+
"&.Mui-selected": {
|
|
219
|
+
opacity: 1,
|
|
220
|
+
backgroundColor: (theme) =>
|
|
221
|
+
theme.palette.backgroundPaperElevation?.[11] ||
|
|
222
|
+
"#32344B",
|
|
223
|
+
color: "text.primary",
|
|
224
|
+
},
|
|
225
|
+
"&:focus": {
|
|
226
|
+
outline: "none",
|
|
227
|
+
},
|
|
228
|
+
"&:active": {
|
|
229
|
+
transform: "none",
|
|
230
|
+
},
|
|
231
|
+
}}
|
|
232
|
+
/>
|
|
233
|
+
)
|
|
234
|
+
|
|
235
|
+
if (!showBadge) {
|
|
236
|
+
return (
|
|
237
|
+
<Box key={item.id} sx={{ display: "inline-flex" }}>
|
|
238
|
+
{tab}
|
|
239
|
+
</Box>
|
|
240
|
+
)
|
|
241
|
+
}
|
|
242
|
+
|
|
243
|
+
return (
|
|
244
|
+
<Badge
|
|
245
|
+
key={item.id}
|
|
246
|
+
badgeContent={badgeContent}
|
|
247
|
+
color={item.badge?.color || "error"}
|
|
248
|
+
max={item.badge?.max}
|
|
249
|
+
showZero={item.badge?.showZero}
|
|
250
|
+
anchorOrigin={{
|
|
251
|
+
vertical: "top",
|
|
252
|
+
horizontal: "right",
|
|
253
|
+
}}
|
|
254
|
+
overlap="rectangular"
|
|
255
|
+
sx={{
|
|
256
|
+
"& .MuiBadge-badge": {
|
|
257
|
+
// Ensure badge doesn't inherit tab opacity
|
|
258
|
+
opacity: "1 !important",
|
|
259
|
+
},
|
|
260
|
+
}}
|
|
261
|
+
>
|
|
262
|
+
{tab}
|
|
263
|
+
</Badge>
|
|
264
|
+
)
|
|
265
|
+
})}
|
|
155
266
|
</Tabs>
|
|
156
267
|
</Box>
|
|
157
268
|
|
|
158
269
|
{/* Border line */}
|
|
159
|
-
<Box
|
|
270
|
+
<Box
|
|
271
|
+
sx={{
|
|
272
|
+
mt: (theme) => theme.spacing(2),
|
|
273
|
+
borderBottom: 1,
|
|
274
|
+
borderColor: "divider",
|
|
275
|
+
}}
|
|
276
|
+
/>
|
|
160
277
|
|
|
161
278
|
{/* Tab Content */}
|
|
162
279
|
<Box sx={{ flex: 1, overflow: "auto" }}>
|