@hero-design/rn 8.100.2 → 8.101.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/.turbo/turbo-build.log +3 -3
- package/CHANGELOG.md +6 -0
- package/es/index.js +109 -25
- package/lib/index.js +109 -25
- package/package.json +1 -1
- package/src/components/Chart/ColumnChart/ColumnChartContent.tsx +19 -3
- package/src/components/Chart/ColumnChart/Segment.tsx +1 -1
- package/src/components/Chart/ColumnChart/StackedSegment.tsx +10 -6
- package/src/components/Chart/ColumnChart/__tests__/Segment.spec.tsx +1 -1
- package/src/components/Chart/ColumnChart/__tests__/__snapshots__/StackedSegment.spec.tsx.snap +6 -21
- package/src/components/Chart/ColumnChart/__tests__/__snapshots__/index.spec.tsx.snap +999 -6
- package/src/components/Chart/ColumnChart/__tests__/index.spec.tsx +107 -0
- package/src/components/Chart/ColumnChart/index.tsx +15 -0
- package/src/components/Chart/Line/Line.tsx +5 -2
- package/src/components/Chart/Line/__tests__/Line.spec.tsx +13 -6
- package/src/components/Chart/Line/__tests__/__snapshots__/Line.spec.tsx.snap +1 -1
- package/src/components/Chart/Line/__tests__/__snapshots__/index.spec.tsx.snap +1464 -4
- package/src/components/Chart/Line/__tests__/index.spec.tsx +95 -1
- package/src/components/Chart/Line/index.tsx +14 -2
- package/src/components/Chart/shared/__tests__/utils.spec.ts +16 -0
- package/src/components/Chart/shared/constants.ts +4 -0
- package/src/components/Chart/shared/hooks/useCustomColor.ts +84 -0
- package/src/components/Chart/shared/utils.ts +14 -0
- package/src/components/Chart/types.ts +32 -0
- package/stats/8.100.2/rn-stats.html +1 -3
- package/stats/8.101.0/rn-stats.html +4844 -0
- package/types/components/Chart/ColumnChart/ColumnChartContent.d.ts +5 -1
- package/types/components/Chart/ColumnChart/StackedSegment.d.ts +4 -0
- package/types/components/Chart/ColumnChart/index.d.ts +8 -2
- package/types/components/Chart/Line/Line.d.ts +3 -1
- package/types/components/Chart/Line/index.d.ts +8 -2
- package/types/components/Chart/index.d.ts +2 -2
- package/types/components/Chart/shared/constants.d.ts +2 -0
- package/types/components/Chart/shared/hooks/useCustomColor.d.ts +22 -0
- package/types/components/Chart/shared/utils.d.ts +11 -0
- package/types/components/Chart/types.d.ts +14 -1
package/.turbo/turbo-build.log
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
(node:
|
|
1
|
+
(node:3247) ExperimentalWarning: Importing JSON modules is an experimental feature and might change at any time
|
|
2
2
|
(Use `node --trace-warnings ...` to show where the warning was created)
|
|
3
3
|
[36m
|
|
4
4
|
[1msrc/index.ts[22m → [1mlib/index.js, es/index.js[22m...[39m
|
|
@@ -15,9 +15,9 @@ node_modules/d3-selection/src/selection/index.js -> node_modules/d3-selection/sr
|
|
|
15
15
|
[7m [0m [91m ~~~~~~~~~~~~~~~~~~~[0m
|
|
16
16
|
[39m
|
|
17
17
|
[1m[33m(!) [plugin node-resolve] preferring built-in module 'events' over local alternative at '/home/runner/work/hero-design/hero-design/node_modules/events/events.js', pass 'preferBuiltins: false' to disable this behavior or 'preferBuiltins: true' to disable this warning.or passing a function to 'preferBuiltins' to provide more fine-grained control over which built-in modules to prefer.[39m[22m
|
|
18
|
-
[32mcreated [1mlib/index.js, es/index.js[22m in [1m1m
|
|
18
|
+
[32mcreated [1mlib/index.js, es/index.js[22m in [1m1m 10.6s[22m[39m
|
|
19
19
|
[36m
|
|
20
20
|
[1m/home/runner/work/hero-design/hero-design/packages/rn/src/locales/en_AU.ts, /home/runner/work/hero-design/hero-design/packages/rn/src/locales/en_CA.ts, /home/runner/work/hero-design/hero-design/packages/rn/src/locales/index.ts, /home/runner/work/hero-design/hero-design/packages/rn/src/locales/types.ts[22m → [1m., .[22m...[39m
|
|
21
21
|
[1m[33m(!) Generated empty chunks[39m[22m
|
|
22
22
|
"locales/types" and "locales/types"
|
|
23
|
-
[32mcreated [1m., .[22m in [1m20.
|
|
23
|
+
[32mcreated [1m., .[22m in [1m20.1s[22m[39m
|
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,11 @@
|
|
|
1
1
|
# @hero-design/rn
|
|
2
2
|
|
|
3
|
+
## 8.101.0
|
|
4
|
+
|
|
5
|
+
### Minor Changes
|
|
6
|
+
|
|
7
|
+
- [#3943](https://github.com/Thinkei/hero-design/pull/3943) [`0eb5957f1c9ff674700266e0c3c460532c369b49`](https://github.com/Thinkei/hero-design/commit/0eb5957f1c9ff674700266e0c3c460532c369b49) Thanks [@vinhphan-eh](https://github.com/vinhphan-eh)! - [Chart] Support custom color config
|
|
8
|
+
|
|
3
9
|
## 8.100.2
|
|
4
10
|
|
|
5
11
|
### Patch Changes
|
package/es/index.js
CHANGED
|
@@ -1785,14 +1785,14 @@ var palette$8 = {
|
|
|
1785
1785
|
maasstrichtBlueLight35: maasstrichtBlue$1.lighten35,
|
|
1786
1786
|
maasstrichtBlueLight40: maasstrichtBlue$1.lighten40,
|
|
1787
1787
|
// Update 23 May 2025
|
|
1788
|
-
|
|
1789
|
-
|
|
1790
|
-
|
|
1791
|
-
|
|
1792
|
-
|
|
1793
|
-
|
|
1794
|
-
|
|
1795
|
-
|
|
1788
|
+
primaryLight: mauve$3.base,
|
|
1789
|
+
blueLight: blue$2.base,
|
|
1790
|
+
greenLight: grotesqueGreen.darken10,
|
|
1791
|
+
redLight: pastelRed.lighten25,
|
|
1792
|
+
orangeLight: blazingBonfire.lighten30,
|
|
1793
|
+
yellowLight: yellow$2.base,
|
|
1794
|
+
pinkLight: pink$2.lighten40,
|
|
1795
|
+
greyLight: cumberlandFog.darken15,
|
|
1796
1796
|
primaryMedium: violet$2.lighten20,
|
|
1797
1797
|
blueMedium: ultramarineBlue.base,
|
|
1798
1798
|
greenMedium: green$2.base,
|
|
@@ -18672,6 +18672,8 @@ var XAxis = function XAxis(_ref) {
|
|
|
18672
18672
|
|
|
18673
18673
|
var DASH_ARRAY = [4, 4];
|
|
18674
18674
|
var DEFAULT_LINE_STROKE_WIDTH = 2;
|
|
18675
|
+
var ERROR_COLOR_NUMBER_MISMATCH = 'styleConfig.series should have exact number of colors as the number of labels';
|
|
18676
|
+
var ERROR_COLOR_NOT_FOUND = 'Color {color} not found in the mobile visualization palette.';
|
|
18675
18677
|
|
|
18676
18678
|
var XAxisGrid = function XAxisGrid(_ref) {
|
|
18677
18679
|
var xAxisConfig = _ref.xAxisConfig,
|
|
@@ -18935,6 +18937,17 @@ var ChartFrame = function ChartFrame(_ref) {
|
|
|
18935
18937
|
}))));
|
|
18936
18938
|
};
|
|
18937
18939
|
|
|
18940
|
+
/**
|
|
18941
|
+
* Filter elements that have no color.
|
|
18942
|
+
* @param data - The data to filter.
|
|
18943
|
+
* @returns The filtered data.
|
|
18944
|
+
*/
|
|
18945
|
+
var filterElementHasNoColor = function filterElementHasNoColor(data) {
|
|
18946
|
+
return data.filter(function (element) {
|
|
18947
|
+
return element.color !== undefined;
|
|
18948
|
+
});
|
|
18949
|
+
};
|
|
18950
|
+
|
|
18938
18951
|
// Only use colors that are not maasstrichtBlue
|
|
18939
18952
|
var DEFAULT_COLORS = Object.entries(palette$8).filter(function (_ref) {
|
|
18940
18953
|
var _ref2 = _slicedToArray(_ref, 1),
|
|
@@ -18953,11 +18966,70 @@ var DEFAULT_COLORS = Object.entries(palette$8).filter(function (_ref) {
|
|
|
18953
18966
|
*/
|
|
18954
18967
|
function useColorScale(labels, customColors) {
|
|
18955
18968
|
return useMemo(function () {
|
|
18956
|
-
var palette = DEFAULT_COLORS;
|
|
18969
|
+
var palette = customColors && customColors.length > 0 ? customColors : DEFAULT_COLORS;
|
|
18957
18970
|
return ordinal().domain(labels).range(palette);
|
|
18958
18971
|
}, [labels, customColors]);
|
|
18959
18972
|
}
|
|
18960
18973
|
|
|
18974
|
+
/**
|
|
18975
|
+
* Hook to handle custom color assignments for chart series
|
|
18976
|
+
*
|
|
18977
|
+
* This hook manages:
|
|
18978
|
+
* 1. Validation of custom color configurations
|
|
18979
|
+
* 2. Color mapping between series and palette
|
|
18980
|
+
* 3. Fallback to default colors when custom colors aren't provided
|
|
18981
|
+
*
|
|
18982
|
+
* @throws {Error} When custom colors are invalid or don't match data series
|
|
18983
|
+
*/
|
|
18984
|
+
var useCustomColor = function useCustomColor(_ref) {
|
|
18985
|
+
var data = _ref.data,
|
|
18986
|
+
seriesConfig = _ref.seriesConfig;
|
|
18987
|
+
// Check if custom colors are provided and non-empty
|
|
18988
|
+
var hasCustomColors = Boolean(seriesConfig === null || seriesConfig === void 0 ? void 0 : seriesConfig.length);
|
|
18989
|
+
// Process and validate custom color segments
|
|
18990
|
+
var customSegments = useMemo(function () {
|
|
18991
|
+
if (!hasCustomColors) return undefined;
|
|
18992
|
+
// Filter out segments without colors
|
|
18993
|
+
var filtered = filterElementHasNoColor(seriesConfig || []);
|
|
18994
|
+
// Validate: number of custom colors must match number of data series
|
|
18995
|
+
if (filtered.length < data.length) {
|
|
18996
|
+
throw new Error(ERROR_COLOR_NUMBER_MISMATCH);
|
|
18997
|
+
}
|
|
18998
|
+
// Validate: all data series must have corresponding custom colors
|
|
18999
|
+
var dataLabels = new Set(data.map(function (d) {
|
|
19000
|
+
return d.label;
|
|
19001
|
+
}));
|
|
19002
|
+
if (!filtered.every(function (series) {
|
|
19003
|
+
return dataLabels.has(series.label);
|
|
19004
|
+
})) {
|
|
19005
|
+
throw new Error(ERROR_COLOR_NUMBER_MISMATCH);
|
|
19006
|
+
}
|
|
19007
|
+
return filtered;
|
|
19008
|
+
}, [seriesConfig, hasCustomColors, data]);
|
|
19009
|
+
// Map custom segments to actual color values from palette
|
|
19010
|
+
var customColors = useMemo(function () {
|
|
19011
|
+
if (!customSegments) return [];
|
|
19012
|
+
// Convert color keys to actual color values
|
|
19013
|
+
var colors = customSegments.map(function (series) {
|
|
19014
|
+
var color = palette$8[series.color];
|
|
19015
|
+
// Validate: color key must exist in palette
|
|
19016
|
+
if (color === undefined) {
|
|
19017
|
+
throw new Error(ERROR_COLOR_NOT_FOUND.replace('{color}', series.color));
|
|
19018
|
+
}
|
|
19019
|
+
return color;
|
|
19020
|
+
});
|
|
19021
|
+
return colors;
|
|
19022
|
+
}, [customSegments]);
|
|
19023
|
+
// Create color scale:
|
|
19024
|
+
// - If custom colors exist, use custom color mapping
|
|
19025
|
+
// - Otherwise, fall back to default color mapping
|
|
19026
|
+
return useColorScale(customSegments ? customSegments.map(function (series) {
|
|
19027
|
+
return series.label;
|
|
19028
|
+
}) : data.map(function (series) {
|
|
19029
|
+
return series.label;
|
|
19030
|
+
}), customColors);
|
|
19031
|
+
};
|
|
19032
|
+
|
|
18961
19033
|
/**
|
|
18962
19034
|
* Finds a "nice" number approximately equal to x.
|
|
18963
19035
|
* https://stackoverflow.com/questions/8506881/nice-label-algorithm-for-charts-with-minimum-ticks
|
|
@@ -19027,7 +19099,8 @@ var Line = function Line(_ref) {
|
|
|
19027
19099
|
minValue = _ref.minValue,
|
|
19028
19100
|
labels = _ref.labels,
|
|
19029
19101
|
coordinates = _ref.coordinates,
|
|
19030
|
-
color = _ref.color
|
|
19102
|
+
color = _ref.color,
|
|
19103
|
+
testID = _ref.testID;
|
|
19031
19104
|
var xStart = coordinates.xStart,
|
|
19032
19105
|
xEnd = coordinates.xEnd,
|
|
19033
19106
|
yStart = coordinates.yStart,
|
|
@@ -19059,8 +19132,8 @@ var Line = function Line(_ref) {
|
|
|
19059
19132
|
return lineGenerator(data);
|
|
19060
19133
|
}, [data, lineGenerator]);
|
|
19061
19134
|
return pathData ? /*#__PURE__*/React__default.createElement(Path$1, {
|
|
19062
|
-
testID:
|
|
19063
|
-
accessibilityLabel: "chart-line-maxValue:".concat(maxValue, ",minValue:").concat(minValue, ",labelsLength:").concat(labels.length),
|
|
19135
|
+
testID: testID,
|
|
19136
|
+
accessibilityLabel: "chart-line-maxValue:".concat(maxValue, ",minValue:").concat(minValue, ",labelsLength:").concat(labels.length, ",color:").concat(color),
|
|
19064
19137
|
d: pathData,
|
|
19065
19138
|
stroke: color || theme.colors.secondary,
|
|
19066
19139
|
strokeWidth: DEFAULT_LINE_STROKE_WIDTH,
|
|
@@ -19078,7 +19151,8 @@ var LineChart = function LineChart(_ref) {
|
|
|
19078
19151
|
style = _ref.style,
|
|
19079
19152
|
testID = _ref.testID,
|
|
19080
19153
|
headerConfig = _ref.headerConfig,
|
|
19081
|
-
emptyText = _ref.emptyText
|
|
19154
|
+
emptyText = _ref.emptyText,
|
|
19155
|
+
styleConfig = _ref.styleConfig;
|
|
19082
19156
|
var _useState = useState({
|
|
19083
19157
|
width: 0,
|
|
19084
19158
|
height: 0
|
|
@@ -19086,9 +19160,10 @@ var LineChart = function LineChart(_ref) {
|
|
|
19086
19160
|
_useState2 = _slicedToArray(_useState, 2),
|
|
19087
19161
|
chartSize = _useState2[0],
|
|
19088
19162
|
setChartSize = _useState2[1];
|
|
19089
|
-
var colorScale =
|
|
19090
|
-
|
|
19091
|
-
|
|
19163
|
+
var colorScale = useCustomColor({
|
|
19164
|
+
data: data,
|
|
19165
|
+
seriesConfig: styleConfig === null || styleConfig === void 0 ? void 0 : styleConfig.series
|
|
19166
|
+
});
|
|
19092
19167
|
var niceValues = useMemo(function () {
|
|
19093
19168
|
var maxDataValue = maxValueFromDataSet(data);
|
|
19094
19169
|
var minDataValue = minValueFromDataSet(data);
|
|
@@ -19129,6 +19204,7 @@ var LineChart = function LineChart(_ref) {
|
|
|
19129
19204
|
var _calculatedXAxisConfi;
|
|
19130
19205
|
return /*#__PURE__*/React__default.createElement(Line, {
|
|
19131
19206
|
color: colorScale(series.label),
|
|
19207
|
+
testID: "line-".concat(series.label),
|
|
19132
19208
|
key: series.label,
|
|
19133
19209
|
data: series.data,
|
|
19134
19210
|
coordinates: coordinates,
|
|
@@ -19195,7 +19271,7 @@ var Segment = function Segment(_ref) {
|
|
|
19195
19271
|
height: adjustedHeight,
|
|
19196
19272
|
rx: width / 2,
|
|
19197
19273
|
fill: color,
|
|
19198
|
-
accessibilityLabel: "Column segment: value ".concat(value, ", x-label ").concat(xLabel, ", series ").concat(seriesLabel),
|
|
19274
|
+
accessibilityLabel: "Column segment: value ".concat(value, ", x-label ").concat(xLabel, ", series ").concat(seriesLabel, ", color ").concat(color),
|
|
19199
19275
|
testID: testID,
|
|
19200
19276
|
onPress: onPress
|
|
19201
19277
|
});
|
|
@@ -19219,7 +19295,8 @@ var StackedSegment = function StackedSegment(_ref) {
|
|
|
19219
19295
|
coordinates = _ref.coordinates,
|
|
19220
19296
|
xCenter = _ref.xCenter,
|
|
19221
19297
|
xIndex = _ref.xIndex,
|
|
19222
|
-
onBarPress = _ref.onBarPress
|
|
19298
|
+
onBarPress = _ref.onBarPress,
|
|
19299
|
+
colorScale = _ref.colorScale;
|
|
19223
19300
|
var yStart = coordinates.yStart,
|
|
19224
19301
|
yEnd = coordinates.yEnd;
|
|
19225
19302
|
var stackedMaxY = (_yAxisConfig$maxValue = yAxisConfig.maxValue) !== null && _yAxisConfig$maxValue !== void 0 ? _yAxisConfig$maxValue : 0;
|
|
@@ -19230,7 +19307,6 @@ var StackedSegment = function StackedSegment(_ref) {
|
|
|
19230
19307
|
yEnd: yEnd
|
|
19231
19308
|
});
|
|
19232
19309
|
var yStack = 0; // running sum for stacking
|
|
19233
|
-
var colorScale = useColorScale(seriesLabels);
|
|
19234
19310
|
return stackedData.map(function (value, index) {
|
|
19235
19311
|
// If value is undefined, skip this segment
|
|
19236
19312
|
if (value === undefined) {
|
|
@@ -19248,7 +19324,7 @@ var StackedSegment = function StackedSegment(_ref) {
|
|
|
19248
19324
|
xCenter: xCenter,
|
|
19249
19325
|
y: y1,
|
|
19250
19326
|
height: colHeight,
|
|
19251
|
-
color: colorScale(seriesLabel),
|
|
19327
|
+
color: colorScale === null || colorScale === void 0 ? void 0 : colorScale(seriesLabel),
|
|
19252
19328
|
value: value,
|
|
19253
19329
|
xLabel: xLabel,
|
|
19254
19330
|
seriesLabel: seriesLabel,
|
|
@@ -19281,7 +19357,8 @@ var ColumnChartContent = function ColumnChartContent(_ref) {
|
|
|
19281
19357
|
data = _ref.data,
|
|
19282
19358
|
yAxisConfig = _ref.yAxisConfig,
|
|
19283
19359
|
xAxisConfig = _ref.xAxisConfig,
|
|
19284
|
-
onBarPress = _ref.onBarPress
|
|
19360
|
+
onBarPress = _ref.onBarPress,
|
|
19361
|
+
colorScale = _ref.colorScale;
|
|
19285
19362
|
var yStart = coordinates.yStart,
|
|
19286
19363
|
yEnd = coordinates.yEnd,
|
|
19287
19364
|
xStart = coordinates.xStart,
|
|
@@ -19319,10 +19396,11 @@ var ColumnChartContent = function ColumnChartContent(_ref) {
|
|
|
19319
19396
|
xCenter: x + scaleX.bandwidth() / 2,
|
|
19320
19397
|
seriesLabels: seriesLabels,
|
|
19321
19398
|
xIndex: xIdx,
|
|
19322
|
-
onBarPress: onBarPress
|
|
19399
|
+
onBarPress: onBarPress,
|
|
19400
|
+
colorScale: colorScale
|
|
19323
19401
|
});
|
|
19324
19402
|
});
|
|
19325
|
-
}, [xLabels, data, xStart, yStart, xEnd, yEnd, onBarPress, yAxisConfig]);
|
|
19403
|
+
}, [xLabels, data, xStart, yStart, xEnd, yEnd, onBarPress, yAxisConfig, colorScale]);
|
|
19326
19404
|
return /*#__PURE__*/React__default.createElement(G, {
|
|
19327
19405
|
testID: "column-chart-content"
|
|
19328
19406
|
}, columns);
|
|
@@ -19365,7 +19443,12 @@ var ColumnChart = function ColumnChart(_ref) {
|
|
|
19365
19443
|
testID = _ref.testID,
|
|
19366
19444
|
headerConfig = _ref.headerConfig,
|
|
19367
19445
|
emptyText = _ref.emptyText,
|
|
19368
|
-
onBarPress = _ref.onBarPress
|
|
19446
|
+
onBarPress = _ref.onBarPress,
|
|
19447
|
+
styleConfig = _ref.styleConfig;
|
|
19448
|
+
var colorScale = useCustomColor({
|
|
19449
|
+
data: data,
|
|
19450
|
+
seriesConfig: styleConfig === null || styleConfig === void 0 ? void 0 : styleConfig.series
|
|
19451
|
+
});
|
|
19369
19452
|
var xLabels = useMemo(function () {
|
|
19370
19453
|
var _data$;
|
|
19371
19454
|
return xAxisConfig.labels && xAxisConfig.labels.length > 0 ? xAxisConfig.labels : ((_data$ = data[0]) === null || _data$ === void 0 ? void 0 : _data$.data.map(function (_, index) {
|
|
@@ -19459,7 +19542,8 @@ var ColumnChart = function ColumnChart(_ref) {
|
|
|
19459
19542
|
data: data,
|
|
19460
19543
|
xAxisConfig: calculatedXAxisConfig,
|
|
19461
19544
|
yAxisConfig: calculatedYAxisConfig,
|
|
19462
|
-
onBarPress: onBarPress
|
|
19545
|
+
onBarPress: onBarPress,
|
|
19546
|
+
colorScale: colorScale
|
|
19463
19547
|
});
|
|
19464
19548
|
}
|
|
19465
19549
|
}));
|
package/lib/index.js
CHANGED
|
@@ -1814,14 +1814,14 @@ var palette$8 = {
|
|
|
1814
1814
|
maasstrichtBlueLight35: maasstrichtBlue$1.lighten35,
|
|
1815
1815
|
maasstrichtBlueLight40: maasstrichtBlue$1.lighten40,
|
|
1816
1816
|
// Update 23 May 2025
|
|
1817
|
-
|
|
1818
|
-
|
|
1819
|
-
|
|
1820
|
-
|
|
1821
|
-
|
|
1822
|
-
|
|
1823
|
-
|
|
1824
|
-
|
|
1817
|
+
primaryLight: mauve$3.base,
|
|
1818
|
+
blueLight: blue$2.base,
|
|
1819
|
+
greenLight: grotesqueGreen.darken10,
|
|
1820
|
+
redLight: pastelRed.lighten25,
|
|
1821
|
+
orangeLight: blazingBonfire.lighten30,
|
|
1822
|
+
yellowLight: yellow$2.base,
|
|
1823
|
+
pinkLight: pink$2.lighten40,
|
|
1824
|
+
greyLight: cumberlandFog.darken15,
|
|
1825
1825
|
primaryMedium: violet$2.lighten20,
|
|
1826
1826
|
blueMedium: ultramarineBlue.base,
|
|
1827
1827
|
greenMedium: green$2.base,
|
|
@@ -18701,6 +18701,8 @@ var XAxis = function XAxis(_ref) {
|
|
|
18701
18701
|
|
|
18702
18702
|
var DASH_ARRAY = [4, 4];
|
|
18703
18703
|
var DEFAULT_LINE_STROKE_WIDTH = 2;
|
|
18704
|
+
var ERROR_COLOR_NUMBER_MISMATCH = 'styleConfig.series should have exact number of colors as the number of labels';
|
|
18705
|
+
var ERROR_COLOR_NOT_FOUND = 'Color {color} not found in the mobile visualization palette.';
|
|
18704
18706
|
|
|
18705
18707
|
var XAxisGrid = function XAxisGrid(_ref) {
|
|
18706
18708
|
var xAxisConfig = _ref.xAxisConfig,
|
|
@@ -18964,6 +18966,17 @@ var ChartFrame = function ChartFrame(_ref) {
|
|
|
18964
18966
|
}))));
|
|
18965
18967
|
};
|
|
18966
18968
|
|
|
18969
|
+
/**
|
|
18970
|
+
* Filter elements that have no color.
|
|
18971
|
+
* @param data - The data to filter.
|
|
18972
|
+
* @returns The filtered data.
|
|
18973
|
+
*/
|
|
18974
|
+
var filterElementHasNoColor = function filterElementHasNoColor(data) {
|
|
18975
|
+
return data.filter(function (element) {
|
|
18976
|
+
return element.color !== undefined;
|
|
18977
|
+
});
|
|
18978
|
+
};
|
|
18979
|
+
|
|
18967
18980
|
// Only use colors that are not maasstrichtBlue
|
|
18968
18981
|
var DEFAULT_COLORS = Object.entries(palette$8).filter(function (_ref) {
|
|
18969
18982
|
var _ref2 = _slicedToArray(_ref, 1),
|
|
@@ -18982,11 +18995,70 @@ var DEFAULT_COLORS = Object.entries(palette$8).filter(function (_ref) {
|
|
|
18982
18995
|
*/
|
|
18983
18996
|
function useColorScale(labels, customColors) {
|
|
18984
18997
|
return React.useMemo(function () {
|
|
18985
|
-
var palette = DEFAULT_COLORS;
|
|
18998
|
+
var palette = customColors && customColors.length > 0 ? customColors : DEFAULT_COLORS;
|
|
18986
18999
|
return ordinal().domain(labels).range(palette);
|
|
18987
19000
|
}, [labels, customColors]);
|
|
18988
19001
|
}
|
|
18989
19002
|
|
|
19003
|
+
/**
|
|
19004
|
+
* Hook to handle custom color assignments for chart series
|
|
19005
|
+
*
|
|
19006
|
+
* This hook manages:
|
|
19007
|
+
* 1. Validation of custom color configurations
|
|
19008
|
+
* 2. Color mapping between series and palette
|
|
19009
|
+
* 3. Fallback to default colors when custom colors aren't provided
|
|
19010
|
+
*
|
|
19011
|
+
* @throws {Error} When custom colors are invalid or don't match data series
|
|
19012
|
+
*/
|
|
19013
|
+
var useCustomColor = function useCustomColor(_ref) {
|
|
19014
|
+
var data = _ref.data,
|
|
19015
|
+
seriesConfig = _ref.seriesConfig;
|
|
19016
|
+
// Check if custom colors are provided and non-empty
|
|
19017
|
+
var hasCustomColors = Boolean(seriesConfig === null || seriesConfig === void 0 ? void 0 : seriesConfig.length);
|
|
19018
|
+
// Process and validate custom color segments
|
|
19019
|
+
var customSegments = React.useMemo(function () {
|
|
19020
|
+
if (!hasCustomColors) return undefined;
|
|
19021
|
+
// Filter out segments without colors
|
|
19022
|
+
var filtered = filterElementHasNoColor(seriesConfig || []);
|
|
19023
|
+
// Validate: number of custom colors must match number of data series
|
|
19024
|
+
if (filtered.length < data.length) {
|
|
19025
|
+
throw new Error(ERROR_COLOR_NUMBER_MISMATCH);
|
|
19026
|
+
}
|
|
19027
|
+
// Validate: all data series must have corresponding custom colors
|
|
19028
|
+
var dataLabels = new Set(data.map(function (d) {
|
|
19029
|
+
return d.label;
|
|
19030
|
+
}));
|
|
19031
|
+
if (!filtered.every(function (series) {
|
|
19032
|
+
return dataLabels.has(series.label);
|
|
19033
|
+
})) {
|
|
19034
|
+
throw new Error(ERROR_COLOR_NUMBER_MISMATCH);
|
|
19035
|
+
}
|
|
19036
|
+
return filtered;
|
|
19037
|
+
}, [seriesConfig, hasCustomColors, data]);
|
|
19038
|
+
// Map custom segments to actual color values from palette
|
|
19039
|
+
var customColors = React.useMemo(function () {
|
|
19040
|
+
if (!customSegments) return [];
|
|
19041
|
+
// Convert color keys to actual color values
|
|
19042
|
+
var colors = customSegments.map(function (series) {
|
|
19043
|
+
var color = palette$8[series.color];
|
|
19044
|
+
// Validate: color key must exist in palette
|
|
19045
|
+
if (color === undefined) {
|
|
19046
|
+
throw new Error(ERROR_COLOR_NOT_FOUND.replace('{color}', series.color));
|
|
19047
|
+
}
|
|
19048
|
+
return color;
|
|
19049
|
+
});
|
|
19050
|
+
return colors;
|
|
19051
|
+
}, [customSegments]);
|
|
19052
|
+
// Create color scale:
|
|
19053
|
+
// - If custom colors exist, use custom color mapping
|
|
19054
|
+
// - Otherwise, fall back to default color mapping
|
|
19055
|
+
return useColorScale(customSegments ? customSegments.map(function (series) {
|
|
19056
|
+
return series.label;
|
|
19057
|
+
}) : data.map(function (series) {
|
|
19058
|
+
return series.label;
|
|
19059
|
+
}), customColors);
|
|
19060
|
+
};
|
|
19061
|
+
|
|
18990
19062
|
/**
|
|
18991
19063
|
* Finds a "nice" number approximately equal to x.
|
|
18992
19064
|
* https://stackoverflow.com/questions/8506881/nice-label-algorithm-for-charts-with-minimum-ticks
|
|
@@ -19056,7 +19128,8 @@ var Line = function Line(_ref) {
|
|
|
19056
19128
|
minValue = _ref.minValue,
|
|
19057
19129
|
labels = _ref.labels,
|
|
19058
19130
|
coordinates = _ref.coordinates,
|
|
19059
|
-
color = _ref.color
|
|
19131
|
+
color = _ref.color,
|
|
19132
|
+
testID = _ref.testID;
|
|
19060
19133
|
var xStart = coordinates.xStart,
|
|
19061
19134
|
xEnd = coordinates.xEnd,
|
|
19062
19135
|
yStart = coordinates.yStart,
|
|
@@ -19088,8 +19161,8 @@ var Line = function Line(_ref) {
|
|
|
19088
19161
|
return lineGenerator(data);
|
|
19089
19162
|
}, [data, lineGenerator]);
|
|
19090
19163
|
return pathData ? /*#__PURE__*/React__namespace.default.createElement(Svg.Path, {
|
|
19091
|
-
testID:
|
|
19092
|
-
accessibilityLabel: "chart-line-maxValue:".concat(maxValue, ",minValue:").concat(minValue, ",labelsLength:").concat(labels.length),
|
|
19164
|
+
testID: testID,
|
|
19165
|
+
accessibilityLabel: "chart-line-maxValue:".concat(maxValue, ",minValue:").concat(minValue, ",labelsLength:").concat(labels.length, ",color:").concat(color),
|
|
19093
19166
|
d: pathData,
|
|
19094
19167
|
stroke: color || theme.colors.secondary,
|
|
19095
19168
|
strokeWidth: DEFAULT_LINE_STROKE_WIDTH,
|
|
@@ -19107,7 +19180,8 @@ var LineChart = function LineChart(_ref) {
|
|
|
19107
19180
|
style = _ref.style,
|
|
19108
19181
|
testID = _ref.testID,
|
|
19109
19182
|
headerConfig = _ref.headerConfig,
|
|
19110
|
-
emptyText = _ref.emptyText
|
|
19183
|
+
emptyText = _ref.emptyText,
|
|
19184
|
+
styleConfig = _ref.styleConfig;
|
|
19111
19185
|
var _useState = React.useState({
|
|
19112
19186
|
width: 0,
|
|
19113
19187
|
height: 0
|
|
@@ -19115,9 +19189,10 @@ var LineChart = function LineChart(_ref) {
|
|
|
19115
19189
|
_useState2 = _slicedToArray(_useState, 2),
|
|
19116
19190
|
chartSize = _useState2[0],
|
|
19117
19191
|
setChartSize = _useState2[1];
|
|
19118
|
-
var colorScale =
|
|
19119
|
-
|
|
19120
|
-
|
|
19192
|
+
var colorScale = useCustomColor({
|
|
19193
|
+
data: data,
|
|
19194
|
+
seriesConfig: styleConfig === null || styleConfig === void 0 ? void 0 : styleConfig.series
|
|
19195
|
+
});
|
|
19121
19196
|
var niceValues = React.useMemo(function () {
|
|
19122
19197
|
var maxDataValue = maxValueFromDataSet(data);
|
|
19123
19198
|
var minDataValue = minValueFromDataSet(data);
|
|
@@ -19158,6 +19233,7 @@ var LineChart = function LineChart(_ref) {
|
|
|
19158
19233
|
var _calculatedXAxisConfi;
|
|
19159
19234
|
return /*#__PURE__*/React__namespace.default.createElement(Line, {
|
|
19160
19235
|
color: colorScale(series.label),
|
|
19236
|
+
testID: "line-".concat(series.label),
|
|
19161
19237
|
key: series.label,
|
|
19162
19238
|
data: series.data,
|
|
19163
19239
|
coordinates: coordinates,
|
|
@@ -19224,7 +19300,7 @@ var Segment = function Segment(_ref) {
|
|
|
19224
19300
|
height: adjustedHeight,
|
|
19225
19301
|
rx: width / 2,
|
|
19226
19302
|
fill: color,
|
|
19227
|
-
accessibilityLabel: "Column segment: value ".concat(value, ", x-label ").concat(xLabel, ", series ").concat(seriesLabel),
|
|
19303
|
+
accessibilityLabel: "Column segment: value ".concat(value, ", x-label ").concat(xLabel, ", series ").concat(seriesLabel, ", color ").concat(color),
|
|
19228
19304
|
testID: testID,
|
|
19229
19305
|
onPress: onPress
|
|
19230
19306
|
});
|
|
@@ -19248,7 +19324,8 @@ var StackedSegment = function StackedSegment(_ref) {
|
|
|
19248
19324
|
coordinates = _ref.coordinates,
|
|
19249
19325
|
xCenter = _ref.xCenter,
|
|
19250
19326
|
xIndex = _ref.xIndex,
|
|
19251
|
-
onBarPress = _ref.onBarPress
|
|
19327
|
+
onBarPress = _ref.onBarPress,
|
|
19328
|
+
colorScale = _ref.colorScale;
|
|
19252
19329
|
var yStart = coordinates.yStart,
|
|
19253
19330
|
yEnd = coordinates.yEnd;
|
|
19254
19331
|
var stackedMaxY = (_yAxisConfig$maxValue = yAxisConfig.maxValue) !== null && _yAxisConfig$maxValue !== void 0 ? _yAxisConfig$maxValue : 0;
|
|
@@ -19259,7 +19336,6 @@ var StackedSegment = function StackedSegment(_ref) {
|
|
|
19259
19336
|
yEnd: yEnd
|
|
19260
19337
|
});
|
|
19261
19338
|
var yStack = 0; // running sum for stacking
|
|
19262
|
-
var colorScale = useColorScale(seriesLabels);
|
|
19263
19339
|
return stackedData.map(function (value, index) {
|
|
19264
19340
|
// If value is undefined, skip this segment
|
|
19265
19341
|
if (value === undefined) {
|
|
@@ -19277,7 +19353,7 @@ var StackedSegment = function StackedSegment(_ref) {
|
|
|
19277
19353
|
xCenter: xCenter,
|
|
19278
19354
|
y: y1,
|
|
19279
19355
|
height: colHeight,
|
|
19280
|
-
color: colorScale(seriesLabel),
|
|
19356
|
+
color: colorScale === null || colorScale === void 0 ? void 0 : colorScale(seriesLabel),
|
|
19281
19357
|
value: value,
|
|
19282
19358
|
xLabel: xLabel,
|
|
19283
19359
|
seriesLabel: seriesLabel,
|
|
@@ -19310,7 +19386,8 @@ var ColumnChartContent = function ColumnChartContent(_ref) {
|
|
|
19310
19386
|
data = _ref.data,
|
|
19311
19387
|
yAxisConfig = _ref.yAxisConfig,
|
|
19312
19388
|
xAxisConfig = _ref.xAxisConfig,
|
|
19313
|
-
onBarPress = _ref.onBarPress
|
|
19389
|
+
onBarPress = _ref.onBarPress,
|
|
19390
|
+
colorScale = _ref.colorScale;
|
|
19314
19391
|
var yStart = coordinates.yStart,
|
|
19315
19392
|
yEnd = coordinates.yEnd,
|
|
19316
19393
|
xStart = coordinates.xStart,
|
|
@@ -19348,10 +19425,11 @@ var ColumnChartContent = function ColumnChartContent(_ref) {
|
|
|
19348
19425
|
xCenter: x + scaleX.bandwidth() / 2,
|
|
19349
19426
|
seriesLabels: seriesLabels,
|
|
19350
19427
|
xIndex: xIdx,
|
|
19351
|
-
onBarPress: onBarPress
|
|
19428
|
+
onBarPress: onBarPress,
|
|
19429
|
+
colorScale: colorScale
|
|
19352
19430
|
});
|
|
19353
19431
|
});
|
|
19354
|
-
}, [xLabels, data, xStart, yStart, xEnd, yEnd, onBarPress, yAxisConfig]);
|
|
19432
|
+
}, [xLabels, data, xStart, yStart, xEnd, yEnd, onBarPress, yAxisConfig, colorScale]);
|
|
19355
19433
|
return /*#__PURE__*/React__namespace.default.createElement(Svg.G, {
|
|
19356
19434
|
testID: "column-chart-content"
|
|
19357
19435
|
}, columns);
|
|
@@ -19394,7 +19472,12 @@ var ColumnChart = function ColumnChart(_ref) {
|
|
|
19394
19472
|
testID = _ref.testID,
|
|
19395
19473
|
headerConfig = _ref.headerConfig,
|
|
19396
19474
|
emptyText = _ref.emptyText,
|
|
19397
|
-
onBarPress = _ref.onBarPress
|
|
19475
|
+
onBarPress = _ref.onBarPress,
|
|
19476
|
+
styleConfig = _ref.styleConfig;
|
|
19477
|
+
var colorScale = useCustomColor({
|
|
19478
|
+
data: data,
|
|
19479
|
+
seriesConfig: styleConfig === null || styleConfig === void 0 ? void 0 : styleConfig.series
|
|
19480
|
+
});
|
|
19398
19481
|
var xLabels = React.useMemo(function () {
|
|
19399
19482
|
var _data$;
|
|
19400
19483
|
return xAxisConfig.labels && xAxisConfig.labels.length > 0 ? xAxisConfig.labels : ((_data$ = data[0]) === null || _data$ === void 0 ? void 0 : _data$.data.map(function (_, index) {
|
|
@@ -19488,7 +19571,8 @@ var ColumnChart = function ColumnChart(_ref) {
|
|
|
19488
19571
|
data: data,
|
|
19489
19572
|
xAxisConfig: calculatedXAxisConfig,
|
|
19490
19573
|
yAxisConfig: calculatedYAxisConfig,
|
|
19491
|
-
onBarPress: onBarPress
|
|
19574
|
+
onBarPress: onBarPress,
|
|
19575
|
+
colorScale: colorScale
|
|
19492
19576
|
});
|
|
19493
19577
|
}
|
|
19494
19578
|
}));
|
package/package.json
CHANGED
|
@@ -4,10 +4,10 @@
|
|
|
4
4
|
|
|
5
5
|
import React, { memo, useMemo } from 'react';
|
|
6
6
|
import { G } from 'react-native-svg';
|
|
7
|
-
import {
|
|
7
|
+
import { deepCompareValue } from '../../../utils/helpers';
|
|
8
8
|
import useScaleBandX from '../shared/hooks/useScaleBandX';
|
|
9
|
+
import { DataValue, Series, XAxisConfig, YAxisConfig } from '../types';
|
|
9
10
|
import StackedSegment from './StackedSegment';
|
|
10
|
-
import { deepCompareValue } from '../../../utils/helpers';
|
|
11
11
|
|
|
12
12
|
interface ColumnChartContentProps {
|
|
13
13
|
coordinates: { yStart: number; yEnd: number; xStart: number; xEnd: number };
|
|
@@ -24,6 +24,10 @@ interface ColumnChartContentProps {
|
|
|
24
24
|
seriesIndex: number;
|
|
25
25
|
xIndex: number;
|
|
26
26
|
}) => void;
|
|
27
|
+
/**
|
|
28
|
+
* A function that maps series labels to colors.
|
|
29
|
+
*/
|
|
30
|
+
colorScale?: (label: string) => string | undefined;
|
|
27
31
|
}
|
|
28
32
|
|
|
29
33
|
/**
|
|
@@ -37,6 +41,7 @@ const ColumnChartContent = ({
|
|
|
37
41
|
yAxisConfig,
|
|
38
42
|
xAxisConfig,
|
|
39
43
|
onBarPress,
|
|
44
|
+
colorScale,
|
|
40
45
|
}: ColumnChartContentProps) => {
|
|
41
46
|
const { yStart, yEnd, xStart, xEnd } = coordinates;
|
|
42
47
|
|
|
@@ -74,10 +79,21 @@ const ColumnChartContent = ({
|
|
|
74
79
|
seriesLabels={seriesLabels}
|
|
75
80
|
xIndex={xIdx}
|
|
76
81
|
onBarPress={onBarPress}
|
|
82
|
+
colorScale={colorScale}
|
|
77
83
|
/>
|
|
78
84
|
);
|
|
79
85
|
});
|
|
80
|
-
}, [
|
|
86
|
+
}, [
|
|
87
|
+
xLabels,
|
|
88
|
+
data,
|
|
89
|
+
xStart,
|
|
90
|
+
yStart,
|
|
91
|
+
xEnd,
|
|
92
|
+
yEnd,
|
|
93
|
+
onBarPress,
|
|
94
|
+
yAxisConfig,
|
|
95
|
+
colorScale,
|
|
96
|
+
]);
|
|
81
97
|
|
|
82
98
|
return <G testID="column-chart-content">{columns}</G>;
|
|
83
99
|
};
|
|
@@ -56,7 +56,7 @@ const Segment = ({
|
|
|
56
56
|
height={adjustedHeight}
|
|
57
57
|
rx={width / 2}
|
|
58
58
|
fill={color}
|
|
59
|
-
accessibilityLabel={`Column segment: value ${value}, x-label ${xLabel}, series ${seriesLabel}`}
|
|
59
|
+
accessibilityLabel={`Column segment: value ${value}, x-label ${xLabel}, series ${seriesLabel}, color ${color}`}
|
|
60
60
|
testID={testID}
|
|
61
61
|
onPress={onPress}
|
|
62
62
|
/>
|
|
@@ -3,11 +3,10 @@
|
|
|
3
3
|
// Each segment represents a value from a different series, stacked vertically. Uses the Segment component for rendering each bar.
|
|
4
4
|
|
|
5
5
|
import React, { memo } from 'react';
|
|
6
|
-
import Segment from './Segment';
|
|
7
|
-
import { DataValue, YAxisConfig } from '../types';
|
|
8
|
-
import useScaleLinearY from '../shared/hooks/useScaleLinearY';
|
|
9
|
-
import useColorScale from '../shared/hooks/useColorScale';
|
|
10
6
|
import { deepCompareValue } from '../../../utils/helpers';
|
|
7
|
+
import useScaleLinearY from '../shared/hooks/useScaleLinearY';
|
|
8
|
+
import { DataValue, YAxisConfig } from '../types';
|
|
9
|
+
import Segment from './Segment';
|
|
11
10
|
|
|
12
11
|
interface StackedSegmentProps {
|
|
13
12
|
stackedData: Array<DataValue>;
|
|
@@ -27,6 +26,10 @@ interface StackedSegmentProps {
|
|
|
27
26
|
seriesIndex: number;
|
|
28
27
|
xIndex: number;
|
|
29
28
|
}) => void;
|
|
29
|
+
/**
|
|
30
|
+
* A function that maps series labels to colors.
|
|
31
|
+
*/
|
|
32
|
+
colorScale?: (label: string) => string | undefined;
|
|
30
33
|
}
|
|
31
34
|
|
|
32
35
|
/**
|
|
@@ -43,6 +46,7 @@ const StackedSegment: React.FC<StackedSegmentProps> = ({
|
|
|
43
46
|
xCenter,
|
|
44
47
|
xIndex,
|
|
45
48
|
onBarPress,
|
|
49
|
+
colorScale,
|
|
46
50
|
}) => {
|
|
47
51
|
const { yStart, yEnd } = coordinates;
|
|
48
52
|
const stackedMaxY = yAxisConfig.maxValue ?? 0;
|
|
@@ -54,7 +58,7 @@ const StackedSegment: React.FC<StackedSegmentProps> = ({
|
|
|
54
58
|
});
|
|
55
59
|
|
|
56
60
|
let yStack = 0; // running sum for stacking
|
|
57
|
-
|
|
61
|
+
|
|
58
62
|
return stackedData.map((value, index) => {
|
|
59
63
|
// If value is undefined, skip this segment
|
|
60
64
|
if (value === undefined) {
|
|
@@ -74,7 +78,7 @@ const StackedSegment: React.FC<StackedSegmentProps> = ({
|
|
|
74
78
|
xCenter={xCenter}
|
|
75
79
|
y={y1}
|
|
76
80
|
height={colHeight}
|
|
77
|
-
color={colorScale(seriesLabel)}
|
|
81
|
+
color={colorScale?.(seriesLabel)}
|
|
78
82
|
value={value}
|
|
79
83
|
xLabel={xLabel}
|
|
80
84
|
seriesLabel={seriesLabel}
|
|
@@ -25,7 +25,7 @@ describe('Segment', () => {
|
|
|
25
25
|
|
|
26
26
|
const segment = getByTestId('test-segment');
|
|
27
27
|
expect(segment.props.accessibilityLabel).toBe(
|
|
28
|
-
'Column segment: value 10, x-label A, series Series 1'
|
|
28
|
+
'Column segment: value 10, x-label A, series Series 1, color #000000'
|
|
29
29
|
);
|
|
30
30
|
});
|
|
31
31
|
|