react95
Version:
Refreshed Windows95 UI components for modern web apps - React95
106 lines (102 loc) • 3.41 kB
JavaScript
import React__default, { forwardRef, useRef, useState, useCallback, useEffect } from 'react';
import styled, { css } from 'styled-components';
import { blockSizes } from '../common/system.mjs';
import { StyledScrollView } from '../ScrollView/ScrollView.mjs';
const Wrapper = styled.div`
display: inline-block;
height: ${blockSizes.md};
width: 100%;
`;
const ProgressCutout = styled(StyledScrollView)`
width: 100%;
height: 100%;
position: relative;
text-align: center;
padding: 0;
overflow: hidden;
&:before {
z-index: 1;
}
`;
const commonBarStyles = css`
width: calc(100% - 4px);
height: calc(100% - 4px);
display: flex;
align-items: center;
justify-content: space-around;
`;
const WhiteBar = styled.div`
position: relative;
top: 4px;
${commonBarStyles}
background: ${({ theme }) => theme.canvas};
color: #000;
margin-left: 2px;
margin-top: -2px;
color: ${({ theme }) => theme.materialText};
`;
const BlueBar = styled.div`
position: absolute;
top: 2px;
left: 2px;
${commonBarStyles}
color: ${({ theme }) => theme.materialTextInvert};
background: ${({ theme }) => theme.progress};
clip-path: polygon(
0 0,
${({ value = 0 }) => value}% 0,
${({ value = 0 }) => value}% 100%,
0 100%
);
transition: 0.4s linear clip-path;
`;
const TilesWrapper = styled.div`
width: calc(100% - 6px);
height: calc(100% - 8px);
position: absolute;
left: 3px;
top: 4px;
box-sizing: border-box;
display: inline-flex;
`;
const tileWidth = 17;
const Tile = styled.span`
display: inline-block;
width: ${tileWidth}px;
box-sizing: border-box;
height: 100%;
background: ${({ theme }) => theme.progress};
border-color: ${({ theme }) => theme.material};
border-width: 0px 1px;
border-style: solid;
`;
const ProgressBar = forwardRef(({ hideValue = false, shadow = true, value, variant = "default", ...otherProps }, ref) => {
const displayValue = hideValue ? null : `${value}%`;
const tilesWrapperRef = useRef(null);
const [tiles, setTiles] = useState([]);
const updateTilesNumber = useCallback(() => {
if (!tilesWrapperRef.current || value === void 0) {
return;
}
const progressWidth = tilesWrapperRef.current.getBoundingClientRect().width;
const newTilesNumber = Math.round(value / 100 * progressWidth / tileWidth);
setTiles(Array.from({ length: newTilesNumber }));
}, [value]);
useEffect(() => {
updateTilesNumber();
window.addEventListener("resize", updateTilesNumber);
return () => window.removeEventListener("resize", updateTilesNumber);
}, [updateTilesNumber]);
return React__default.createElement(
Wrapper,
{ "aria-valuenow": value !== void 0 ? Math.round(value) : void 0, ref, role: "progressbar", variant, ...otherProps },
React__default.createElement(ProgressCutout, { variant, shadow }, variant === "default" ? React__default.createElement(
React__default.Fragment,
null,
React__default.createElement(WhiteBar, { "data-testid": "defaultProgress1" }, displayValue),
React__default.createElement(BlueBar, { "data-testid": "defaultProgress2", value }, displayValue)
) : React__default.createElement(TilesWrapper, { ref: tilesWrapperRef, "data-testid": "tileProgress" }, tiles.map((_, index) => React__default.createElement(Tile, { key: index }))))
);
});
ProgressBar.displayName = "ProgressBar";
export { ProgressBar };