@razorpay/blade
Version:
The Design System that powers Razorpay
310 lines (300 loc) • 15.2 kB
JavaScript
import _slicedToArray from '@babel/runtime/helpers/slicedToArray';
import _defineProperty from '@babel/runtime/helpers/defineProperty';
import _objectWithoutProperties from '@babel/runtime/helpers/objectWithoutProperties';
import React__default, { useRef, useEffect, createElement, useState } from 'react';
import '../../../node_modules/recharts/es6/index.js';
import '../utils/index.js';
import '../CommonChartComponents/index.js';
import { componentId } from '../CommonChartComponents/tokens.js';
import { useBarChartContext, BarChartContext } from './BarChartContext.js';
import { DISTANCE_BETWEEN_STACKED_BARS, componentIds, BAR_SIZE, DISTANCE_BETWEEN_BARS, DISTANCE_BETWEEN_CATEGORY_BARS } from './tokens.js';
import getIn from '../../../utils/lodashButBetter/get.js';
import '../../../utils/makeAnalyticsAttribute/index.js';
import isNumber from '../../../utils/lodashButBetter/isNumber.js';
import '../../../utils/metaAttribute/index.js';
import '../../BladeProvider/index.js';
import '../../Box/BaseBox/index.js';
import '../../../utils/assignWithoutSideEffects/index.js';
import '../../../utils/isValidAllowedChildren/index.js';
import { jsxs, Fragment, jsx } from 'react/jsx-runtime';
import useTheme from '../../BladeProvider/useTheme.js';
import useChartsColorTheme from '../utils/useColorTheme.js';
import { getHighestColorInRange } from '../utils/getHighestColorInRange.js';
import { Bar } from '../../../node_modules/recharts/es6/cartesian/Bar.js';
import { assignWithoutSideEffects } from '../../../utils/assignWithoutSideEffects/assignWithoutSideEffects.js';
import { getComponentId } from '../../../utils/isValidAllowedChildren/isValidAllowedChildren.js';
import { assignDataColorMapping } from '../utils/assignDataColorMapping/assignDataColorMapping.js';
import { CommonChartComponentsContext } from '../CommonChartComponents/CommonChartComponentsContext.js';
import { BaseBox } from '../../Box/BaseBox/BaseBox.web.js';
import { metaAttribute } from '../../../utils/metaAttribute/metaAttribute.web.js';
import { makeAnalyticsAttribute } from '../../../utils/makeAnalyticsAttribute/makeAnalyticsAttribute.js';
import { ResponsiveContainer } from '../../../node_modules/recharts/es6/component/ResponsiveContainer.js';
import { BarChart } from '../../../node_modules/recharts/es6/chart/BarChart.js';
var _excluded = ["color", "name", "dataKey", "activeBar", "label", "showLegend", "hide", "_index"],
_excluded2 = ["children", "colorTheme", "layout", "testID", "data"];
function _createForOfIteratorHelper(r, e) { var t = "undefined" != typeof Symbol && r[Symbol.iterator] || r["@@iterator"]; if (!t) { if (Array.isArray(r) || (t = _unsupportedIterableToArray(r)) || e && r && "number" == typeof r.length) { t && (r = t); var _n = 0, F = function F() {}; return { s: F, n: function n() { return _n >= r.length ? { done: !0 } : { done: !1, value: r[_n++] }; }, e: function e(r) { throw r; }, f: F }; } throw new TypeError("Invalid attempt to iterate non-iterable instance.\nIn order to be iterable, non-array objects must have a [Symbol.iterator]() method."); } var o, a = !0, u = !1; return { s: function s() { t = t.call(r); }, n: function n() { var r = t.next(); return a = r.done, r; }, e: function e(r) { u = !0, o = r; }, f: function f() { try { a || null == t["return"] || t["return"](); } finally { if (u) throw o; } } }; }
function _unsupportedIterableToArray(r, a) { if (r) { if ("string" == typeof r) return _arrayLikeToArray(r, a); var t = {}.toString.call(r).slice(8, -1); return "Object" === t && r.constructor && (t = r.constructor.name), "Map" === t || "Set" === t ? Array.from(r) : "Arguments" === t || /^(?:Ui|I)nt(?:8|16|32)(?:Clamped)?Array$/.test(t) ? _arrayLikeToArray(r, a) : void 0; } }
function _arrayLikeToArray(r, a) { (null == a || a > r.length) && (a = r.length); for (var e = 0, n = Array(a); e < a; e++) n[e] = r[e]; return n; }
function ownKeys(e, r) { var t = Object.keys(e); if (Object.getOwnPropertySymbols) { var o = Object.getOwnPropertySymbols(e); r && (o = o.filter(function (r) { return Object.getOwnPropertyDescriptor(e, r).enumerable; })), t.push.apply(t, o); } return t; }
function _objectSpread(e) { for (var r = 1; r < arguments.length; r++) { var t = null != arguments[r] ? arguments[r] : {}; r % 2 ? ownKeys(Object(t), !0).forEach(function (r) { _defineProperty(e, r, t[r]); }) : Object.getOwnPropertyDescriptors ? Object.defineProperties(e, Object.getOwnPropertyDescriptors(t)) : ownKeys(Object(t)).forEach(function (r) { Object.defineProperty(e, r, Object.getOwnPropertyDescriptor(t, r)); }); } return e; }
// Bar component - resolves Blade color tokens to actual colors
var _ChartBar = /*#__PURE__*/React__default.memo(function (_ref) {
var color = _ref.color,
name = _ref.name,
dataKey = _ref.dataKey,
_ref$activeBar = _ref.activeBar,
activeBar = _ref$activeBar === void 0 ? false : _ref$activeBar,
_ref$label = _ref.label,
label = _ref$label === void 0 ? false : _ref$label,
_ref$showLegend = _ref.showLegend,
showLegend = _ref$showLegend === void 0 ? true : _ref$showLegend,
hide = _ref.hide,
_ref$_index = _ref._index,
_index = _ref$_index === void 0 ? 0 : _ref$_index,
rest = _objectWithoutProperties(_ref, _excluded);
var _useTheme = useTheme(),
theme = _useTheme.theme;
var _useBarChartContext = useBarChartContext(),
layout = _useBarChartContext.layout,
activeIndex = _useBarChartContext.activeIndex,
_colorTheme = _useBarChartContext.colorTheme,
totalBars = _useBarChartContext.totalBars;
var defaultColorArray = useChartsColorTheme({
colorTheme: _colorTheme,
chartName: 'bar',
chartDataIndicators: totalBars
});
var fill = getIn(theme.colors, color !== null && color !== void 0 ? color : defaultColorArray[_index]);
var strokeFill = getIn(theme.colors, getHighestColorInRange({
colorToken: color !== null && color !== void 0 ? color : defaultColorArray[_index],
followIntensityMapping: Boolean(color)
}));
var animationBegin = theme.motion.duration.gentle;
var animationDuration = theme.motion.duration.gentle;
/**
* We need to control the animation of the bar.
* Recharts tries to animate bar when tooltip is hovered. we don't need that.
* So we need to control the animation of the bar.
* we currently need it for entry , exit and when a bar is hidden only.
*/
var shouldAnimatedBar = useRef(true);
useEffect(function () {
shouldAnimatedBar.current = true;
}, [hide]);
return /*#__PURE__*/createElement(Bar, _objectSpread(_objectSpread({}, rest), {}, {
fill: fill,
legendType: showLegend ? 'rect' : 'none',
activeBar: activeBar,
label: label,
animationBegin: animationBegin,
animationDuration: animationDuration,
animationEasing: "linear",
dataKey: dataKey,
name: name,
key: "".concat(dataKey, "-").concat(_index, "-").concat(name),
hide: hide,
isAnimationActive: shouldAnimatedBar.current,
onAnimationStart: function onAnimationStart() {
shouldAnimatedBar.current = true;
},
onAnimationEnd: function onAnimationEnd() {
shouldAnimatedBar.current = false;
},
shape: function shape(props) {
var _ref2 = props,
fill = _ref2.fill,
x = _ref2.x,
y = _ref2.y,
width = _ref2.width,
height = _ref2.height,
barIndex = _ref2.index;
var fillOpacity = isNumber(activeIndex) ? barIndex === activeIndex ? 1 : 0.2 : 1;
var gap = DISTANCE_BETWEEN_STACKED_BARS;
var isVertical = layout === 'vertical';
if (isVertical) {
return /*#__PURE__*/jsxs(Fragment, {
children: [/*#__PURE__*/jsx("rect", {
fill: fill,
x: x + gap / 1.5,
y: y,
width: width - gap,
height: height,
fillOpacity: fillOpacity
}), /*#__PURE__*/jsx("rect", {
fill: strokeFill,
x: x + gap / 1.5 + (width - gap) - 1.5 // Position at the right end
,
y: y,
width: width > gap ? 1.5 : 0,
height: height,
fillOpacity: fillOpacity
})]
});
}
return /*#__PURE__*/jsxs(Fragment, {
children: [/*#__PURE__*/jsx("rect", {
fill: fill,
x: x,
y: y + gap / 1.5,
width: width,
height: height > gap ? height - gap : 0,
fillOpacity: fillOpacity
}), /*#__PURE__*/jsx("rect", {
fill: strokeFill,
x: x,
y: y + gap / 1.5,
width: width,
height: height > gap ? 1.5 : 0,
fillOpacity: fillOpacity
})]
});
}
}));
});
var ChartBar = /*#__PURE__*/assignWithoutSideEffects(_ChartBar, {
componentId: componentIds.chartBar
});
// BarChart wrapper with default margin, auto-color assignment, and max bars guard
var ChartBarWrapper = function ChartBarWrapper(_ref3) {
var children = _ref3.children,
_ref3$colorTheme = _ref3.colorTheme,
colorTheme = _ref3$colorTheme === void 0 ? 'categorical' : _ref3$colorTheme,
_ref3$layout = _ref3.layout,
layout = _ref3$layout === void 0 ? 'horizontal' : _ref3$layout,
testID = _ref3.testID,
_ref3$data = _ref3.data,
data = _ref3$data === void 0 ? [] : _ref3$data,
restProps = _objectWithoutProperties(_ref3, _excluded2);
var _useState = useState(undefined),
_useState2 = _slicedToArray(_useState, 2),
activeIndex = _useState2[0],
setActiveIndex = _useState2[1];
// State to track which bars are currently selected (visible)
var _useState3 = useState(undefined),
_useState4 = _slicedToArray(_useState3, 2),
selectedDataKeys = _useState4[0],
setSelectedDataKeys = _useState4[1];
var themeColors = useChartsColorTheme({
colorTheme: colorTheme,
chartName: 'bar'
});
var _React$useMemo = React__default.useMemo(function () {
var childrenArray = React__default.Children.toArray(children);
var dataColorMapping = {};
// Count ChartBar components
var totalBars = childrenArray.filter(function (child) {
return /*#__PURE__*/React__default.isValidElement(child) && getComponentId(child) === componentIds.chartBar;
}).length;
// Find ChartXAxis and extract secondaryDataKey
var secondaryDataKey;
var _iterator = _createForOfIteratorHelper(childrenArray),
_step;
try {
for (_iterator.s(); !(_step = _iterator.n()).done;) {
var child = _step.value;
if (/*#__PURE__*/React__default.isValidElement(child) && getComponentId(child) === componentId.chartXAxis) {
var _child$props3;
secondaryDataKey = (_child$props3 = child.props) === null || _child$props3 === void 0 ? void 0 : _child$props3.secondaryDataKey;
break;
}
}
} catch (err) {
_iterator.e(err);
} finally {
_iterator.f();
}
var BarChartIndex = 0;
/**
* We check to check child of ChartBarWrapper. if they have any custom color we store that.
* We need these mapping because colors of tooltip & legend is determine based on this
* recharts do provide a color but it is hex code and we need blade color token .
*/
var modifiedChildren = React__default.Children.map(children, function (child) {
if (/*#__PURE__*/React__default.isValidElement(child) && getComponentId(child) === componentIds.chartBar) {
var _child$props, _child$props2;
var childColor = child === null || child === void 0 || (_child$props = child.props) === null || _child$props === void 0 ? void 0 : _child$props.color;
var dataKey = child === null || child === void 0 || (_child$props2 = child.props) === null || _child$props2 === void 0 ? void 0 : _child$props2.dataKey;
if (dataKey) {
// assign colors to the dataColorMapping, if no color is assigned we assign color in `assignDataColorMapping`
dataColorMapping[dataKey] = {
colorToken: childColor,
isCustomColor: Boolean(childColor)
};
}
// Pass hide prop based on whether this bar's dataKey is NOT in selectedDataKeys
// If selectedDataKeys is undefined, show all bars (default behavior)
return /*#__PURE__*/React__default.cloneElement(child, {
_index: BarChartIndex++,
hide: selectedDataKeys ? !selectedDataKeys.includes(dataKey) : false
});
}
return child;
});
assignDataColorMapping(dataColorMapping, themeColors);
return {
barChartModifiedChildrens: modifiedChildren,
totalBars: totalBars,
dataColorMapping: dataColorMapping,
secondaryDataKey: secondaryDataKey
};
}, [children, themeColors, selectedDataKeys]),
barChartModifiedChildrens = _React$useMemo.barChartModifiedChildrens,
totalBars = _React$useMemo.totalBars,
dataColorMapping = _React$useMemo.dataColorMapping,
secondaryDataKey = _React$useMemo.secondaryDataKey;
// Build secondary label map internally from ChartXAxis's secondaryDataKey prop
var secondaryLabelMap = React__default.useMemo(function () {
if (!secondaryDataKey || !data) return undefined;
var map = {};
data.forEach(function (item, index) {
map[index] = item[secondaryDataKey];
});
return map;
}, [data, secondaryDataKey]);
return /*#__PURE__*/jsx(CommonChartComponentsContext.Provider, {
value: {
chartName: 'bar',
dataColorMapping: dataColorMapping,
secondaryLabelMap: secondaryLabelMap,
dataLength: data === null || data === void 0 ? void 0 : data.length,
selectedDataKeys: selectedDataKeys,
setSelectedDataKeys: setSelectedDataKeys
},
children: /*#__PURE__*/jsx(BaseBox, _objectSpread(_objectSpread(_objectSpread(_objectSpread({}, metaAttribute({
name: 'bar-chart',
testID: testID
})), makeAnalyticsAttribute(restProps)), {}, {
width: "100%",
height: "100%"
}, restProps), {}, {
children: /*#__PURE__*/jsx(BarChartContext.Provider, {
value: {
layout: layout,
activeIndex: activeIndex,
colorTheme: colorTheme,
totalBars: totalBars
},
children: /*#__PURE__*/jsx(ResponsiveContainer, {
width: "100%",
height: "100%",
children: /*#__PURE__*/jsx(BarChart, {
barSize: BAR_SIZE,
barGap: DISTANCE_BETWEEN_BARS,
barCategoryGap: DISTANCE_BETWEEN_CATEGORY_BARS,
onMouseMove: function onMouseMove(state) {
setActiveIndex(state !== null && state !== void 0 && state.activeIndex ? Number(state === null || state === void 0 ? void 0 : state.activeIndex) : undefined);
},
onMouseLeave: function onMouseLeave() {
setActiveIndex(undefined);
},
layout: layout,
data: data,
children: barChartModifiedChildrens
})
})
})
}))
});
};
export { ChartBar, ChartBarWrapper };
//# sourceMappingURL=BarChart.web.js.map