@amaui/ui-react
Version:
UI for React
465 lines (459 loc) • 20 kB
JavaScript
import _extends from "@babel/runtime/helpers/extends";
import _objectWithoutProperties from "@babel/runtime/helpers/objectWithoutProperties";
import _defineProperty from "@babel/runtime/helpers/defineProperty";
const _excluded = ["tonal", "color", "size", "parts", "lineCap", "orientation", "linePosition", "width", "height", "padding", "paddingVertical", "paddingHorizontal", "gap", "border", "background", "boundaryWidth", "lineProgress", "linesVisible", "marksVisible", "labelsVisible", "marks", "markSize", "markWidth", "labels", "additional", "textProps", "pathProps", "SvgProps", "MarkProps", "LabelProps", "BackgroundProps", "BorderProps", "LineProps", "LineMainProps", "LinesProgressProps", "LineProgressProps", "Component", "className", "style", "children"],
_excluded2 = ["size", "padding", "position"],
_excluded3 = ["value", "padding", "position"],
_excluded4 = ["x", "y", "value"];
function ownKeys(object, enumerableOnly) { var keys = Object.keys(object); if (Object.getOwnPropertySymbols) { var symbols = Object.getOwnPropertySymbols(object); enumerableOnly && (symbols = symbols.filter(function (sym) { return Object.getOwnPropertyDescriptor(object, sym).enumerable; })), keys.push.apply(keys, symbols); } return keys; }
function _objectSpread(target) { for (var i = 1; i < arguments.length; i++) { var source = null != arguments[i] ? arguments[i] : {}; i % 2 ? ownKeys(Object(source), !0).forEach(function (key) { _defineProperty(target, key, source[key]); }) : Object.getOwnPropertyDescriptors ? Object.defineProperties(target, Object.getOwnPropertyDescriptors(source)) : ownKeys(Object(source)).forEach(function (key) { Object.defineProperty(target, key, Object.getOwnPropertyDescriptor(source, key)); }); } return target; }
import React from 'react';
import { clamp, is, parse } from '@amaui/utils';
import { classNames, style as styleMethod, useAmauiTheme } from '@amaui/style-react';
import SurfaceElement from '../Surface';
import { staticClassName } from '../utils';
const useStyle = styleMethod(theme => ({
root: {
width: '100%'
},
size_small: {
maxWidth: '180px'
},
size_regular: {
maxWidth: '240px'
},
size_large: {
maxWidth: '300px'
},
label: _objectSpread(_objectSpread({}, theme.typography.values.b2), {}, {
textAnchor: 'middle',
alignmentBaseline: 'central',
dominantBaseline: 'central'
}),
svg: {
position: 'relative',
width: '100%',
height: 'auto'
}
}), {
name: 'amaui-LinearMeter'
});
const LinearMeter = /*#__PURE__*/React.forwardRef((props_, ref) => {
const theme = useAmauiTheme();
const props = React.useMemo(() => _objectSpread(_objectSpread(_objectSpread({}, theme?.ui?.elements?.all?.props?.default), theme?.ui?.elements?.amauiLinearMeter?.props?.default), props_), [props_]);
const Surface = React.useMemo(() => theme?.elements?.Surface || SurfaceElement, [theme]);
const {
tonal = true,
color = 'primary',
size = 'regular',
parts: parts_ = 1,
lineCap,
// vertical, horizontal
orientation = 'horizontal',
// start, center, end
linePosition = 'end',
width: width_,
height: height_,
padding: outsidePadding = 0,
paddingVertical,
paddingHorizontal,
gap = 0,
border = false,
background = false,
boundaryWidth = 1,
lineProgress = false,
linesVisible = true,
marksVisible = true,
labelsVisible = true,
marks: marks_ = [],
markSize = 4,
markWidth = 1,
labels: labels_ = [],
additional,
textProps,
pathProps,
SvgProps,
MarkProps,
LabelProps,
BackgroundProps,
BorderProps,
LineProps,
LineMainProps,
LinesProgressProps,
LineProgressProps,
Component = 'div',
className,
style,
children
} = props,
other = _objectWithoutProperties(props, _excluded);
const {
classes
} = useStyle();
const refs = {
root: React.useRef(undefined)
};
const styles = {
root: {}
};
let width = width_ !== undefined ? width_ : size === 'regular' ? 240 : size === 'large' ? 300 : 180;
let height = height_ !== undefined ? height_ : 100;
if (orientation === 'vertical') {
height = height_ !== undefined ? height_ : size === 'regular' ? 240 : size === 'large' ? 300 : 180;
width = width_ !== undefined ? width_ : 100;
styles.root.maxWidth = width;
} else {
styles.root.height = height;
}
const parts = clamp(parse(parts_), 1, 1000);
const paddings = {
x: paddingHorizontal !== undefined ? paddingHorizontal : outsidePadding || 0,
y: paddingVertical !== undefined ? paddingVertical : outsidePadding || 0
};
if (!['small', 'regular', 'large'].includes(size)) styles.root.maxWidth = size;
const marks = React.useMemo(() => {
const values = [];
if (marks_.length) {
let marksValues = marks_;
if (!is('array', marksValues[0])) marksValues = [marksValues];
marksValues.forEach((marksValue, index) => {
values[index] = [];
marksValue.forEach(mark => {
const {
size: size_,
padding: markPadding = 0,
position
} = mark,
other_ = _objectWithoutProperties(mark, _excluded2);
if (orientation === 'horizontal') {
const total = width - paddings.x * 2;
const x = total * (position / 100);
let y = height - paddings.y - boundaryWidth - markPadding;
let yl = y - size_;
if (linePosition === 'start') {
y = paddings.y + boundaryWidth + markPadding;
yl = y + size_;
}
if (linePosition === 'center') {
y = height / 2 - boundaryWidth / 2 - markPadding;
yl = y - size_;
}
if (linePosition === 'end') {
y = height - paddings.y - boundaryWidth - markPadding;
yl = y - size_;
}
values[index].push(_objectSpread({
d: ['M', x + paddings.x, y, 'L', x + paddings.x, yl].join(' ')
}, other_));
}
if (orientation === 'vertical') {
const total = height - paddings.y * 2;
const y = total * (position / 100);
let x = width - paddings.x - boundaryWidth - markPadding;
let xl = x - size_;
if (linePosition === 'start') {
x = paddings.x + boundaryWidth + markPadding;
xl = x + size_;
}
if (linePosition === 'center') {
x = width / 2 + boundaryWidth / 2 + markPadding;
xl = x + size_;
}
if (linePosition === 'end') {
x = width - paddings.y - boundaryWidth - markPadding;
xl = x - size_;
}
values[index].push(_objectSpread({
d: ['M', x, y + paddings.y, 'L', xl, y + paddings.y].join(' ')
}, other_));
}
});
});
}
return values;
}, [orientation, linePosition, width, height, parts, marks_, markWidth, markSize, boundaryWidth, lineCap, paddingVertical, paddingHorizontal, outsidePadding, gap]);
const labels = React.useMemo(() => {
const values = [];
if (labels_.length) {
const marksPadding = marks_?.length ? (marks_ || []).sort((a, b) => b.size - a.size)[0]?.size || markSize : 0;
let labelsValues = labels_;
if (!is('array', labelsValues[0])) labelsValues = [labelsValues];
labelsValues.forEach((labelsValue, index) => {
values[index] = [];
labelsValue.forEach(label => {
const {
value,
padding: labelPadding = 0,
position
} = label,
other_ = _objectWithoutProperties(label, _excluded3);
const fontSize = label.style?.fontSize !== undefined ? label.style.fontSize : 14;
if (orientation === 'horizontal') {
const total = width - paddings.x * 2;
const x = total * (position / 100);
let y = height - paddings.y - boundaryWidth - labelPadding;
if (linePosition === 'start') {
y = paddings.y + boundaryWidth + labelPadding + fontSize / 2 + marksPadding;
}
if (linePosition === 'center') {
y = height / 2 - boundaryWidth / 2 - labelPadding - fontSize / 2 - marksPadding;
}
if (linePosition === 'end') {
y = height - paddings.y - boundaryWidth - labelPadding - fontSize / 2 - marksPadding;
}
values[index].push(_objectSpread({
x: x + paddings.x,
y,
value
}, other_));
}
if (orientation === 'vertical') {
const total = height - paddings.y * 2;
const y = total * (position / 100);
let x = width - paddings.x - boundaryWidth - labelPadding;
if (linePosition === 'start') {
x = paddings.x + boundaryWidth + labelPadding + fontSize / 2 + marksPadding;
}
if (linePosition === 'center') {
x = width / 2 + boundaryWidth / 2 + labelPadding + fontSize / 2 + marksPadding;
}
if (linePosition === 'end') {
x = width - paddings.y - boundaryWidth - labelPadding - fontSize / 2 - marksPadding;
}
values[index].push(_objectSpread({
x,
y: y + paddings.y,
value
}, other));
}
});
});
}
return values;
}, [orientation, linePosition, width, height, parts, marks_, markWidth, markSize, boundaryWidth, lineCap, outsidePadding, gap]);
const lines = React.useMemo(() => {
const values = [];
let value = [];
if (orientation === 'horizontal') {
const lineCapOffset = ['round', 'square'].includes(lineCap) ? boundaryWidth / 2 : 0;
const offset = paddings.x * 2 + (lineCapOffset ? boundaryWidth * parts : 0);
const total = width;
const part = (total - (parts - 1) * gap - offset) / parts;
let previousValue = 0;
const x = 0 + lineCapOffset + paddings.x;
let y = height - boundaryWidth / 2;
if (linePosition === 'start') {
y = boundaryWidth / 2;
y += paddings.y;
}
if (linePosition === 'center') y = height / 2;
if (linePosition === 'end') {
y = height - boundaryWidth / 2;
y -= paddings.y;
}
for (let i = 0; i < parts; i++) {
// move to bottom left
if (i === 0) value.push(
// Move to bottom left
'm', x, y);
// line
value.push('l', part, 0);
// Previous value with/out the gap value
if (gap > 0 && i < parts - 1) previousValue += part + gap + (lineCapOffset ? boundaryWidth : 0);else previousValue += part + (lineCapOffset ? boundaryWidth : 0);
values.push({
d: value.join(' ')
});
if (i === 0) previousValue += lineCapOffset + paddings.x;
// move for the next value
if (i < parts - 1) {
value = ['m', previousValue, y];
}
}
}
if (orientation === 'vertical') {
const lineCapOffset = ['round', 'square'].includes(lineCap) ? boundaryWidth / 2 : 0;
const offset = paddings.y * 2 + (lineCapOffset ? boundaryWidth * parts : 0);
const total = height;
const part = (total - (parts - 1) * gap - offset) / parts;
let previousValue = 0;
let x = width - boundaryWidth / 2;
const y = 0 + lineCapOffset + paddings.y;
if (linePosition === 'start') {
x = boundaryWidth / 2;
x += paddings.x;
}
if (linePosition === 'center') x = width / 2;
if (linePosition === 'end') {
x = width - boundaryWidth / 2;
x -= paddings.x;
}
for (let i = 0; i < parts; i++) {
// move to bottom left
if (i === 0) value.push(
// Move to bottom left
'm', x, y);
// line
value.push('l', 0, part);
// Previous value with/out the gap value
if (gap > 0 && i < parts - 1) previousValue += part + gap + (lineCapOffset ? boundaryWidth : 0);else previousValue += part + (lineCapOffset ? boundaryWidth : 0);
values.push({
d: value.join(' ')
});
if (i === 0) previousValue += lineCapOffset + paddings.y;
// move for the next value
if (i < parts - 1) {
value = ['m', x, previousValue];
}
}
}
return values;
}, [width, height, parts, boundaryWidth, lineCap, orientation, linePosition, paddingVertical, paddingHorizontal, outsidePadding, gap]);
const pathBackground = React.useMemo(() => {
const values = [];
if (orientation === 'horizontal') {
values.push(
// Move
'M', paddings.x, height - paddings.y, 'L', paddings.x, paddings.y, 'L', width - paddings.x, paddings.y, 'L', width - paddings.x, height - paddings.y, 'Z');
}
if (orientation === 'vertical') {
values.push(
// Move
'M', width - paddings.x, paddings.y, 'L', paddings.x, paddings.y, 'L', paddings.x, height - paddings.y, 'L', width - paddings.x, height - paddings.y, 'Z');
}
return values.join(' ');
}, [orientation, linePosition, width, height, boundaryWidth, outsidePadding, paddingVertical, paddingHorizontal]);
const pathBorder = React.useMemo(() => {
const values = [];
if (orientation === 'horizontal') {
if (linePosition === 'start') {
values.push(
// Move
'M', paddings.x, paddings.y, 'L', paddings.x, height - paddings.y, 'L', width - paddings.x, height - paddings.y, 'L', width - paddings.x, paddings.y);
}
if (linePosition === 'center') {
values.push(
// Move
'M', paddings.x, height - paddings.y, 'L', paddings.x, paddings.y, 'L', width - paddings.x, paddings.y, 'L', width - paddings.x, height - paddings.y, 'Z');
}
if (linePosition === 'end') {
values.push(
// Move
'M', paddings.x, height - paddings.y, 'L', paddings.x, paddings.y, 'L', width - paddings.x, paddings.y, 'L', width - paddings.x, height - paddings.y);
}
}
if (orientation === 'vertical') {
if (linePosition === 'start') {
values.push(
// Move
'M', paddings.x, height - paddings.y, 'L', width - paddings.x, height - paddings.y, 'L', width - paddings.x, paddings.y, 'L', paddings.x, paddings.y);
}
if (linePosition === 'center') {
values.push(
// Move
'M', width - paddings.x, paddings.y, 'L', paddings.x, paddings.y, 'L', paddings.x, height - paddings.y, 'L', width - paddings.x, height - paddings.y, 'Z');
}
if (linePosition === 'end') {
values.push(
// Move
'M', width - paddings.x, paddings.y, 'L', paddings.x, paddings.y, 'L', paddings.x, height - paddings.y, 'L', width - paddings.x, height - paddings.y);
}
}
return values.join(' ');
}, [orientation, linePosition, width, height, boundaryWidth, outsidePadding, paddingVertical, paddingHorizontal]);
return /*#__PURE__*/React.createElement(Component, _extends({
ref: item => {
if (ref) {
if (is('function', ref)) ref(item);else ref.current = item;
}
refs.root.current = item;
},
className: classNames([staticClassName('LinearMeter', theme) && ['amaui-LinearMeter-root', `amaui-LinearMeter-size-${size}`], className, classes.root, classes[`size_${size}`]]),
style: _objectSpread(_objectSpread({}, styles.root), style)
}, other), additional, /*#__PURE__*/React.createElement(Surface, {
tonal: tonal,
color: color
}, _ref => {
let {
color: color_,
backgroundColor
} = _ref;
return /*#__PURE__*/React.createElement("svg", _extends({
xmlns: "http://www.w3.org/2000/svg",
viewBox: `0 0 ${width || 0} ${height || 0}`
}, SvgProps, {
className: classNames([staticClassName('LinearMeter', theme) && ['amaui-LinearMeter-svg'], SvgProps?.className, classes.svg])
}), background && /*#__PURE__*/React.createElement("path", _extends({
d: pathBackground,
fill: backgroundColor,
stroke: "none"
}, pathProps, BackgroundProps)), border && /*#__PURE__*/React.createElement("path", _extends({
d: pathBorder,
fill: "none",
stroke: color_,
strokeWidth: boundaryWidth
}, pathProps, BorderProps)), linesVisible && /*#__PURE__*/React.createElement("g", {
className: classNames([staticClassName('LinearMeter', theme) && ['amaui-LinearMeter-arcs'], classes.arcs])
}, lines.map((item, index) => /*#__PURE__*/React.createElement("path", _extends({
key: index,
d: item.d,
fill: "none",
stroke: color_,
strokeWidth: boundaryWidth,
strokeLinecap: lineCap
}, pathProps, LineProps, LineMainProps)))), linesVisible && lineProgress && /*#__PURE__*/React.createElement("g", _extends({}, LinesProgressProps, {
className: classNames([staticClassName('LinearMeter', theme) && ['amaui-LinearMeter-lines-progress'], LinesProgressProps?.className, classes.lines_progress])
}), lines.map((item, index) => /*#__PURE__*/React.createElement("path", _extends({
key: index,
d: item.d,
fill: "none",
stroke: color_,
strokeWidth: boundaryWidth,
strokeLinecap: lineCap
}, pathProps, LineProps, LineProgressProps)))), children && /*#__PURE__*/React.createElement("g", {
className: classNames([staticClassName('LinearMeter', theme) && ['amaui-LinearMeter-children'], classes.children])
}, React.Children.toArray(children).map((item, index) => {
return /*#__PURE__*/React.cloneElement(item, {
key: index,
fill: item.props.fill !== undefined ? item.props.fill : color_,
stroke: item.props.stroke !== undefined ? item.props.stroke : color_,
// clean up
value: undefined,
style: _objectSpread(_objectSpread({}, item.props.value !== undefined ? {
transform: orientation === 'horizontal' ? `translate3d(${paddings.x + (item.props.value / 100 || 0) * (width - paddings.x * 2)}px, 0, 0)` : `translate3d(0, ${paddings.y + (item.props.value / 100 || 0) * (height - paddings.y * 2)}px, 0)`
} : undefined), item.props.style)
});
})), marksVisible && !!marks_.length && marks.map((marksValue, index) => /*#__PURE__*/React.createElement("g", {
key: index,
className: classNames([staticClassName('LinearMeter', theme) && ['amaui-LinearMeter-marks'], classes.marks])
}, marksValue.map((item, index_) => /*#__PURE__*/React.createElement("path", _extends({
key: index_,
d: item.d,
fill: "none",
stroke: color_,
strokeWidth: item.width !== undefined ? item.width : markWidth,
strokeLinecap: lineCap
}, pathProps, MarkProps))))), labelsVisible && !!labels_.length && labels.map((labelsValue, index) => /*#__PURE__*/React.createElement("g", {
key: index,
className: classNames([staticClassName('LinearMeter', theme) && ['amaui-LinearMeter-labels'], classes.labels])
}, labelsValue.map((item, index_) => {
const {
x,
y,
value
} = item,
other_ = _objectWithoutProperties(item, _excluded4);
return /*#__PURE__*/React.createElement("text", _extends({
key: index_,
x: x,
y: y
}, other_, textProps, LabelProps, {
className: classNames([staticClassName('LinearMeter', theme) && ['amaui-LinearMeter-label'], other_?.className, textProps?.className, LabelProps?.className, classes.label]),
style: _objectSpread(_objectSpread(_objectSpread({
fill: color_
}, other_.style), textProps?.style), LabelProps?.style)
}), value);
}))));
}));
});
LinearMeter.displayName = 'amaui-LinearMeter';
export default LinearMeter;