@trackunit/react-components 1.12.13 → 1.13.2
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/index.cjs.js +216 -178
- package/index.esm.js +217 -181
- package/package.json +5 -5
- package/src/components/KPI/KPI.d.ts +1 -27
- package/src/components/KPI/KPI.variants.d.ts +1 -9
- package/src/components/KPICard/KPICard.d.ts +18 -2
- package/src/components/KPICard/KPICard.variants.d.ts +0 -3
- package/src/components/KPICard/components/TrendIndicator/TrendIndicator.d.ts +32 -0
- package/src/components/KPICard/components/TrendIndicators.d.ts +13 -0
- package/src/components/List/List.d.ts +2 -0
- package/src/components/Notice/Notice.d.ts +15 -5
- package/src/components/Spacer/Spacer.d.ts +12 -1
- package/src/components/Tag/Tag.d.ts +1 -4
- package/src/components/Tag/Tag.variants.d.ts +8 -1
- package/src/index.d.ts +2 -0
package/index.cjs.js
CHANGED
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
'use strict';
|
|
2
2
|
|
|
3
3
|
var jsxRuntime = require('react/jsx-runtime');
|
|
4
|
-
var react = require('react');
|
|
5
4
|
var sharedUtils = require('@trackunit/shared-utils');
|
|
5
|
+
var react = require('react');
|
|
6
6
|
var uiDesignTokens = require('@trackunit/ui-design-tokens');
|
|
7
7
|
var uiIcons = require('@trackunit/ui-icons');
|
|
8
8
|
var IconSpriteMicro = require('@trackunit/ui-icons/icons-sprite-micro.svg');
|
|
@@ -165,8 +165,17 @@ const Icon = ({ name, size = "medium", className, "data-testid": dataTestId, col
|
|
|
165
165
|
return (jsxRuntime.jsx("span", { "aria-describedby": ariaDescribedBy, "aria-hidden": ariaHidden, "aria-label": ariaLabel ? ariaLabel : stringTs.titleCase(iconName), "aria-labelledby": ariaLabelledBy, className: cvaIcon({ color, size, fontSize, className }), "data-testid": dataTestId, id: ICON_CONTAINER_ID, onClick: onClick, ref: forwardedRef, children: jsxRuntime.jsx("svg", { "aria-labelledby": ICON_CONTAINER_ID, "data-testid": dataTestId ? `${dataTestId}-${iconName}` : iconName, role: "img", style: style, viewBox: correctViewBox, children: jsxRuntime.jsx("use", { href: href[correctIconType], ref: useTagRef }) }) }));
|
|
166
166
|
};
|
|
167
167
|
|
|
168
|
+
/**
|
|
169
|
+
* The Tailwind class for minimum width of tag text.
|
|
170
|
+
* This is the source of truth - use parseTailwindArbitraryValue to derive the numeric value.
|
|
171
|
+
*/
|
|
172
|
+
const TAG_TEXT_MIN_WIDTH_CLASS = "min-w-[80px]";
|
|
168
173
|
const cvaTag = cssClassVarianceUtilities.cvaMerge([
|
|
169
|
-
"
|
|
174
|
+
"grid",
|
|
175
|
+
"grid-cols-[1fr]",
|
|
176
|
+
"has-[[data-slot=icon]]:grid-cols-[auto_1fr]",
|
|
177
|
+
"has-[[data-slot=dismiss]]:grid-cols-[1fr_auto]",
|
|
178
|
+
"has-[[data-slot=icon]]:has-[[data-slot=dismiss]]:grid-cols-[auto_1fr_auto]",
|
|
170
179
|
"justify-center",
|
|
171
180
|
"items-center",
|
|
172
181
|
"rounded-full",
|
|
@@ -174,11 +183,11 @@ const cvaTag = cssClassVarianceUtilities.cvaMerge([
|
|
|
174
183
|
"px-2",
|
|
175
184
|
"text-center",
|
|
176
185
|
"h-min",
|
|
177
|
-
"min-w-[1.5rem]",
|
|
178
186
|
"font-medium",
|
|
179
|
-
"truncate",
|
|
180
187
|
"max-w-full",
|
|
181
188
|
"w-fit",
|
|
189
|
+
"overflow-hidden",
|
|
190
|
+
"min-w-min",
|
|
182
191
|
"text-xs",
|
|
183
192
|
], {
|
|
184
193
|
variants: {
|
|
@@ -222,10 +231,21 @@ const cvaTag = cssClassVarianceUtilities.cvaMerge([
|
|
|
222
231
|
color: "info",
|
|
223
232
|
},
|
|
224
233
|
});
|
|
225
|
-
const cvaTagText = cssClassVarianceUtilities.cvaMerge(["
|
|
226
|
-
|
|
234
|
+
const cvaTagText = cssClassVarianceUtilities.cvaMerge(["whitespace-nowrap"], {
|
|
235
|
+
variants: {
|
|
236
|
+
truncate: {
|
|
237
|
+
true: ["truncate", TAG_TEXT_MIN_WIDTH_CLASS],
|
|
238
|
+
false: "min-w-min",
|
|
239
|
+
},
|
|
240
|
+
},
|
|
241
|
+
defaultVariants: {
|
|
242
|
+
truncate: true,
|
|
243
|
+
},
|
|
244
|
+
});
|
|
245
|
+
const cvaTagIconContainer = cssClassVarianceUtilities.cvaMerge(["shrink-0", "inline-flex", "self-center"]);
|
|
227
246
|
const cvaTagIcon = cssClassVarianceUtilities.cvaMerge(["cursor-pointer", "transition-opacity", "hover:opacity-70", "text-neutral-500"]);
|
|
228
247
|
|
|
248
|
+
const TAG_TEXT_MIN_WIDTH_PX = sharedUtils.parseTailwindArbitraryValue(TAG_TEXT_MIN_WIDTH_CLASS);
|
|
229
249
|
/**
|
|
230
250
|
* The Tag component is used for labeling or categorizing items in the UI.
|
|
231
251
|
* It's commonly used to indicate the status of an asset, mark a feature as Beta,
|
|
@@ -240,6 +260,19 @@ const cvaTagIcon = cssClassVarianceUtilities.cvaMerge(["cursor-pointer", "transi
|
|
|
240
260
|
* @returns {ReactElement} The rendered Tag component.
|
|
241
261
|
*/
|
|
242
262
|
const Tag = ({ className, "data-testid": dataTestId, children, size = "medium", onClose, color = "info", disabled = false, ref, icon, onMouseEnter, }) => {
|
|
263
|
+
const textRef = react.useRef(null);
|
|
264
|
+
const [shouldTruncate, setShouldTruncate] = react.useState(false);
|
|
265
|
+
react.useLayoutEffect(() => {
|
|
266
|
+
// Using simple DOM measurements to avoid the complexity of the useMeasure hook.
|
|
267
|
+
// Resize observers have some overhead and we don't need the full power of the useMeasure hook here.
|
|
268
|
+
// And tags could be rendered many at a time, multiplying the performance penalty of useMeasure.
|
|
269
|
+
// We measure the visible span directly using scrollWidth which gives the full content width
|
|
270
|
+
// even when truncation styles are applied.
|
|
271
|
+
if (textRef.current !== null) {
|
|
272
|
+
const width = textRef.current.scrollWidth;
|
|
273
|
+
setShouldTruncate(width >= TAG_TEXT_MIN_WIDTH_PX);
|
|
274
|
+
}
|
|
275
|
+
}, [children]);
|
|
243
276
|
const isSupportedDismissColor = react.useMemo(() => {
|
|
244
277
|
if (color === "neutral" || color === "primary" || color === "white" || color === "info") {
|
|
245
278
|
return true;
|
|
@@ -255,11 +288,16 @@ const Tag = ({ className, "data-testid": dataTestId, children, size = "medium",
|
|
|
255
288
|
}
|
|
256
289
|
return "default";
|
|
257
290
|
}, [onClose, isSupportedDismissColor, disabled, icon]);
|
|
258
|
-
return (jsxRuntime.jsxs("div", { className: cvaTag({
|
|
291
|
+
return (jsxRuntime.jsxs("div", { className: cvaTag({
|
|
292
|
+
className,
|
|
293
|
+
size,
|
|
294
|
+
color,
|
|
295
|
+
layout,
|
|
296
|
+
border: color === "white" ? "default" : "none",
|
|
297
|
+
}), "data-testid": dataTestId, onMouseEnter: onMouseEnter, ref: ref, children: [icon !== null && icon !== undefined && size === "medium" ? (jsxRuntime.jsx("div", { className: cvaTagIconContainer(), "data-slot": "icon", children: icon })) : null, jsxRuntime.jsx("span", { className: cvaTagText({ truncate: shouldTruncate }), ref: textRef, children: children }), Boolean(onClose) && isSupportedDismissColor && size === "medium" && !disabled ? (
|
|
259
298
|
// a fix for multiselect deselecting tags working together with fade out animation
|
|
260
|
-
jsxRuntime.jsx("div", { className: cvaTagIconContainer(), onMouseDown: onClose, children: jsxRuntime.jsx(Icon, { className: cvaTagIcon(), "data-testid": dataTestId + "Icon", name: "XCircle", size: "small", style: { WebkitTransition: "-webkit-transform 0.150s" }, type: "solid" }) })) : null] }));
|
|
299
|
+
jsxRuntime.jsx("div", { className: cvaTagIconContainer(), "data-slot": "dismiss", onMouseDown: onClose, children: jsxRuntime.jsx(Icon, { className: cvaTagIcon(), "data-testid": dataTestId + "Icon", name: "XCircle", size: "small", style: { WebkitTransition: "-webkit-transform 0.150s" }, type: "solid" }) })) : null] }));
|
|
261
300
|
};
|
|
262
|
-
Tag.displayName = "Tag";
|
|
263
301
|
|
|
264
302
|
/**
|
|
265
303
|
* A component used to display the package name and version in the Storybook docs.
|
|
@@ -1244,7 +1282,7 @@ const cvaCardHeaderContainer = cssClassVarianceUtilities.cvaMerge(["flex", "bord
|
|
|
1244
1282
|
padding: "default",
|
|
1245
1283
|
},
|
|
1246
1284
|
});
|
|
1247
|
-
const cvaCardBodyContainer
|
|
1285
|
+
const cvaCardBodyContainer = cssClassVarianceUtilities.cvaMerge(["flex", "flex-grow", "overflow-auto"], {
|
|
1248
1286
|
variants: {
|
|
1249
1287
|
direction: {
|
|
1250
1288
|
row: "flex-row",
|
|
@@ -1289,7 +1327,7 @@ const Card = react.forwardRef(function Card({ children, onClick, fullHeight = fa
|
|
|
1289
1327
|
* @returns {ReactElement} CardBody component
|
|
1290
1328
|
*/
|
|
1291
1329
|
const CardBody = ({ children, "data-testid": dataTestId, className, direction = "column", gap = "default", padding = "default", id, }) => {
|
|
1292
|
-
return (jsxRuntime.jsx("div", { className: cvaCardBodyContainer
|
|
1330
|
+
return (jsxRuntime.jsx("div", { className: cvaCardBodyContainer({
|
|
1293
1331
|
gap,
|
|
1294
1332
|
padding,
|
|
1295
1333
|
className,
|
|
@@ -2372,7 +2410,7 @@ const useScrollDetection = (options) => {
|
|
|
2372
2410
|
}), [ref, element, scrollState]);
|
|
2373
2411
|
};
|
|
2374
2412
|
|
|
2375
|
-
const cvaZStackContainer = cssClassVarianceUtilities.cvaMerge(["grid", "grid-cols-1", "grid-rows-1"]);
|
|
2413
|
+
const cvaZStackContainer = cssClassVarianceUtilities.cvaMerge(["grid", "grid-cols-1", "grid-rows-1", "isolate"]);
|
|
2376
2414
|
const cvaZStackItem = cssClassVarianceUtilities.cvaMerge(["col-start-1", "col-end-1", "row-start-1", "row-end-2"]);
|
|
2377
2415
|
|
|
2378
2416
|
/**
|
|
@@ -3124,63 +3162,163 @@ const cvaKPI = cssClassVarianceUtilities.cvaMerge(["w-full", "flex", "flex-col"]
|
|
|
3124
3162
|
variant: "default",
|
|
3125
3163
|
},
|
|
3126
3164
|
});
|
|
3127
|
-
const
|
|
3128
|
-
const cvaKPITitleText = cssClassVarianceUtilities.cvaMerge(["truncate", "whitespace-nowrap"]);
|
|
3129
|
-
const cvaKPIvalueText = cssClassVarianceUtilities.cvaMerge(["truncate", "whitespace-nowrap", "text-lg", "font-medium"], {
|
|
3165
|
+
const cvaKPITrendPercentage = cssClassVarianceUtilities.cvaMerge([""], {
|
|
3130
3166
|
variants: {
|
|
3131
|
-
|
|
3132
|
-
|
|
3133
|
-
|
|
3134
|
-
|
|
3167
|
+
color: {
|
|
3168
|
+
success: ["text-success-600"],
|
|
3169
|
+
danger: ["text-danger-600"],
|
|
3170
|
+
warning: ["text-warning-600"],
|
|
3171
|
+
neutral: ["text-neutral-600"],
|
|
3172
|
+
info: ["text-info-600"],
|
|
3135
3173
|
},
|
|
3136
3174
|
},
|
|
3137
3175
|
defaultVariants: {
|
|
3138
|
-
|
|
3176
|
+
color: "success",
|
|
3139
3177
|
},
|
|
3140
3178
|
});
|
|
3141
|
-
|
|
3179
|
+
|
|
3180
|
+
/**
|
|
3181
|
+
* The KPI component is used to display KPIs.
|
|
3182
|
+
*
|
|
3183
|
+
* @param {KPIProps} props - The props for the KPI component
|
|
3184
|
+
* @returns {ReactElement} KPI component
|
|
3185
|
+
*/
|
|
3186
|
+
const KPI = ({ title, value, loading = false, unit, className, "data-testid": dataTestId, tooltipLabel, variant = "default", style, ...rest }) => {
|
|
3187
|
+
const isSmallVariant = variant === "small";
|
|
3188
|
+
return (jsxRuntime.jsx(Tooltip, { className: "min-w-8 shrink-0", "data-testid": dataTestId ? `${dataTestId}-tooltip` : undefined, disabled: tooltipLabel === undefined || tooltipLabel === "", label: tooltipLabel, placement: "bottom", children: jsxRuntime.jsxs("div", { className: cvaKPI({ variant, className }), "data-testid": dataTestId, style: style, ...rest, children: [loading ? (jsxRuntime.jsx(SkeletonLines, { className: tailwindMerge.twMerge("flex", "items-center", "flex-row", isSmallVariant ? "h-4" : "h-5"), "data-testid": dataTestId ? `${dataTestId}-title-loading` : undefined, height: isSmallVariant ? uiDesignTokens.themeFontSize.xs : uiDesignTokens.themeFontSize.sm, lines: 1, width: "80%" })) : (jsxRuntime.jsx(Text, { className: tailwindMerge.twMerge("truncate", "whitespace-nowrap"), "data-testid": dataTestId ? `${dataTestId}-title` : undefined, size: isSmallVariant ? "small" : "medium", subtle: true, weight: isSmallVariant ? "normal" : "bold", children: title })), jsxRuntime.jsx("div", { className: tailwindMerge.twMerge("truncate", "whitespace-nowrap"), children: loading ? (jsxRuntime.jsx(SkeletonLines, { className: "flex h-7 flex-row items-center", "data-testid": dataTestId ? `${dataTestId}-value-loading` : undefined, height: uiDesignTokens.themeFontSize.base, lines: 1, width: "100%" })) : (jsxRuntime.jsxs(Text, { className: "truncate whitespace-nowrap text-lg font-medium", "data-testid": dataTestId ? `${dataTestId}-value` : undefined, size: isSmallVariant ? "small" : "large", type: "div", weight: isSmallVariant ? "bold" : "thick", children: [value, " ", unit] })) })] }) }));
|
|
3189
|
+
};
|
|
3190
|
+
|
|
3191
|
+
/**
|
|
3192
|
+
* The TrendIndicator component is used within the KPI Card component to display the trend indicator.
|
|
3193
|
+
*
|
|
3194
|
+
* @param {TrendIndicatorProps} props - The props for the TrendIndicator component
|
|
3195
|
+
* @returns {ReactElement} TrendIndicator component
|
|
3196
|
+
*/
|
|
3197
|
+
const TrendIndicator = ({ value, trend, label, icon = undefined, color = undefined, "data-testid": dataTestId, className, }) => {
|
|
3198
|
+
return (jsxRuntime.jsxs("div", { className: tailwindMerge.twMerge("flex flex-row items-center gap-1", className), "data-testid": dataTestId, children: [value !== undefined ? (jsxRuntime.jsx(Text, { "data-testid": dataTestId ? `${dataTestId}-value` : undefined, size: "small", weight: "normal", children: value })) : null, jsxRuntime.jsxs("div", { className: "flex items-center", children: [icon ? (jsxRuntime.jsx(Icon, { color: color, "data-testid": dataTestId ? `${dataTestId}-icon` : undefined, name: icon, size: "small" })) : null, jsxRuntime.jsx(Text, { className: cvaKPITrendPercentage({ color }), "data-testid": dataTestId ? `${dataTestId}-trend` : undefined, size: "small", weight: "bold", children: trend })] }), jsxRuntime.jsx(Text, { "data-testid": dataTestId ? `${dataTestId}-label` : undefined, size: "small", weight: "normal", children: label })] }));
|
|
3199
|
+
};
|
|
3200
|
+
|
|
3201
|
+
/**
|
|
3202
|
+
* The TrendIndicators component is used within the KPI Card component to display the trend indicators.
|
|
3203
|
+
*
|
|
3204
|
+
* @param {TrendIndicatorsProps} props - The props for the TrendIndicators component
|
|
3205
|
+
* @returns {ReactElement} TrendIndicators component
|
|
3206
|
+
*/
|
|
3207
|
+
const TrendIndicators = ({ trends, "data-testid": dataTestId, className, }) => {
|
|
3208
|
+
return (jsxRuntime.jsx("span", { className: tailwindMerge.twMerge("flex flex-row items-center gap-1", className), "data-testid": dataTestId, children: trends.map((trend, index) => (jsxRuntime.jsx(TrendIndicator, { "data-testid": dataTestId ? `${dataTestId}-trend-indicator-${index}` : undefined, ...trend }, index))) }));
|
|
3209
|
+
};
|
|
3210
|
+
|
|
3211
|
+
const cvaValueBar = cssClassVarianceUtilities.cvaMerge([
|
|
3212
|
+
"w-full",
|
|
3213
|
+
"overflow-hidden",
|
|
3214
|
+
"rounded",
|
|
3215
|
+
"bg-neutral-100",
|
|
3216
|
+
"appearance-none",
|
|
3217
|
+
"[&::-webkit-progress-bar]:bg-transparent",
|
|
3218
|
+
"[&::-webkit-progress-value]:bg-current",
|
|
3219
|
+
"[&::-moz-progress-bar]:bg-current",
|
|
3220
|
+
], {
|
|
3142
3221
|
variants: {
|
|
3143
|
-
|
|
3144
|
-
|
|
3145
|
-
|
|
3146
|
-
|
|
3222
|
+
size: {
|
|
3223
|
+
extraSmall: "h-1",
|
|
3224
|
+
small: "h-3",
|
|
3225
|
+
large: "h-9",
|
|
3147
3226
|
},
|
|
3148
3227
|
},
|
|
3149
3228
|
defaultVariants: {
|
|
3150
|
-
|
|
3229
|
+
size: "small",
|
|
3151
3230
|
},
|
|
3152
3231
|
});
|
|
3153
|
-
const
|
|
3232
|
+
const cvaValueBarText = cssClassVarianceUtilities.cvaMerge(["whitespace-nowrap"], {
|
|
3154
3233
|
variants: {
|
|
3155
|
-
|
|
3156
|
-
|
|
3157
|
-
|
|
3234
|
+
size: {
|
|
3235
|
+
small: "leading-xs text-xs font-medium text-neutral-600",
|
|
3236
|
+
large: "absolute pl-3 text-base text-white drop-shadow-lg",
|
|
3158
3237
|
},
|
|
3159
3238
|
},
|
|
3160
3239
|
defaultVariants: {
|
|
3161
|
-
|
|
3240
|
+
size: "small",
|
|
3162
3241
|
},
|
|
3163
3242
|
});
|
|
3164
3243
|
|
|
3165
|
-
const LoadingContent$1 = () => (jsxRuntime.jsx("div", { className: "flex h-11 flex-row items-center gap-3", "data-testid": "kpi-card-loading-content", children: jsxRuntime.jsx("div", { className: "w-full", children: jsxRuntime.jsx(SkeletonLines, { gap: 3, height: [14, 18], lines: 2, width: [80, 60] }) }) }));
|
|
3166
3244
|
/**
|
|
3167
|
-
*
|
|
3168
|
-
|
|
3169
|
-
* @param {
|
|
3170
|
-
* @
|
|
3245
|
+
* Helper function to get normalized score in range 0-1 used by the ValueBar
|
|
3246
|
+
|
|
3247
|
+
* @param {number} value - value for which score should be returned
|
|
3248
|
+
* @param {number} min - min range value
|
|
3249
|
+
* @param {number} max - max range value
|
|
3250
|
+
* @param {boolean} zeroScoreAllowed - If true, allows the score to be exactly 0 when the value is less than or equal to the minimum.
|
|
3251
|
+
* If false or not provided, ensures a minimal score (0.01) is returned to always render a small fragment.
|
|
3252
|
+
* @returns {number} normalized score
|
|
3171
3253
|
*/
|
|
3172
|
-
const
|
|
3173
|
-
|
|
3174
|
-
|
|
3175
|
-
|
|
3176
|
-
|
|
3177
|
-
|
|
3254
|
+
const getScore = (value, min, max, zeroScoreAllowed) => {
|
|
3255
|
+
if (value <= min) {
|
|
3256
|
+
if (zeroScoreAllowed === true) {
|
|
3257
|
+
return 0;
|
|
3258
|
+
}
|
|
3259
|
+
return 0.01; // always render at least some small fragment
|
|
3260
|
+
}
|
|
3261
|
+
if (value >= max) {
|
|
3262
|
+
return 1;
|
|
3263
|
+
}
|
|
3264
|
+
return (value - min) / (max - min);
|
|
3178
3265
|
};
|
|
3179
|
-
|
|
3180
|
-
|
|
3181
|
-
|
|
3266
|
+
/**
|
|
3267
|
+
* Helper function to get default color used by the ValueBar
|
|
3268
|
+
|
|
3269
|
+
* @param {number} score - score number for which color should be returned
|
|
3270
|
+
* @returns {string} color value
|
|
3271
|
+
*/
|
|
3272
|
+
const getDefaultFillColor = (score) => {
|
|
3273
|
+
if (score < 0.3) {
|
|
3274
|
+
return uiDesignTokens.color("DANGER", 500, "CSS");
|
|
3275
|
+
}
|
|
3276
|
+
if (score >= 0.6) {
|
|
3277
|
+
return uiDesignTokens.color("SUCCESS", 600, "CSS");
|
|
3278
|
+
}
|
|
3279
|
+
return uiDesignTokens.color("WARNING", 300, "CSS");
|
|
3280
|
+
};
|
|
3281
|
+
/**
|
|
3282
|
+
* Helper function to get custom color used by the ValueBar
|
|
3283
|
+
|
|
3284
|
+
* @param {number} score - score number for which color should be returned
|
|
3285
|
+
* @param {LevelColors} levelColors - custom colors and levels definitions
|
|
3286
|
+
* @returns {string} color value
|
|
3287
|
+
*/
|
|
3288
|
+
const getFillColor = (score, levelColors) => {
|
|
3289
|
+
if (levelColors.low !== undefined && score < (levelColors.low.level !== undefined ? levelColors.low.level : 0)) {
|
|
3290
|
+
return levelColors.low.color;
|
|
3291
|
+
}
|
|
3292
|
+
if (levelColors.high !== undefined && score >= (levelColors.high.level !== undefined ? levelColors.high.level : 0)) {
|
|
3293
|
+
return levelColors.high.color;
|
|
3182
3294
|
}
|
|
3183
|
-
return
|
|
3295
|
+
return levelColors.medium?.color ?? uiDesignTokens.color("WARNING", 300);
|
|
3296
|
+
};
|
|
3297
|
+
/**
|
|
3298
|
+
* Helper function to get color used by the ValueBar
|
|
3299
|
+
|
|
3300
|
+
* @param {number} value - value for which color should be returned
|
|
3301
|
+
* @param {number} min - min range value
|
|
3302
|
+
* @param {number} max - max range value
|
|
3303
|
+
* @param {LevelColors} levelColors - level colors used to coloring the bar
|
|
3304
|
+
* @returns {ReactElement} ValueBar component
|
|
3305
|
+
*/
|
|
3306
|
+
const getValueBarColorByValue = (value, min, max, levelColors) => {
|
|
3307
|
+
const score = getScore(value, min, max);
|
|
3308
|
+
return getFillColor(score, levelColors);
|
|
3309
|
+
};
|
|
3310
|
+
|
|
3311
|
+
/**
|
|
3312
|
+
* ValueBar component is used to display value on a colorful bar within provided range.
|
|
3313
|
+
|
|
3314
|
+
* @param {ValueBarProps} props - The props for the ValueBar component
|
|
3315
|
+
* @returns {ReactElement} ValueBar component
|
|
3316
|
+
*/
|
|
3317
|
+
const ValueBar = ({ value, min = 0, max = 100, unit, size = "small", levelColors, valueColor, showValue = false, className, "data-testid": dataTestId, zeroScoreAllowed = false, }) => {
|
|
3318
|
+
const score = getScore(value, min, max, zeroScoreAllowed);
|
|
3319
|
+
const barFillColor = levelColors ? getFillColor(score, levelColors) : getDefaultFillColor(score);
|
|
3320
|
+
const valueText = `${Number(value.toFixed(1))}${sharedUtils.nonNullable(unit) ? unit : ""}`;
|
|
3321
|
+
return (jsxRuntime.jsxs("span", { className: "relative flex items-center gap-2", "data-testid": dataTestId, children: [jsxRuntime.jsx("progress", { "aria-label": valueText, className: cvaValueBar({ className, size }), max: 100, style: { color: barFillColor }, value: score * 100 }), showValue && (size === "small" || size === "large") ? (jsxRuntime.jsx(Text, { className: cvaValueBarText({ size }), "data-testid": dataTestId ? `${dataTestId}-value` : undefined, children: jsxRuntime.jsx("span", { style: valueColor ? { color: valueColor } : undefined, children: valueText }) })) : null] }));
|
|
3184
3322
|
};
|
|
3185
3323
|
|
|
3186
3324
|
const cvaKPICard = cssClassVarianceUtilities.cvaMerge([
|
|
@@ -3214,14 +3352,6 @@ const cvaKPIIconContainer = cssClassVarianceUtilities.cvaMerge(["flex", "items-c
|
|
|
3214
3352
|
},
|
|
3215
3353
|
},
|
|
3216
3354
|
});
|
|
3217
|
-
const cvaCardBodyContainer = cssClassVarianceUtilities.cvaMerge(["grid", "grid-cols-[1fr_auto]", "px-3", "pb-2", "pt-3"], {
|
|
3218
|
-
variants: {
|
|
3219
|
-
iconName: {
|
|
3220
|
-
true: "gap-2",
|
|
3221
|
-
false: "gap-3 ",
|
|
3222
|
-
},
|
|
3223
|
-
},
|
|
3224
|
-
});
|
|
3225
3355
|
|
|
3226
3356
|
/**
|
|
3227
3357
|
* The KPICard component is used to display KPIs.
|
|
@@ -3229,13 +3359,15 @@ const cvaCardBodyContainer = cssClassVarianceUtilities.cvaMerge(["grid", "grid-c
|
|
|
3229
3359
|
* @param {KPICardProps} props - The props for the KPICard component
|
|
3230
3360
|
* @returns {ReactElement} KPICard component
|
|
3231
3361
|
*/
|
|
3232
|
-
const KPICard = ({ isActive = false, onClick, className, "data-testid": dataTestId, children, iconName = undefined, iconColor = "info", loading = false, ...rest }) => {
|
|
3362
|
+
const KPICard = ({ isActive = false, onClick, className, "data-testid": dataTestId, children, iconName = undefined, iconColor = "info", loading = false, notice, valueBar, trends, unit, ...rest }) => {
|
|
3233
3363
|
const isClickable = Boolean(onClick !== undefined && loading !== true);
|
|
3234
3364
|
return (jsxRuntime.jsx(Card, { className: cvaKPICard({
|
|
3235
3365
|
isClickable,
|
|
3236
3366
|
isActive,
|
|
3237
3367
|
className,
|
|
3238
|
-
}), "data-testid": dataTestId ? dataTestId : undefined, onClick: onClick, children: jsxRuntime.jsxs(CardBody, { className:
|
|
3368
|
+
}), "data-testid": dataTestId ? dataTestId : undefined, onClick: onClick, children: jsxRuntime.jsxs(CardBody, { className: "grid gap-2 px-3 pb-2 pt-3", gap: "none", padding: "none", children: [jsxRuntime.jsxs("div", { className: "grid grid-cols-[1fr_auto] justify-between gap-2", children: [jsxRuntime.jsx(KPI, { ...rest, className: "p-0", "data-testid": dataTestId ? `${dataTestId}-kpi` : undefined, loading: loading, unit: unit }), iconName ? (jsxRuntime.jsx("div", { className: cvaKPIIconContainer({ iconColor }), children: jsxRuntime.jsx(Icon, { name: iconName, size: "small", type: "solid" }) })) : null] }), trends !== undefined && trends.length > 0 ? (loading ? (jsxRuntime.jsx(SkeletonLines, { className: "h-4", "data-testid": dataTestId ? `${dataTestId}-trend-indicator-loading` : undefined, height: uiDesignTokens.themeFontSize.xs, lines: 1, width: "100%" })) : (jsxRuntime.jsx(TrendIndicators, { "data-testid": dataTestId ? `${dataTestId}-trend-indicators` : undefined, trends: trends }))) : null, valueBar !== undefined ? (loading ? (jsxRuntime.jsx(SkeletonLines, { className: "h-4", "data-testid": dataTestId ? `${dataTestId}-value-bar-loading` : undefined, gap: 0, height: uiDesignTokens.themeFontSize.xs, lines: 1, width: "100%" })) : (jsxRuntime.jsx(ValueBar, { className: "h-2", "data-testid": dataTestId ? `${dataTestId}-value-bar` : undefined, ...valueBar }))) : null, notice !== undefined ? (loading ? (jsxRuntime.jsx(SkeletonLines, { className: "h-4", "data-testid": dataTestId ? `${dataTestId}-notice-loading` : undefined, gap: 0, height: uiDesignTokens.themeFontSize.xs, lines: 1, width: "100%" })) : (
|
|
3369
|
+
// NOTE: Can't use Notice component here due to the non-flexible text styling options
|
|
3370
|
+
jsxRuntime.jsxs("div", { className: "flex items-center gap-1 truncate", "data-testid": dataTestId ? `${dataTestId}-notice` : undefined, children: [notice.iconName ? (jsxRuntime.jsx(Icon, { color: notice.iconColor, "data-testid": dataTestId ? `${dataTestId}-notice-icon` : undefined, name: notice.iconName, size: "small" })) : null, jsxRuntime.jsx(Text, { className: "truncate text-neutral-900", "data-testid": dataTestId ? `${dataTestId}-notice-label` : undefined, size: "small", children: notice.label })] }))) : null, children] }) }));
|
|
3239
3371
|
};
|
|
3240
3372
|
|
|
3241
3373
|
const cvaListContainer = cssClassVarianceUtilities.cvaMerge(["overflow-y-auto", "overflow-x-hidden", "h-full"], {
|
|
@@ -3371,6 +3503,7 @@ const ListLoadingIndicator = ({ type, hasThumbnail, thumbnailShape, hasDescripti
|
|
|
3371
3503
|
*
|
|
3372
3504
|
* @example Basic usage
|
|
3373
3505
|
* ```tsx
|
|
3506
|
+
* import { useList, List } from "@trackunit/react-components";
|
|
3374
3507
|
* const list = useList({
|
|
3375
3508
|
* count: items.length,
|
|
3376
3509
|
* getItem: index => items[index],
|
|
@@ -3387,6 +3520,7 @@ const ListLoadingIndicator = ({ type, hasThumbnail, thumbnailShape, hasDescripti
|
|
|
3387
3520
|
* ```
|
|
3388
3521
|
* @example With header
|
|
3389
3522
|
* ```tsx
|
|
3523
|
+
* import { useList, List } from "@trackunit/react-components";
|
|
3390
3524
|
* const list = useList({
|
|
3391
3525
|
* count: items.length,
|
|
3392
3526
|
* getItem: index => items[index],
|
|
@@ -3895,7 +4029,11 @@ const cvaMenuList = cssClassVarianceUtilities.cvaMerge([
|
|
|
3895
4029
|
"overflow-y-auto",
|
|
3896
4030
|
]);
|
|
3897
4031
|
const cvaMenuListDivider = cssClassVarianceUtilities.cvaMerge(["mx-[-4px]", "my-0.5", "min-h-px", "bg-neutral-300"]);
|
|
3898
|
-
const cvaMenuListMultiSelect = cssClassVarianceUtilities.cvaMerge(
|
|
4032
|
+
const cvaMenuListMultiSelect = cssClassVarianceUtilities.cvaMerge([
|
|
4033
|
+
"!has-[:checked]:bg-primary-100",
|
|
4034
|
+
"!hover:has-[:checked]:bg-primary-200",
|
|
4035
|
+
"!focus-within:has-[:checked]:bg-primary-100",
|
|
4036
|
+
]);
|
|
3899
4037
|
const cvaMenuListItem = cssClassVarianceUtilities.cvaMerge("max-w-full");
|
|
3900
4038
|
|
|
3901
4039
|
/**
|
|
@@ -3986,7 +4124,7 @@ const cvaMenuItemPrefix = cssClassVarianceUtilities.cvaMerge([
|
|
|
3986
4124
|
], {
|
|
3987
4125
|
variants: {
|
|
3988
4126
|
selected: {
|
|
3989
|
-
true: "text-
|
|
4127
|
+
true: "text-primary-600",
|
|
3990
4128
|
false: "",
|
|
3991
4129
|
},
|
|
3992
4130
|
variant: {
|
|
@@ -4101,7 +4239,7 @@ const MenuList = ({ "data-testid": dataTestId, className, children, isMulti = fa
|
|
|
4101
4239
|
: cvaMenuListItem({ className: menuItem.props.className }),
|
|
4102
4240
|
selected: isSelected,
|
|
4103
4241
|
suffix: menuItem.props.suffix ??
|
|
4104
|
-
(isMulti && isSelected ? jsxRuntime.jsx(Icon, { className: "
|
|
4242
|
+
(isMulti && isSelected ? jsxRuntime.jsx(Icon, { className: "text-primary-600 block", name: "Check", size: "medium" }) : null),
|
|
4105
4243
|
});
|
|
4106
4244
|
}
|
|
4107
4245
|
return null;
|
|
@@ -4129,8 +4267,8 @@ const MoreMenu = ({ className, "data-testid": dataTestId, popoverProps, iconProp
|
|
|
4129
4267
|
return (jsxRuntime.jsx("div", { className: cvaMoreMenu({ className }), "data-testid": dataTestId ? dataTestId : undefined, ref: actionMenuRef, children: jsxRuntime.jsxs(Popover, { placement: "bottom-end", ...popoverProps, children: [jsxRuntime.jsx(PopoverTrigger, { children: customButton ?? (jsxRuntime.jsx(IconButton, { "data-testid": "more-menu-icon", ...iconButtonProps, icon: jsxRuntime.jsx(Icon, { name: "EllipsisHorizontal", ...iconProps }) })) }), jsxRuntime.jsx(PopoverContent, { portalId: customPortalId, children: close => (typeof children === "function" ? children(close) : children) })] }) }));
|
|
4130
4268
|
};
|
|
4131
4269
|
|
|
4132
|
-
const cvaNotice = cssClassVarianceUtilities.cvaMerge(["flex", "items-center"]);
|
|
4133
|
-
const cvaNoticeLabel = cssClassVarianceUtilities.cvaMerge(["
|
|
4270
|
+
const cvaNotice = cssClassVarianceUtilities.cvaMerge(["flex", "items-center", "gap-1"]);
|
|
4271
|
+
const cvaNoticeLabel = cssClassVarianceUtilities.cvaMerge(["font-medium", "text-sm", "overflow-hidden", "text-ellipsis"], {
|
|
4134
4272
|
variants: {
|
|
4135
4273
|
color: {
|
|
4136
4274
|
neutral: "text-neutral-400",
|
|
@@ -4170,12 +4308,12 @@ const cvaNoticeIcon = cssClassVarianceUtilities.cvaMerge(["rounded-full", "items
|
|
|
4170
4308
|
* _**Do use** notices to communicate non-essential information that does not necessarily require action to be taken._
|
|
4171
4309
|
*
|
|
4172
4310
|
* _**Do not use** notices for essential information (use `<Alert/>` instead), or to communicate information related to the state of an asset (use `<Indicator/>` instead)._
|
|
4173
|
-
|
|
4311
|
+
*
|
|
4174
4312
|
* @param {NoticeProps} props - The props for the Notice component
|
|
4175
4313
|
* @returns {ReactElement} Notice component
|
|
4176
4314
|
*/
|
|
4177
|
-
const Notice = ({ "data-testid": dataTestId,
|
|
4178
|
-
return (jsxRuntime.jsx(Tooltip, { className: className, disabled: withTooltip === false, label: tooltipLabel, placement: "bottom", children: jsxRuntime.jsxs("div", { "aria-label": label, className: cvaNotice(), "data-testid": dataTestId, ...rest, children: [jsxRuntime.jsx("div", { className: cvaNoticeIcon({ color }), "data-testid": dataTestId ? `${dataTestId}-icon` : "notice-icon", children:
|
|
4315
|
+
const Notice = ({ "data-testid": dataTestId, iconName = undefined, iconSize = "medium", iconColor = undefined, label, color = "neutral", withLabel = true, className, tooltipLabel = label, withTooltip = false, size = "medium", ...rest }) => {
|
|
4316
|
+
return (jsxRuntime.jsx(Tooltip, { className: className, disabled: withTooltip === false, label: tooltipLabel, placement: "bottom", children: jsxRuntime.jsxs("div", { "aria-label": label, className: cvaNotice(), "data-testid": dataTestId, ...rest, children: [sharedUtils.nonNullable(iconName) ? (jsxRuntime.jsx("div", { className: cvaNoticeIcon({ color: iconColor || color }), "data-testid": dataTestId ? `${dataTestId}-icon` : "notice-icon", children: jsxRuntime.jsx(Icon, { name: iconName, size: iconSize }) })) : null, label && withLabel ? (jsxRuntime.jsx("div", { className: cvaNoticeLabel({ color, size }), "data-testid": dataTestId ? `${dataTestId}-label` : "notice-label", children: label })) : null] }) }));
|
|
4179
4317
|
};
|
|
4180
4318
|
|
|
4181
4319
|
const cvaPage = cssClassVarianceUtilities.cvaMerge(["grid", "h-full"], {
|
|
@@ -4565,7 +4703,18 @@ const cvaSpacer = cssClassVarianceUtilities.cvaMerge([], {
|
|
|
4565
4703
|
|
|
4566
4704
|
/**
|
|
4567
4705
|
* The Spacer component is used for adding a bit of space in the ui.
|
|
4568
|
-
|
|
4706
|
+
*
|
|
4707
|
+
* @example basic usage
|
|
4708
|
+
* ```tsx
|
|
4709
|
+
* import { Spacer } from "@trackunit/react-components";
|
|
4710
|
+
* const MySpacer = () => {
|
|
4711
|
+
* return (
|
|
4712
|
+
* <div>
|
|
4713
|
+
* <Spacer size="small" border data-testid="my-spacer-testid" />
|
|
4714
|
+
* </div>
|
|
4715
|
+
* );
|
|
4716
|
+
* };
|
|
4717
|
+
* ```
|
|
4569
4718
|
* @param {SpacerProps} props - The props for the Spacer component
|
|
4570
4719
|
* @returns {ReactElement} Spacer component
|
|
4571
4720
|
*/
|
|
@@ -4995,119 +5144,6 @@ const ToggleButton = ({ title, size, children, "data-testid": dataTestId, classN
|
|
|
4995
5144
|
return (jsxRuntime.jsx("button", { className: tailwindMerge.twMerge("flex items-center justify-center gap-1 self-stretch", paddingClasses, className), "data-testid": dataTestId, title: isIconOnly ? title : undefined, type: "button", ...rest, children: isIconOnly ? (icon) : (jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [iconPrefix, children] })) }));
|
|
4996
5145
|
};
|
|
4997
5146
|
|
|
4998
|
-
const cvaValueBar = cssClassVarianceUtilities.cvaMerge([
|
|
4999
|
-
"w-full",
|
|
5000
|
-
"overflow-hidden",
|
|
5001
|
-
"rounded",
|
|
5002
|
-
"bg-neutral-100",
|
|
5003
|
-
"appearance-none",
|
|
5004
|
-
"[&::-webkit-progress-bar]:bg-transparent",
|
|
5005
|
-
"[&::-webkit-progress-value]:bg-current",
|
|
5006
|
-
"[&::-moz-progress-bar]:bg-current",
|
|
5007
|
-
], {
|
|
5008
|
-
variants: {
|
|
5009
|
-
size: {
|
|
5010
|
-
extraSmall: "h-1",
|
|
5011
|
-
small: "h-3",
|
|
5012
|
-
large: "h-9",
|
|
5013
|
-
},
|
|
5014
|
-
},
|
|
5015
|
-
defaultVariants: {
|
|
5016
|
-
size: "small",
|
|
5017
|
-
},
|
|
5018
|
-
});
|
|
5019
|
-
const cvaValueBarText = cssClassVarianceUtilities.cvaMerge(["whitespace-nowrap"], {
|
|
5020
|
-
variants: {
|
|
5021
|
-
size: {
|
|
5022
|
-
small: "text-sm font-bold text-neutral-400",
|
|
5023
|
-
large: "absolute pl-3 text-base text-white drop-shadow-lg",
|
|
5024
|
-
},
|
|
5025
|
-
},
|
|
5026
|
-
defaultVariants: {
|
|
5027
|
-
size: "small",
|
|
5028
|
-
},
|
|
5029
|
-
});
|
|
5030
|
-
|
|
5031
|
-
/**
|
|
5032
|
-
* Helper function to get normalized score in range 0-1 used by the ValueBar
|
|
5033
|
-
|
|
5034
|
-
* @param {number} value - value for which score should be returned
|
|
5035
|
-
* @param {number} min - min range value
|
|
5036
|
-
* @param {number} max - max range value
|
|
5037
|
-
* @param {boolean} zeroScoreAllowed - If true, allows the score to be exactly 0 when the value is less than or equal to the minimum.
|
|
5038
|
-
* If false or not provided, ensures a minimal score (0.01) is returned to always render a small fragment.
|
|
5039
|
-
* @returns {number} normalized score
|
|
5040
|
-
*/
|
|
5041
|
-
const getScore = (value, min, max, zeroScoreAllowed) => {
|
|
5042
|
-
if (value <= min) {
|
|
5043
|
-
if (zeroScoreAllowed === true) {
|
|
5044
|
-
return 0;
|
|
5045
|
-
}
|
|
5046
|
-
return 0.01; // always render at least some small fragment
|
|
5047
|
-
}
|
|
5048
|
-
if (value >= max) {
|
|
5049
|
-
return 1;
|
|
5050
|
-
}
|
|
5051
|
-
return (value - min) / (max - min);
|
|
5052
|
-
};
|
|
5053
|
-
/**
|
|
5054
|
-
* Helper function to get default color used by the ValueBar
|
|
5055
|
-
|
|
5056
|
-
* @param {number} score - score number for which color should be returned
|
|
5057
|
-
* @returns {string} color value
|
|
5058
|
-
*/
|
|
5059
|
-
const getDefaultFillColor = (score) => {
|
|
5060
|
-
if (score < 0.3) {
|
|
5061
|
-
return uiDesignTokens.color("DANGER", 500, "CSS");
|
|
5062
|
-
}
|
|
5063
|
-
if (score >= 0.6) {
|
|
5064
|
-
return uiDesignTokens.color("SUCCESS", 600, "CSS");
|
|
5065
|
-
}
|
|
5066
|
-
return uiDesignTokens.color("WARNING", 300, "CSS");
|
|
5067
|
-
};
|
|
5068
|
-
/**
|
|
5069
|
-
* Helper function to get custom color used by the ValueBar
|
|
5070
|
-
|
|
5071
|
-
* @param {number} score - score number for which color should be returned
|
|
5072
|
-
* @param {LevelColors} levelColors - custom colors and levels definitions
|
|
5073
|
-
* @returns {string} color value
|
|
5074
|
-
*/
|
|
5075
|
-
const getFillColor = (score, levelColors) => {
|
|
5076
|
-
if (levelColors.low !== undefined && score < (levelColors.low.level !== undefined ? levelColors.low.level : 0)) {
|
|
5077
|
-
return levelColors.low.color;
|
|
5078
|
-
}
|
|
5079
|
-
if (levelColors.high !== undefined && score >= (levelColors.high.level !== undefined ? levelColors.high.level : 0)) {
|
|
5080
|
-
return levelColors.high.color;
|
|
5081
|
-
}
|
|
5082
|
-
return levelColors.medium?.color ?? uiDesignTokens.color("WARNING", 300);
|
|
5083
|
-
};
|
|
5084
|
-
/**
|
|
5085
|
-
* Helper function to get color used by the ValueBar
|
|
5086
|
-
|
|
5087
|
-
* @param {number} value - value for which color should be returned
|
|
5088
|
-
* @param {number} min - min range value
|
|
5089
|
-
* @param {number} max - max range value
|
|
5090
|
-
* @param {LevelColors} levelColors - level colors used to coloring the bar
|
|
5091
|
-
* @returns {ReactElement} ValueBar component
|
|
5092
|
-
*/
|
|
5093
|
-
const getValueBarColorByValue = (value, min, max, levelColors) => {
|
|
5094
|
-
const score = getScore(value, min, max);
|
|
5095
|
-
return getFillColor(score, levelColors);
|
|
5096
|
-
};
|
|
5097
|
-
|
|
5098
|
-
/**
|
|
5099
|
-
* ValueBar component is used to display value on a colorful bar within provided range.
|
|
5100
|
-
|
|
5101
|
-
* @param {ValueBarProps} props - The props for the ValueBar component
|
|
5102
|
-
* @returns {ReactElement} ValueBar component
|
|
5103
|
-
*/
|
|
5104
|
-
const ValueBar = ({ value, min = 0, max = 100, unit, size = "small", levelColors, valueColor, showValue = false, className, "data-testid": dataTestId, zeroScoreAllowed = false, }) => {
|
|
5105
|
-
const score = getScore(value, min, max, zeroScoreAllowed);
|
|
5106
|
-
const barFillColor = levelColors ? getFillColor(score, levelColors) : getDefaultFillColor(score);
|
|
5107
|
-
const valueText = `${Number(value.toFixed(1))}${sharedUtils.nonNullable(unit) ? unit : ""}`;
|
|
5108
|
-
return (jsxRuntime.jsxs("span", { className: "relative flex items-center gap-2", "data-testid": dataTestId, children: [jsxRuntime.jsx("progress", { "aria-label": valueText, className: cvaValueBar({ className, size }), max: 100, style: { color: barFillColor }, value: score * 100 }), showValue && (size === "small" || size === "large") ? (jsxRuntime.jsx(Text, { className: cvaValueBarText({ size }), "data-testid": dataTestId ? `${dataTestId}-value` : undefined, children: jsxRuntime.jsx("span", { style: valueColor ? { color: valueColor } : undefined, children: valueText }) })) : null] }));
|
|
5109
|
-
};
|
|
5110
|
-
|
|
5111
5147
|
/**
|
|
5112
5148
|
* Base64URL encode bytes to a URL-safe string
|
|
5113
5149
|
*/
|
|
@@ -6111,6 +6147,8 @@ exports.Tag = Tag;
|
|
|
6111
6147
|
exports.Text = Text;
|
|
6112
6148
|
exports.ToggleGroup = ToggleGroup;
|
|
6113
6149
|
exports.Tooltip = Tooltip;
|
|
6150
|
+
exports.TrendIndicator = TrendIndicator;
|
|
6151
|
+
exports.TrendIndicators = TrendIndicators;
|
|
6114
6152
|
exports.ValueBar = ValueBar;
|
|
6115
6153
|
exports.ZStack = ZStack;
|
|
6116
6154
|
exports.cvaButton = cvaButton;
|