antd-group-slider
Version:
Grouped slider based on ant-design
424 lines (357 loc) • 13.5 kB
JavaScript
function _interopDefault (ex) { return (ex && (typeof ex === 'object') && 'default' in ex) ? ex['default'] : ex; }
var React = require('react');
var React__default = _interopDefault(React);
var antd = require('antd');
function _inheritsLoose(subClass, superClass) {
subClass.prototype = Object.create(superClass.prototype);
subClass.prototype.constructor = subClass;
_setPrototypeOf(subClass, superClass);
}
function _setPrototypeOf(o, p) {
_setPrototypeOf = Object.setPrototypeOf || function _setPrototypeOf(o, p) {
o.__proto__ = p;
return o;
};
return _setPrototypeOf(o, p);
}
function _objectWithoutPropertiesLoose(source, excluded) {
if (source == null) return {};
var target = {};
var sourceKeys = Object.keys(source);
var key, i;
for (i = 0; i < sourceKeys.length; i++) {
key = sourceKeys[i];
if (excluded.indexOf(key) >= 0) continue;
target[key] = source[key];
}
return target;
}
var DEFAULT_SEPARATOR = '-';
function renderRangeInText(range, text, separator) {
if (text === void 0) {
text = '';
}
if (separator === void 0) {
separator = DEFAULT_SEPARATOR;
}
if (!range || range.length !== 2) {
return text;
}
var left = range[0];
var right = range[1];
return text.replace(/{{range}}/, "" + left + separator + right);
}
var DEFAULT_PLACEHOLDER = 'Description for range {{range}}';
var SideTextDescription = function SideTextDescription(_ref) {
var leftText = _ref.leftText,
rightText = _ref.rightText,
children = _ref.children;
return /*#__PURE__*/React__default.createElement("div", {
className: "antd-group-slider-item__description"
}, /*#__PURE__*/React__default.createElement("div", {
className: "antd-group-slider-item__description-left-text"
}, leftText), children, /*#__PURE__*/React__default.createElement("div", {
className: "antd-group-slider-item__description-right-text"
}, rightText));
};
var GroupSliderLine = /*#__PURE__*/function (_React$Component) {
_inheritsLoose(GroupSliderLine, _React$Component);
function GroupSliderLine() {
var _this;
for (var _len = arguments.length, args = new Array(_len), _key = 0; _key < _len; _key++) {
args[_key] = arguments[_key];
}
_this = _React$Component.call.apply(_React$Component, [this].concat(args)) || this;
_this.state = {
right: _this.props.value[1],
left: _this.props.value[0]
};
_this.onChange = function (val) {
var left = val[0],
right = val[1];
var nextRight = left === _this.state.left ? right : left;
_this.setState({
right: Math.max(_this.state.left, nextRight)
});
};
_this.calculateMarks = function (min, max) {
var _ref2;
if (min === void 0) {
min = 0;
}
var mid = Math.floor((max + min) / 2);
return _ref2 = {}, _ref2[min] = min.toString(), _ref2[mid] = mid.toString(), _ref2[max] = max.toString(), _ref2;
};
_this.renderDescription = function () {
var descriptionConfig = _this.props.descriptionConfig || {};
var placeholder = descriptionConfig.placeholder,
type = descriptionConfig.type,
separator = descriptionConfig.separator,
leftText = descriptionConfig.leftText,
leftAddonText = descriptionConfig.leftAddonText,
rightText = descriptionConfig.rightText,
rightAddonText = descriptionConfig.rightAddonText;
if (type === 'none') {
return /*#__PURE__*/React__default.createElement(React__default.Fragment, null);
}
var range = [_this.state.left, _this.state.right];
var inputProps = {
className: 'antd-group-slider-item__description',
placeholder: placeholder ? renderRangeInText(range, placeholder, separator) : renderRangeInText(range, DEFAULT_PLACEHOLDER, separator),
defaultValue: _this.props.initialDescription,
onChange: function onChange(e) {
return _this.props.updateDescription(e.target.value);
}
};
if (type === 'input') {
var inputPropsWithAddon = Object.assign({}, inputProps, {
addonBefore: renderRangeInText(range, leftAddonText, separator),
addonAfter: renderRangeInText(range, rightAddonText, separator)
});
return /*#__PURE__*/React__default.createElement(SideTextDescription, {
range: range,
leftText: renderRangeInText(range, leftText, separator),
rightText: renderRangeInText(range, rightText, separator)
}, /*#__PURE__*/React__default.createElement(antd.Input, inputPropsWithAddon));
}
return /*#__PURE__*/React__default.createElement(SideTextDescription, {
range: range,
leftText: renderRangeInText(range, leftText, separator),
rightText: renderRangeInText(range, rightText, separator)
}, /*#__PURE__*/React__default.createElement(antd.Input.TextArea, inputProps));
};
return _this;
}
var _proto = GroupSliderLine.prototype;
_proto.render = function render() {
var _this2 = this;
var _this$state = this.state,
left = _this$state.left,
right = _this$state.right;
var marks = this.props.marks || this.calculateMarks(this.props.min, this.props.max);
return /*#__PURE__*/React__default.createElement("div", {
className: "antd-group-slider-item"
}, /*#__PURE__*/React__default.createElement(antd.Slider, {
className: "antd-group-slider-item__slider",
range: true,
min: this.props.min,
max: this.props.max,
marks: marks,
value: [left, right],
onChange: this.onChange,
onAfterChange: function onAfterChange(val) {
_this2.props.onAfterRangeChange(val);
_this2.setState({
right: _this2.props.value[1],
left: _this2.props.value[0]
});
}
}), this.renderDescription(), this.props.extra ? this.props.extra : /*#__PURE__*/React__default.createElement(React__default.Fragment, null));
};
return GroupSliderLine;
}(React__default.Component);
function syncRanges(inputRanges, range, index) {
var ranges = [].concat(inputRanges);
var currentRight = range[1];
var rightNeighbor = ranges[index + 1];
if (rightNeighbor) {
var nextRight = rightNeighbor[1];
if (currentRight >= nextRight - 1) {
currentRight = nextRight - 1;
rightNeighbor[0] = rightNeighbor[1];
} else {
rightNeighbor[0] = currentRight + 1;
}
}
ranges[index][1] = currentRight;
return ranges;
}
function fillGaps(data, config) {
if (config === void 0) {
config = {
fillGaps: true
};
}
if (!config.fillGaps) return data;
if (data.ranges && data.ranges.length < 2) return data;
var descriptions = data.descriptions;
var ranges = standardizeRanges(data.ranges);
var output = fillMissingGaps(ranges, descriptions);
return output;
}
function standardizeRanges(ranges) {
return ranges.map(function (range) {
var left = Math.min.apply(Math, range);
var right = Math.max.apply(Math, range);
return [left, right];
});
}
function enoughForNewRange(ranges, leftIndex, rightIndex) {
return ranges[rightIndex][0] - ranges[leftIndex][1] > 1;
}
function fillMissingGaps(inputRanges, inputDescriptions) {
var ranges = [].concat(inputRanges);
var descriptions = [].concat(inputDescriptions);
for (var rightIndex = ranges.length - 1; rightIndex > 0; rightIndex--) {
var leftIndex = rightIndex - 1;
if (enoughForNewRange(ranges, leftIndex, rightIndex)) {
var missingRange = calculateMissingRange(ranges, leftIndex, rightIndex);
ranges.splice(rightIndex, 0, missingRange);
descriptions.splice(rightIndex, 0, '');
}
}
return {
ranges: ranges,
descriptions: descriptions
};
}
function calculateMissingRange(ranges, leftIndex, rightIndex) {
var left = ranges[leftIndex][1] + 1;
var right = ranges[rightIndex][0] - 1;
return [left, right];
}
var _excluded = ["min", "max"];
var DEFAULT_LEFT = 0;
var DEFAULT_RIGHT = 100;
var TooltipAddButton = function TooltipAddButton(_ref) {
var children = _ref.children;
return /*#__PURE__*/React__default.createElement(antd.Tooltip, {
trigger: "hover",
placement: "top",
title: "Only can add range if the point range is not fully covered"
}, children);
};
var GroupSlider = function GroupSlider(_ref2) {
var _ref2$min = _ref2.min,
min = _ref2$min === void 0 ? DEFAULT_LEFT : _ref2$min,
_ref2$max = _ref2.max,
max = _ref2$max === void 0 ? DEFAULT_RIGHT : _ref2$max,
props = _objectWithoutPropertiesLoose(_ref2, _excluded);
var _useState = React.useState([[min, max]]),
ranges = _useState[0],
setRanges = _useState[1];
var _useState2 = React.useState([]),
descriptions = _useState2[0],
setDescriptions = _useState2[1];
var _useState3 = React.useState([]),
lineExtras = _useState3[0],
setLineExtras = _useState3[1];
React.useEffect(function () {
if (props.initialValues) {
setLineExtras(lineExtras.lineExtras);
var processedInitialValues = fillGaps(props.initialValues, props.initialValuesConfig);
var _ranges = processedInitialValues.ranges,
_descriptions = processedInitialValues.descriptions;
var leftMost = _ranges[0][0];
_ranges[0][0] = Math.max(min, leftMost);
var lastIndex = _ranges.length - 1;
var rightMost = _ranges[lastIndex][1];
_ranges[lastIndex][1] = Math.min(max, rightMost);
setRanges(_ranges);
setDescriptions(_descriptions);
}
}, []);
React.useEffect(function () {
ranges[0][0] = min;
}, [min]);
var isFullRange = function isFullRange() {
var values = new Set();
ranges.forEach(function (r) {
var left = r[0],
right = r[1];
for (var i = left; i <= right; i++) {
if (i >= 0 && i <= 100) values.add(i);
}
});
return values.size === parseInt(max) + 1;
};
React.useEffect(function () {
if (props.onChange) {
props.onChange({
ranges: ranges,
descriptions: descriptions,
isFullRange: isFullRange()
});
}
}, [ranges, descriptions]);
var addRange = function addRange() {
var newRanges = [].concat(ranges);
var lastIndex = ranges.length - 1;
var left = ranges[lastIndex][1];
newRanges.push([left + 1, max]);
setRanges(newRanges);
};
var syncNewRange = function syncNewRange(updatedRange, index) {
var nextRanges = syncRanges(ranges, updatedRange, index);
setRanges(nextRanges);
};
var _updateDescription = function updateDescription(description, index) {
var nextDescriptions = [].concat(descriptions);
nextDescriptions[index] = description;
setDescriptions(nextDescriptions);
};
var renderPointRangeGroupLine = function renderPointRangeGroupLine() {
return ranges.map(function (range, i) {
var _props$lineExtras;
return /*#__PURE__*/React__default.createElement(React__default.Fragment, {
key: range
}, /*#__PURE__*/React__default.createElement(GroupSliderLine, {
marks: props.marks,
descriptionConfig: props.descriptionConfig,
onAfterRangeChange: function onAfterRangeChange(data) {
return syncNewRange(data, i);
},
updateDescription: function updateDescription(data) {
return _updateDescription(data, i);
},
initialDescription: descriptions[i],
extra: (_props$lineExtras = props.lineExtras) === null || _props$lineExtras === void 0 ? void 0 : _props$lineExtras[i],
value: range,
max: max,
min: min
}), props.showDivider ? /*#__PURE__*/React__default.createElement(antd.Divider, null) : /*#__PURE__*/React__default.createElement(React__default.Fragment, null));
});
};
var isAbleToAddRange = function isAbleToAddRange() {
var lastIndex = ranges.length - 1;
var rightMost = ranges[lastIndex][1];
return rightMost > max - 1;
};
var cannotRemoveRange = function cannotRemoveRange() {
return ranges.length <= 1;
};
var removeLastRange = function removeLastRange() {
ranges.pop();
var lastIndex = ranges.length - 1;
ranges[lastIndex][1] = max;
setRanges([].concat(ranges));
descriptions.pop();
setDescriptions([].concat(descriptions));
};
var removeText = props.removeButtonText || 'Remove last range';
var addText = props.addButtonText || 'Add more range';
var addButton = /*#__PURE__*/React__default.createElement(antd.Button, {
className: "antd-group-slider__btn-add-range",
disabled: isAbleToAddRange(),
ghost: true,
type: "primary",
onClick: addRange
}, addText);
return /*#__PURE__*/React__default.createElement("div", {
className: "antd-group-slider"
}, renderPointRangeGroupLine(), /*#__PURE__*/React__default.createElement(antd.Row, {
className: "antd-group-slider__footer",
gutter: 4
}, /*#__PURE__*/React__default.createElement(antd.Col, {
span: 12
}, isFullRange() ? /*#__PURE__*/React__default.createElement(TooltipAddButton, null, addButton) : addButton), /*#__PURE__*/React__default.createElement(antd.Col, {
span: 12
}, /*#__PURE__*/React__default.createElement(antd.Button, {
className: "antd-group-slider__btn-remove-range",
danger: true,
disabled: cannotRemoveRange(),
onClick: removeLastRange
}, removeText))));
};
module.exports = GroupSlider;
//# sourceMappingURL=index.js.map