@czi-sds/data-viz 0.14.0 → 0.14.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/dist/index.cjs.d.ts +30 -13
- package/dist/index.cjs.js +244 -136
- package/dist/index.esm.d.ts +30 -13
- package/dist/index.esm.js +244 -136
- package/dist/tsconfig.tsbuildinfo +1 -1
- package/package.json +2 -2
package/dist/index.esm.js
CHANGED
|
@@ -1023,7 +1023,7 @@ const SDSLightThemeColors = {
|
|
|
1023
1023
|
purple: {
|
|
1024
1024
|
"100": "#efeafe",
|
|
1025
1025
|
"200": "#e4dbfc",
|
|
1026
|
-
"300": "#
|
|
1026
|
+
"300": "#cbbaf8",
|
|
1027
1027
|
"400": "#b296f2",
|
|
1028
1028
|
"500": "#8b54e2",
|
|
1029
1029
|
"600": "#6526b5",
|
|
@@ -1194,7 +1194,7 @@ const percentToHex = (percentOpacity) => {
|
|
|
1194
1194
|
// Convert percentage to 0-255 range
|
|
1195
1195
|
const alphaValue = Math.round((clampedPercent / 100) * 255);
|
|
1196
1196
|
// Convert to hex and pad with leading zero if needed
|
|
1197
|
-
return alphaValue.toString(16).padStart(2, "0").
|
|
1197
|
+
return alphaValue.toString(16).padStart(2, "0").toLowerCase();
|
|
1198
1198
|
};
|
|
1199
1199
|
/**
|
|
1200
1200
|
* Adds opacity to a hex color by appending the hex opacity value.
|
|
@@ -1873,10 +1873,10 @@ const fontBodyS$1 = fontBody("s", "regular");
|
|
|
1873
1873
|
const fontBodyXs$2 = fontBody("xs", "regular");
|
|
1874
1874
|
const fontBodyXxs$1 = fontBody("xxs", "regular");
|
|
1875
1875
|
const fontBodyXxxs$1 = fontBody("xxxs", "regular");
|
|
1876
|
-
const fontBodyXxxxs = fontBody("xxxxs", "regular");
|
|
1877
1876
|
const fontBodyMediumL = fontBody("l", "medium");
|
|
1878
1877
|
const fontBodyMediumS = fontBody("s", "medium");
|
|
1879
1878
|
const fontBodyMediumXs = fontBody("xs", "medium");
|
|
1879
|
+
const fontBodyMediumXxxs = fontBody("xxxs", "medium");
|
|
1880
1880
|
const fontBodySemiboldL = fontBody("l", "semibold");
|
|
1881
1881
|
const fontBodySemiboldM = fontBody("m", "semibold");
|
|
1882
1882
|
const fontBodySemiboldS = fontBody("s", "semibold");
|
|
@@ -10515,7 +10515,7 @@ const LegendItem = styled$2("div") `
|
|
|
10515
10515
|
align-items: center;
|
|
10516
10516
|
cursor: ${disabled ? "not-allowed" : "pointer"} !important;
|
|
10517
10517
|
transition: background-color 0.2s ease-in-out;
|
|
10518
|
-
padding:
|
|
10518
|
+
padding: ${spaces?.xxxs}px ${spaces?.xxs}px;
|
|
10519
10519
|
border-radius: ${corners?.s}px;
|
|
10520
10520
|
background-color: ${isSelected ? semanticColors?.base?.backgroundTertiary : "transparent"};
|
|
10521
10521
|
pointer-events: ${disabled ? "none" : "auto"};
|
|
@@ -10532,8 +10532,8 @@ const LegendIcon = styled$2("div") `
|
|
|
10532
10532
|
const spaces = getSpaces(props);
|
|
10533
10533
|
const corners = getCorners(props);
|
|
10534
10534
|
return `
|
|
10535
|
-
width:
|
|
10536
|
-
height:
|
|
10535
|
+
width: ${spaces?.m}px;
|
|
10536
|
+
height: ${spaces?.m}px;
|
|
10537
10537
|
border-radius: ${corners?.s}px;
|
|
10538
10538
|
background-color: ${color};
|
|
10539
10539
|
flex-shrink: 0;
|
|
@@ -10544,7 +10544,7 @@ const LegendIcon = styled$2("div") `
|
|
|
10544
10544
|
}}
|
|
10545
10545
|
`;
|
|
10546
10546
|
const LegendLabel = styled$2("span") `
|
|
10547
|
-
${
|
|
10547
|
+
${fontBodyMediumXxxs}
|
|
10548
10548
|
${(props) => {
|
|
10549
10549
|
const semanticColors = getSemanticColors(props);
|
|
10550
10550
|
return `
|
|
@@ -10553,13 +10553,13 @@ const LegendLabel = styled$2("span") `
|
|
|
10553
10553
|
}}
|
|
10554
10554
|
`;
|
|
10555
10555
|
const LegendValue = styled$2("span") `
|
|
10556
|
-
${
|
|
10556
|
+
${fontBodyMediumXxxs}
|
|
10557
10557
|
${(props) => {
|
|
10558
10558
|
const semanticColors = getSemanticColors(props);
|
|
10559
10559
|
const spaces = getSpaces(props);
|
|
10560
10560
|
return `
|
|
10561
10561
|
color: ${semanticColors?.base?.textSecondary};
|
|
10562
|
-
margin-left: ${spaces?.
|
|
10562
|
+
margin-left: ${spaces?.xxs}px;
|
|
10563
10563
|
`;
|
|
10564
10564
|
}}
|
|
10565
10565
|
`;
|
|
@@ -24751,7 +24751,7 @@ Object.assign(chroma, {
|
|
|
24751
24751
|
const generateDiscreteColors = (count, options = {}) => {
|
|
24752
24752
|
if (count === 0)
|
|
24753
24753
|
return [];
|
|
24754
|
-
const { isDarkMode = false, start =
|
|
24754
|
+
const { isDarkMode = false, start = 250, rotations = 0.85, gamma = 0.7, lightness = [0.4, 0.7], correctLightness = true, } = options;
|
|
24755
24755
|
let scale = chroma
|
|
24756
24756
|
.cubehelix()
|
|
24757
24757
|
.start(start)
|
|
@@ -24787,33 +24787,22 @@ var StyledBadge = styled$2("div")(templateObject_4 || (templateObject_4 = __make
|
|
|
24787
24787
|
return "\n padding: ".concat(spaces === null || spaces === void 0 ? void 0 : spaces.xxxs, "px ").concat(spaces === null || spaces === void 0 ? void 0 : spaces.xxs, "px;\n border-radius: ").concat(corners === null || corners === void 0 ? void 0 : corners.m, "px;\n background-color: ").concat((_a = semanticColors === null || semanticColors === void 0 ? void 0 : semanticColors.base) === null || _a === void 0 ? void 0 : _a.backgroundTertiary, ";\n color: ").concat((_b = semanticColors === null || semanticColors === void 0 ? void 0 : semanticColors.base) === null || _b === void 0 ? void 0 : _b.textSecondary, ";\n ");
|
|
24788
24788
|
});
|
|
24789
24789
|
var BarContainer = styled$2("div")(templateObject_5 || (templateObject_5 = __makeTemplateObject(["\n ", "\n"], ["\n ", "\n"])), function (props) {
|
|
24790
|
-
var
|
|
24790
|
+
var _a;
|
|
24791
|
+
var width = props.width, barHeight = props.barHeight, isEmpty = props.isEmpty;
|
|
24791
24792
|
var corners = getCorners(props);
|
|
24793
|
+
var semanticColors = getSemanticColors(props);
|
|
24792
24794
|
var finalWidth = typeof width === "number" ? "".concat(width, "px") : width;
|
|
24793
|
-
return "\n display: flex;\n border-radius: ".concat(corners === null || corners === void 0 ? void 0 : corners.s, "px;\n width: ").concat(finalWidth, ";\n height: ").concat(barHeight, "px;\n ");
|
|
24795
|
+
return "\n display: flex;\n border-radius: ".concat(corners === null || corners === void 0 ? void 0 : corners.s, "px;\n width: ").concat(finalWidth, ";\n height: ").concat(barHeight, "px;\n background-color: ").concat(isEmpty ? (_a = semanticColors === null || semanticColors === void 0 ? void 0 : semanticColors.base) === null || _a === void 0 ? void 0 : _a.backgroundTertiary : "transparent", ";\n overflow: hidden;\n ");
|
|
24794
24796
|
});
|
|
24795
24797
|
var BarSegment = styled$2("div")(templateObject_6 || (templateObject_6 = __makeTemplateObject(["\n ", "\n"], ["\n ", "\n"])), function (props) {
|
|
24796
|
-
var
|
|
24798
|
+
var color = props.color, height = props.height, percentage = props.percentage, opacity = props.opacity, disabled = props.disabled, isLast = props.isLast;
|
|
24797
24799
|
var spaces = getSpaces(props);
|
|
24798
24800
|
var gap = (spaces === null || spaces === void 0 ? void 0 : spaces.xxxs) || 0;
|
|
24799
|
-
|
|
24800
|
-
var corners = getCorners(props);
|
|
24801
|
-
var borderRadius = corners === null || corners === void 0 ? void 0 : corners.s;
|
|
24802
|
-
if (isFirst && isLast) {
|
|
24803
|
-
return "border-radius: ".concat(borderRadius, "px;");
|
|
24804
|
-
}
|
|
24805
|
-
if (isFirst) {
|
|
24806
|
-
return "\n border-top-left-radius: ".concat(borderRadius, "px; \n border-bottom-left-radius: ").concat(borderRadius, "px;\n ");
|
|
24807
|
-
}
|
|
24808
|
-
if (isLast) {
|
|
24809
|
-
return "\n border-top-right-radius: ".concat(borderRadius, "px; \n border-bottom-right-radius: ").concat(borderRadius, "px;\n ");
|
|
24810
|
-
}
|
|
24811
|
-
return "";
|
|
24812
|
-
};
|
|
24813
|
-
// Add gap as margin-right, except for last item
|
|
24801
|
+
// Add gap as margin-right for spacing between segments
|
|
24814
24802
|
// When percentage is 0, margin also becomes 0 (animates away with the segment)
|
|
24815
|
-
|
|
24816
|
-
|
|
24803
|
+
// Last visible segment also gets no margin
|
|
24804
|
+
var marginRight = percentage > 0 && !isLast ? "".concat(gap, "px") : 0;
|
|
24805
|
+
return "\n background-color: ".concat(color, ";\n height: ").concat(height, "px;\n flex-grow: ").concat(percentage, ";\n flex-basis: 0;\n flex-shrink: 1;\n margin-right: ").concat(marginRight, ";\n opacity: ").concat(opacity, ";\n transition: opacity 0.2s ease-in-out, flex-grow 0.25s ease-in-out, margin-right 0.25s ease-out;\n cursor: ").concat(disabled ? "default" : "pointer", ";\n pointer-events: ").concat(disabled ? "none" : "auto", ";\n ");
|
|
24817
24806
|
});
|
|
24818
24807
|
var StyledStackedBarChartWrapper = styled$2("div")(templateObject_7 || (templateObject_7 = __makeTemplateObject(["\n ", "\n"], ["\n ", "\n"])), function (props) {
|
|
24819
24808
|
var spaces = getSpaces(props);
|
|
@@ -24823,56 +24812,126 @@ var templateObject_1, templateObject_2, templateObject_3, templateObject_4, temp
|
|
|
24823
24812
|
|
|
24824
24813
|
// Helper: Calculate badge display text based on selection state
|
|
24825
24814
|
var calculateBadgeText = function (totalItems, selectedCount) {
|
|
24826
|
-
if (selectedCount === 0)
|
|
24815
|
+
if (selectedCount === 0 || selectedCount === totalItems)
|
|
24827
24816
|
return "".concat(totalItems);
|
|
24828
|
-
if (selectedCount === totalItems)
|
|
24829
|
-
return "All";
|
|
24830
24817
|
return "".concat(selectedCount, " of ").concat(totalItems);
|
|
24831
24818
|
};
|
|
24832
24819
|
// Helper: Calculate legend value display
|
|
24833
|
-
var calculateLegendValue = function (item,
|
|
24820
|
+
var calculateLegendValue = function (item, showLegendValues, legendValueFormat, globalUnit) {
|
|
24834
24821
|
if (!showLegendValues)
|
|
24835
24822
|
return undefined;
|
|
24836
|
-
if (
|
|
24823
|
+
if (legendValueFormat === "percentage") {
|
|
24837
24824
|
return "".concat(Math.round(item.percentage), "%");
|
|
24838
24825
|
}
|
|
24839
|
-
//
|
|
24826
|
+
// Count format: show value with optional unit
|
|
24840
24827
|
var effectiveUnit = item.unit || globalUnit;
|
|
24841
24828
|
return effectiveUnit ? "".concat(item.value, " ").concat(effectiveUnit) : "".concat(item.value);
|
|
24842
24829
|
};
|
|
24843
24830
|
// Helper: Get segment opacity based on hover and selection state
|
|
24844
|
-
var getSegmentOpacity = function (index, hoveredIndex,
|
|
24845
|
-
var hasSelection =
|
|
24831
|
+
var getSegmentOpacity = function (index, hoveredIndex, selectedIndicesSet, selectionBehavior) {
|
|
24832
|
+
var hasSelection = selectedIndicesSet.size > 0;
|
|
24833
|
+
// Hide mode doesn't use opacity - segments animate to 0% width instead
|
|
24834
|
+
if (selectionBehavior === "hide") {
|
|
24835
|
+
return 1;
|
|
24836
|
+
}
|
|
24837
|
+
// Dim mode
|
|
24846
24838
|
if (hoveredIndex !== null) {
|
|
24847
|
-
return hoveredIndex === index ||
|
|
24839
|
+
return hoveredIndex === index || selectedIndicesSet.has(index) ? 1 : 0.2;
|
|
24848
24840
|
}
|
|
24849
24841
|
if (hasSelection) {
|
|
24850
|
-
return
|
|
24842
|
+
return selectedIndicesSet.has(index) ? 1 : 0.2;
|
|
24851
24843
|
}
|
|
24852
24844
|
return 1;
|
|
24853
24845
|
};
|
|
24846
|
+
// Helper: Apply cumulative mode hide styling
|
|
24847
|
+
var applyCumulativeHideStyling = function (items, selectedIndicesSet, selectedTotal, hasRemaining, effectiveMaxAmount) {
|
|
24848
|
+
var newRemainingValue = hasRemaining
|
|
24849
|
+
? effectiveMaxAmount - selectedTotal
|
|
24850
|
+
: 0;
|
|
24851
|
+
var newRemainingPercentage = hasRemaining
|
|
24852
|
+
? (newRemainingValue / effectiveMaxAmount) * 100
|
|
24853
|
+
: 0;
|
|
24854
|
+
var styledItems = items.map(function (item) {
|
|
24855
|
+
var isSelected = selectedIndicesSet.has(item.originalIndex);
|
|
24856
|
+
return __assign$1(__assign$1({}, item), { percentage: isSelected ? item.percentage : 0 });
|
|
24857
|
+
});
|
|
24858
|
+
return {
|
|
24859
|
+
styledItems: styledItems,
|
|
24860
|
+
updatedRemainingPercentage: newRemainingPercentage,
|
|
24861
|
+
updatedRemainingValue: newRemainingValue,
|
|
24862
|
+
};
|
|
24863
|
+
};
|
|
24864
|
+
// Helper: Apply proportional mode hide styling
|
|
24865
|
+
var applyProportionalHideStyling = function (items, selectedIndicesSet, selectedTotal) {
|
|
24866
|
+
if (selectedTotal === 0) {
|
|
24867
|
+
return {
|
|
24868
|
+
styledItems: items.map(function (item) { return (__assign$1(__assign$1({}, item), { percentage: 0 })); }),
|
|
24869
|
+
updatedRemainingPercentage: 0,
|
|
24870
|
+
updatedRemainingValue: 0,
|
|
24871
|
+
};
|
|
24872
|
+
}
|
|
24873
|
+
var styledItems = items.map(function (item) {
|
|
24874
|
+
var isSelected = selectedIndicesSet.has(item.originalIndex);
|
|
24875
|
+
var newPercentage = isSelected ? (item.value / selectedTotal) * 100 : 0;
|
|
24876
|
+
return __assign$1(__assign$1({}, item), { percentage: newPercentage });
|
|
24877
|
+
});
|
|
24878
|
+
return {
|
|
24879
|
+
styledItems: styledItems,
|
|
24880
|
+
updatedRemainingPercentage: 0,
|
|
24881
|
+
updatedRemainingValue: 0,
|
|
24882
|
+
};
|
|
24883
|
+
};
|
|
24884
|
+
// Helper: Apply selection styling and recalculate percentages for hide mode
|
|
24885
|
+
var applySelectionStyling = function (items, selectedIndicesSet, selectionBehavior, mode, hasRemaining, effectiveMaxAmount, baseRemainingPercentage, baseRemainingValue) {
|
|
24886
|
+
var hasSelection = selectedIndicesSet.size > 0;
|
|
24887
|
+
// If no selection or dim mode, return items as-is with base remaining values
|
|
24888
|
+
if (selectionBehavior !== "hide" || !hasSelection) {
|
|
24889
|
+
return {
|
|
24890
|
+
styledItems: items,
|
|
24891
|
+
updatedRemainingPercentage: baseRemainingPercentage,
|
|
24892
|
+
updatedRemainingValue: baseRemainingValue,
|
|
24893
|
+
};
|
|
24894
|
+
}
|
|
24895
|
+
// Calculate total of selected items
|
|
24896
|
+
var selectedTotal = items
|
|
24897
|
+
.filter(function (item) { return selectedIndicesSet.has(item.originalIndex); })
|
|
24898
|
+
.reduce(function (sum, item) { return sum + item.value; }, 0);
|
|
24899
|
+
// Apply mode-specific styling
|
|
24900
|
+
return mode === "cumulative"
|
|
24901
|
+
? applyCumulativeHideStyling(items, selectedIndicesSet, selectedTotal, hasRemaining, effectiveMaxAmount)
|
|
24902
|
+
: applyProportionalHideStyling(items, selectedIndicesSet, selectedTotal);
|
|
24903
|
+
};
|
|
24854
24904
|
// Helper: Build legend items from data with optional remaining segment
|
|
24855
24905
|
var buildLegendItems = function (dataWithPercentages, options) {
|
|
24856
|
-
var _a, _b, _c
|
|
24857
|
-
var
|
|
24906
|
+
var _a, _b, _c;
|
|
24907
|
+
var showLegendValues = options.showLegendValues, legendValueFormat = options.legendValueFormat, unit = options.unit, hasRemaining = options.hasRemaining, showLegend = options.showLegend, remainingValue = options.remainingValue, remainingPercentage = options.remainingPercentage, remainingLabel = options.remainingLabel, remainingUnit = options.remainingUnit, theme = options.theme;
|
|
24858
24908
|
var legendItems = dataWithPercentages.map(function (item) { return ({
|
|
24859
24909
|
name: item.name,
|
|
24860
|
-
value: calculateLegendValue(item,
|
|
24910
|
+
value: calculateLegendValue(item, showLegendValues, legendValueFormat, unit),
|
|
24861
24911
|
color: item.color,
|
|
24862
24912
|
disabled: item.disabled,
|
|
24863
24913
|
}); });
|
|
24864
24914
|
// Add remaining item to legend if applicable
|
|
24865
24915
|
if (hasRemaining && showLegend) {
|
|
24866
|
-
var
|
|
24867
|
-
|
|
24868
|
-
|
|
24916
|
+
var remainingValueDisplay = void 0;
|
|
24917
|
+
if (!showLegendValues) {
|
|
24918
|
+
remainingValueDisplay = undefined;
|
|
24919
|
+
}
|
|
24920
|
+
else if (legendValueFormat === "percentage") {
|
|
24921
|
+
remainingValueDisplay = "".concat(Math.round(remainingPercentage), "%");
|
|
24922
|
+
}
|
|
24923
|
+
else {
|
|
24924
|
+
// Count format
|
|
24925
|
+
// Use remainingUnit or global unit (never a custom unit from data items)
|
|
24926
|
+
var effectiveRemainingUnit = remainingUnit || unit || "";
|
|
24927
|
+
remainingValueDisplay = effectiveRemainingUnit
|
|
24869
24928
|
? "".concat(remainingValue, " ").concat(effectiveRemainingUnit)
|
|
24870
|
-
: "".concat(remainingValue)
|
|
24871
|
-
|
|
24929
|
+
: "".concat(remainingValue);
|
|
24930
|
+
}
|
|
24872
24931
|
legendItems.push({
|
|
24873
24932
|
name: remainingLabel,
|
|
24874
24933
|
value: remainingValueDisplay,
|
|
24875
|
-
color: (
|
|
24934
|
+
color: (_c = (_b = (_a = theme === null || theme === void 0 ? void 0 : theme.palette) === null || _a === void 0 ? void 0 : _a.sds) === null || _b === void 0 ? void 0 : _b.base) === null || _c === void 0 ? void 0 : _c.backgroundTertiary,
|
|
24876
24935
|
disabled: true,
|
|
24877
24936
|
});
|
|
24878
24937
|
}
|
|
@@ -24880,8 +24939,10 @@ var buildLegendItems = function (dataWithPercentages, options) {
|
|
|
24880
24939
|
};
|
|
24881
24940
|
// Helper: Render a bar segment with optional tooltip
|
|
24882
24941
|
var renderBarSegment = function (item, index, options) {
|
|
24883
|
-
var
|
|
24884
|
-
|
|
24942
|
+
var barHeight = options.barHeight, hoveredIndex = options.hoveredIndex, selectedIndicesSet = options.selectedIndicesSet, selectionBehavior = options.selectionBehavior, isLast = options.isLast, onMouseEnter = options.onMouseEnter, onMouseLeave = options.onMouseLeave, onClick = options.onClick;
|
|
24943
|
+
// Mark hidden segments with data-hide attribute when in hide mode
|
|
24944
|
+
var isHidden = selectionBehavior === "hide" && item.percentage === 0;
|
|
24945
|
+
var barSegment = (jsx(BarSegment, { color: item.color, percentage: item.percentage, height: barHeight, opacity: getSegmentOpacity(item.originalIndex, hoveredIndex, selectedIndicesSet, selectionBehavior), isLast: isLast, "data-hide": isHidden, onMouseEnter: onMouseEnter, onMouseLeave: onMouseLeave, onClick: onClick }));
|
|
24885
24946
|
return item.tooltip !== undefined ? (jsx(Tooltip, { title: null, componentSlot: jsx(TooltipTableContent, __assign$1({}, item.tooltip)), placement: "top", hasInvertedStyle: false, open: hoveredIndex === item.originalIndex, disableInteractive: true, PopperProps: {
|
|
24886
24947
|
disablePortal: false,
|
|
24887
24948
|
modifiers: [
|
|
@@ -24896,18 +24957,20 @@ var renderBarSegment = function (item, index, options) {
|
|
|
24896
24957
|
};
|
|
24897
24958
|
var StackedBarChart = function (props) {
|
|
24898
24959
|
var _a, _b, _c;
|
|
24899
|
-
var title = props.title, badge = props.badge, _d = props.hideBadge, hideBadge = _d === void 0 ? false : _d, data = props.data, _e = props.width, width = _e === void 0 ? "100%" : _e, _f = props.barHeight,
|
|
24960
|
+
var title = props.title, badge = props.badge, _d = props.hideBadge, hideBadge = _d === void 0 ? false : _d, data = props.data, _e = props.width, width = _e === void 0 ? "100%" : _e, _f = props.barHeight, barHeightProp = _f === void 0 ? 16 : _f, _g = props.showLegend, showLegend = _g === void 0 ? true : _g, _h = props.showLegendValues, showLegendValues = _h === void 0 ? true : _h, _j = props.legendValueFormat, legendValueFormat = _j === void 0 ? "percentage" : _j, _k = props.selectedIndices, selectedIndices = _k === void 0 ? [] : _k, onSelectionChange = props.onSelectionChange, _l = props.selectionBehavior, selectionBehavior = _l === void 0 ? "dim" : _l, _m = props.mode, mode = _m === void 0 ? "proportional" : _m, maxAmount = props.maxAmount, _o = props.remainingLabel, remainingLabel = _o === void 0 ? "Remaining" : _o, remainingUnit = props.remainingUnit, unit = props.unit, colorGeneratorOptions = props.colorGeneratorOptions, rest = __rest(props, ["title", "badge", "hideBadge", "data", "width", "barHeight", "showLegend", "showLegendValues", "legendValueFormat", "selectedIndices", "onSelectionChange", "selectionBehavior", "mode", "maxAmount", "remainingLabel", "remainingUnit", "unit", "colorGeneratorOptions"]);
|
|
24961
|
+
// Ensure barHeight is at least 1px
|
|
24962
|
+
var barHeight = Math.max(1, barHeightProp);
|
|
24900
24963
|
var theme = useTheme$4();
|
|
24901
|
-
var
|
|
24902
|
-
var
|
|
24903
|
-
var
|
|
24904
|
-
var
|
|
24964
|
+
var _p = useState(null), hoveredIndex = _p[0], setHoveredIndex = _p[1];
|
|
24965
|
+
var _q = useState([]), animatedItems = _q[0], setAnimatedItems = _q[1];
|
|
24966
|
+
var _r = useState(new Map()), autoColorMap = _r[0], setAutoColorMap = _r[1];
|
|
24967
|
+
var _s = useState(0), animatedRemainingPercentage = _s[0], setAnimatedRemainingPercentage = _s[1];
|
|
24905
24968
|
var previousProcessedRef = useRef([]);
|
|
24906
24969
|
var previousDataKeysRef = useRef(new Set());
|
|
24907
24970
|
var previousColorOptionsRef = useRef(null);
|
|
24908
24971
|
var previousRemainingPercentageRef = useRef(0);
|
|
24909
|
-
//
|
|
24910
|
-
var animateItemRemoval = function (previousItems, nextItems, currentRemainingPercentage, newRemainingPercentage) {
|
|
24972
|
+
// Animate items when removals occur
|
|
24973
|
+
var animateItemRemoval = useCallback(function (previousItems, nextItems, currentRemainingPercentage, newRemainingPercentage) {
|
|
24911
24974
|
if (typeof window === "undefined") {
|
|
24912
24975
|
setAnimatedItems(nextItems);
|
|
24913
24976
|
previousProcessedRef.current = nextItems;
|
|
@@ -24966,9 +25029,9 @@ var StackedBarChart = function (props) {
|
|
|
24966
25029
|
frameIds.forEach(function (id) { return window.cancelAnimationFrame(id); });
|
|
24967
25030
|
window.clearTimeout(timeoutId);
|
|
24968
25031
|
};
|
|
24969
|
-
};
|
|
25032
|
+
}, []);
|
|
24970
25033
|
// Detect dark mode from theme
|
|
24971
|
-
var isDarkMode = getMode({ theme: theme }) === "dark";
|
|
25034
|
+
var isDarkMode = useMemo(function () { return getMode({ theme: theme }) === "dark"; }, [theme]);
|
|
24972
25035
|
// Helper to generate color map for auto items
|
|
24973
25036
|
var generateColorMap = useCallback(function (items) {
|
|
24974
25037
|
var palette = generateDiscreteColors(items.length, __assign$1(__assign$1({}, (colorGeneratorOptions || {})), { isDarkMode: isDarkMode }));
|
|
@@ -24988,8 +25051,7 @@ var StackedBarChart = function (props) {
|
|
|
24988
25051
|
// Check if color generation options changed
|
|
24989
25052
|
var colorOptionsChanged = !previousColorOptions ||
|
|
24990
25053
|
previousColorOptions.isDarkMode !== isDarkMode ||
|
|
24991
|
-
|
|
24992
|
-
JSON.stringify(colorGeneratorOptions);
|
|
25054
|
+
previousColorOptions.options !== colorGeneratorOptions;
|
|
24993
25055
|
// Update refs
|
|
24994
25056
|
previousDataKeysRef.current = currentDataKeys;
|
|
24995
25057
|
previousColorOptionsRef.current = {
|
|
@@ -25022,36 +25084,38 @@ var StackedBarChart = function (props) {
|
|
|
25022
25084
|
setAutoColorMap(updatedMap);
|
|
25023
25085
|
}
|
|
25024
25086
|
}
|
|
25025
|
-
|
|
25026
|
-
|
|
25027
|
-
|
|
25028
|
-
|
|
25029
|
-
|
|
25030
|
-
|
|
25031
|
-
|
|
25032
|
-
|
|
25033
|
-
|
|
25034
|
-
|
|
25035
|
-
|
|
25036
|
-
|
|
25037
|
-
|
|
25038
|
-
|
|
25039
|
-
|
|
25040
|
-
|
|
25041
|
-
|
|
25042
|
-
|
|
25043
|
-
|
|
25044
|
-
|
|
25045
|
-
: 0;
|
|
25087
|
+
// eslint-disable-next-line react-hooks/exhaustive-deps
|
|
25088
|
+
}, [data, colorGeneratorOptions, isDarkMode, theme, generateColorMap]);
|
|
25089
|
+
// Calculate display badge value
|
|
25090
|
+
var displayBadge = badge !== null && badge !== void 0 ? badge : calculateBadgeText(data.length, selectedIndices.length);
|
|
25091
|
+
// Calculate totals and remaining segments for cumulative mode
|
|
25092
|
+
var _t = useMemo(function () {
|
|
25093
|
+
var total = data.reduce(function (sum, item) { return sum + item.value; }, 0);
|
|
25094
|
+
var maxAmountValue = mode === "cumulative" && maxAmount ? maxAmount : total;
|
|
25095
|
+
var hasRemainingSegment = mode === "cumulative" && total < maxAmountValue;
|
|
25096
|
+
var remaining = hasRemainingSegment ? maxAmountValue - total : 0;
|
|
25097
|
+
var remainingPct = hasRemainingSegment
|
|
25098
|
+
? (remaining / maxAmountValue) * 100
|
|
25099
|
+
: 0;
|
|
25100
|
+
return {
|
|
25101
|
+
effectiveMaxAmount: maxAmountValue,
|
|
25102
|
+
hasRemaining: hasRemainingSegment,
|
|
25103
|
+
remainingValue: remaining,
|
|
25104
|
+
remainingPercentage: remainingPct,
|
|
25105
|
+
};
|
|
25106
|
+
}, [data, mode, maxAmount]), effectiveMaxAmount = _t.effectiveMaxAmount, hasRemaining = _t.hasRemaining, remainingValue = _t.remainingValue, remainingPercentage = _t.remainingPercentage;
|
|
25046
25107
|
// Calculate percentages and assign colors for each segment
|
|
25047
25108
|
// default to ornament secondary color if no color is provided
|
|
25048
|
-
|
|
25049
|
-
|
|
25050
|
-
|
|
25051
|
-
|
|
25052
|
-
|
|
25053
|
-
|
|
25054
|
-
|
|
25109
|
+
// Memoize to prevent unnecessary recalculations and re-renders
|
|
25110
|
+
var dataWithPercentages = useMemo(function () {
|
|
25111
|
+
return data.map(function (item, index) {
|
|
25112
|
+
var _a, _b, _c;
|
|
25113
|
+
var resolvedColor = item.color ||
|
|
25114
|
+
autoColorMap.get(item.name) ||
|
|
25115
|
+
((_c = (_b = (_a = theme === null || theme === void 0 ? void 0 : theme.palette) === null || _a === void 0 ? void 0 : _a.sds) === null || _b === void 0 ? void 0 : _b.base) === null || _c === void 0 ? void 0 : _c.ornamentSecondary);
|
|
25116
|
+
return __assign$1(__assign$1({}, item), { color: resolvedColor, percentage: effectiveMaxAmount > 0 ? (item.value / effectiveMaxAmount) * 100 : 0, key: item.name, originalIndex: index });
|
|
25117
|
+
});
|
|
25118
|
+
}, [data, effectiveMaxAmount, autoColorMap, theme]);
|
|
25055
25119
|
// Handle data changes and animate exits
|
|
25056
25120
|
useEffect(function () {
|
|
25057
25121
|
var previousProcessed = previousProcessedRef.current;
|
|
@@ -25071,53 +25135,104 @@ var StackedBarChart = function (props) {
|
|
|
25071
25135
|
previousProcessedRef.current = dataWithPercentages;
|
|
25072
25136
|
setAnimatedRemainingPercentage(remainingPercentage);
|
|
25073
25137
|
previousRemainingPercentageRef.current = remainingPercentage;
|
|
25074
|
-
|
|
25075
|
-
|
|
25076
|
-
|
|
25077
|
-
|
|
25078
|
-
|
|
25079
|
-
|
|
25080
|
-
|
|
25081
|
-
|
|
25082
|
-
|
|
25083
|
-
|
|
25084
|
-
|
|
25085
|
-
|
|
25086
|
-
|
|
25087
|
-
|
|
25088
|
-
|
|
25089
|
-
|
|
25090
|
-
|
|
25091
|
-
|
|
25092
|
-
|
|
25093
|
-
|
|
25094
|
-
var
|
|
25095
|
-
|
|
25096
|
-
|
|
25097
|
-
|
|
25098
|
-
|
|
25138
|
+
}, [dataWithPercentages, remainingPercentage, animateItemRemoval]);
|
|
25139
|
+
// Create a Set for O(1) lookups of selected indices
|
|
25140
|
+
var selectedIndicesSet = useMemo(function () { return new Set(selectedIndices); }, [selectedIndices]);
|
|
25141
|
+
// Apply selection styling for hide mode
|
|
25142
|
+
// This modifies percentages but keeps all items (including hidden ones at 0%)
|
|
25143
|
+
// so animations continue to work smoothly
|
|
25144
|
+
var _u = useMemo(function () {
|
|
25145
|
+
return applySelectionStyling(animatedItems, selectedIndicesSet, selectionBehavior, mode, hasRemaining, effectiveMaxAmount, animatedRemainingPercentage, remainingValue);
|
|
25146
|
+
}, [
|
|
25147
|
+
animatedItems,
|
|
25148
|
+
selectedIndicesSet,
|
|
25149
|
+
selectionBehavior,
|
|
25150
|
+
mode,
|
|
25151
|
+
hasRemaining,
|
|
25152
|
+
effectiveMaxAmount,
|
|
25153
|
+
animatedRemainingPercentage,
|
|
25154
|
+
remainingValue,
|
|
25155
|
+
]), styledItems = _u.styledItems, updatedRemainingPercentage = _u.updatedRemainingPercentage, updatedRemainingValue = _u.updatedRemainingValue;
|
|
25156
|
+
// Calculate display values for hide mode
|
|
25157
|
+
var isHideMode = selectionBehavior === "hide" && selectedIndices.length > 0;
|
|
25158
|
+
var displayRemainingPercentage = isHideMode
|
|
25159
|
+
? updatedRemainingPercentage
|
|
25160
|
+
: animatedRemainingPercentage;
|
|
25161
|
+
var displayRemainingValue = isHideMode
|
|
25162
|
+
? updatedRemainingValue
|
|
25163
|
+
: remainingValue;
|
|
25164
|
+
// Convert data to legend items format (always use full data, not filtered)
|
|
25165
|
+
// Use updated remaining values when in hide mode with selections
|
|
25166
|
+
var legendItems = useMemo(function () {
|
|
25167
|
+
return buildLegendItems(dataWithPercentages, {
|
|
25168
|
+
showLegendValues: showLegendValues,
|
|
25169
|
+
legendValueFormat: legendValueFormat,
|
|
25170
|
+
unit: unit,
|
|
25171
|
+
hasRemaining: hasRemaining,
|
|
25172
|
+
showLegend: showLegend,
|
|
25173
|
+
remainingValue: displayRemainingValue,
|
|
25174
|
+
remainingPercentage: displayRemainingPercentage,
|
|
25175
|
+
remainingLabel: remainingLabel,
|
|
25176
|
+
remainingUnit: remainingUnit,
|
|
25177
|
+
theme: theme,
|
|
25178
|
+
});
|
|
25179
|
+
}, [
|
|
25180
|
+
dataWithPercentages,
|
|
25181
|
+
showLegendValues,
|
|
25182
|
+
legendValueFormat,
|
|
25183
|
+
unit,
|
|
25184
|
+
hasRemaining,
|
|
25185
|
+
showLegend,
|
|
25186
|
+
displayRemainingValue,
|
|
25187
|
+
displayRemainingPercentage,
|
|
25188
|
+
remainingLabel,
|
|
25189
|
+
remainingUnit,
|
|
25190
|
+
theme,
|
|
25191
|
+
]);
|
|
25192
|
+
// Handle legend item hover and leave
|
|
25193
|
+
var handleLegendItemHover = useCallback(function (_item, index) { return setHoveredIndex(index); }, []);
|
|
25194
|
+
var handleLegendItemLeave = useCallback(function () { return setHoveredIndex(null); }, []);
|
|
25195
|
+
// Handle selection change - reusable logic for both segment and legend
|
|
25196
|
+
var handleSelectionChange = useCallback(function (newSelectedIndices) {
|
|
25099
25197
|
if (!onSelectionChange)
|
|
25100
25198
|
return;
|
|
25101
|
-
var isSelected = selectedIndices.includes(index);
|
|
25102
|
-
var newSelectedIndices;
|
|
25103
|
-
if (isSelected) {
|
|
25104
|
-
newSelectedIndices = selectedIndices.filter(function (i) { return i !== index; });
|
|
25105
|
-
}
|
|
25106
|
-
else {
|
|
25107
|
-
newSelectedIndices = __spreadArray(__spreadArray([], selectedIndices, true), [index], false);
|
|
25108
|
-
}
|
|
25109
25199
|
var selectedData = data.filter(function (item, itemIndex) {
|
|
25110
25200
|
return newSelectedIndices.includes(itemIndex);
|
|
25111
25201
|
});
|
|
25112
25202
|
onSelectionChange(newSelectedIndices, selectedData);
|
|
25113
|
-
};
|
|
25114
|
-
|
|
25203
|
+
}, [onSelectionChange, data]);
|
|
25204
|
+
// Handle segment click - toggle selection
|
|
25205
|
+
var handleSegmentClick = useCallback(function (index) {
|
|
25206
|
+
if (!onSelectionChange)
|
|
25207
|
+
return;
|
|
25208
|
+
var isSelected = selectedIndicesSet.has(index);
|
|
25209
|
+
var newSelectedIndices = isSelected
|
|
25210
|
+
? selectedIndices.filter(function (i) { return i !== index; })
|
|
25211
|
+
: __spreadArray(__spreadArray([], selectedIndices, true), [index], false);
|
|
25212
|
+
handleSelectionChange(newSelectedIndices);
|
|
25213
|
+
}, [
|
|
25214
|
+
onSelectionChange,
|
|
25215
|
+
selectedIndices,
|
|
25216
|
+
selectedIndicesSet,
|
|
25217
|
+
handleSelectionChange,
|
|
25218
|
+
]);
|
|
25219
|
+
// Calculate the last visible segment (percentage > 0)
|
|
25220
|
+
var lastVisibleIndex = useMemo(function () {
|
|
25221
|
+
for (var i = styledItems.length - 1; i >= 0; i--) {
|
|
25222
|
+
if (styledItems[i].percentage > 0) {
|
|
25223
|
+
return i;
|
|
25224
|
+
}
|
|
25225
|
+
}
|
|
25226
|
+
return -1;
|
|
25227
|
+
}, [styledItems]);
|
|
25228
|
+
var chartContent = (jsxs(StyledStackedBarChartWrapper, { children: [jsxs(BarContainer, { width: width, barHeight: barHeight, isEmpty: styledItems.length === 0 && !hasRemaining, children: [styledItems.map(function (item, index) {
|
|
25229
|
+
var isLastVisible = index === lastVisibleIndex && !hasRemaining;
|
|
25115
25230
|
return renderBarSegment(item, index, {
|
|
25116
|
-
isFirst: index === 0,
|
|
25117
|
-
isLast: index === animatedItems.length - 1 && !hasRemaining,
|
|
25118
25231
|
barHeight: barHeight,
|
|
25119
25232
|
hoveredIndex: hoveredIndex,
|
|
25120
|
-
|
|
25233
|
+
selectedIndicesSet: selectedIndicesSet,
|
|
25234
|
+
selectionBehavior: selectionBehavior,
|
|
25235
|
+
isLast: isLastVisible,
|
|
25121
25236
|
onMouseEnter: function () {
|
|
25122
25237
|
return !item.isExiting && setHoveredIndex(item.originalIndex);
|
|
25123
25238
|
},
|
|
@@ -25126,14 +25241,7 @@ var StackedBarChart = function (props) {
|
|
|
25126
25241
|
return !item.isExiting && handleSegmentClick(item.originalIndex);
|
|
25127
25242
|
},
|
|
25128
25243
|
});
|
|
25129
|
-
}), hasRemaining && (jsx(BarSegment, { color: (_c = (_b = (_a = theme === null || theme === void 0 ? void 0 : theme.palette) === null || _a === void 0 ? void 0 : _a.sds) === null || _b === void 0 ? void 0 : _b.base) === null || _c === void 0 ? void 0 : _c.backgroundTertiary, percentage:
|
|
25130
|
-
? function (newSelectedIndices) {
|
|
25131
|
-
var selectedData = data.filter(function (item, itemIndex) {
|
|
25132
|
-
return newSelectedIndices.includes(itemIndex);
|
|
25133
|
-
});
|
|
25134
|
-
onSelectionChange(newSelectedIndices, selectedData);
|
|
25135
|
-
}
|
|
25136
|
-
: undefined, hoveredIndex: hoveredIndex }))] }));
|
|
25244
|
+
}), hasRemaining && (jsx(BarSegment, { color: (_c = (_b = (_a = theme === null || theme === void 0 ? void 0 : theme.palette) === null || _a === void 0 ? void 0 : _a.sds) === null || _b === void 0 ? void 0 : _b.base) === null || _c === void 0 ? void 0 : _c.backgroundTertiary, percentage: displayRemainingPercentage, height: barHeight, isLast: true, opacity: 1, disabled: true }, "remaining"))] }), showLegend && (jsx(Legend, { items: legendItems, showValues: showLegendValues, onItemMouseEnter: handleLegendItemHover, onItemMouseLeave: handleLegendItemLeave, selectedIndices: selectedIndices, onSelectionChange: onSelectionChange ? handleSelectionChange : undefined, hoveredIndex: hoveredIndex }))] }));
|
|
25137
25245
|
// If no title, render chart and optional legend without wrapper
|
|
25138
25246
|
if (!title) {
|
|
25139
25247
|
return (jsx(ChartWrapper, __assign$1({ width: width }, rest, { children: chartContent })));
|