react-responsive-scale
Version:
A React component for responsive scaling of data dashboards
331 lines (330 loc) • 12 kB
JavaScript
(function(global2, factory) {
typeof exports === "object" && typeof module !== "undefined" ? factory(exports, require("react"), require("react/jsx-runtime")) : typeof define === "function" && define.amd ? define(["exports", "react", "react/jsx-runtime"], factory) : (global2 = typeof globalThis !== "undefined" ? globalThis : global2 || self, factory(global2.ReactResponsiveScale = {}, global2.React, global2.jsxRuntime));
})(this, function(exports2, react, jsxRuntime) {
"use strict";
const ScaleContext = react.createContext(null);
function isObject(value) {
var type = typeof value;
return value != null && (type == "object" || type == "function");
}
var freeGlobal = typeof global == "object" && global && global.Object === Object && global;
var freeSelf = typeof self == "object" && self && self.Object === Object && self;
var root = freeGlobal || freeSelf || Function("return this")();
var now = function() {
return root.Date.now();
};
var reWhitespace = /\s/;
function trimmedEndIndex(string) {
var index = string.length;
while (index-- && reWhitespace.test(string.charAt(index))) {
}
return index;
}
var reTrimStart = /^\s+/;
function baseTrim(string) {
return string ? string.slice(0, trimmedEndIndex(string) + 1).replace(reTrimStart, "") : string;
}
var Symbol$1 = root.Symbol;
var objectProto$1 = Object.prototype;
var hasOwnProperty = objectProto$1.hasOwnProperty;
var nativeObjectToString$1 = objectProto$1.toString;
var symToStringTag$1 = Symbol$1 ? Symbol$1.toStringTag : void 0;
function getRawTag(value) {
var isOwn = hasOwnProperty.call(value, symToStringTag$1), tag = value[symToStringTag$1];
try {
value[symToStringTag$1] = void 0;
var unmasked = true;
} catch (e) {
}
var result = nativeObjectToString$1.call(value);
if (unmasked) {
if (isOwn) {
value[symToStringTag$1] = tag;
} else {
delete value[symToStringTag$1];
}
}
return result;
}
var objectProto = Object.prototype;
var nativeObjectToString = objectProto.toString;
function objectToString(value) {
return nativeObjectToString.call(value);
}
var nullTag = "[object Null]", undefinedTag = "[object Undefined]";
var symToStringTag = Symbol$1 ? Symbol$1.toStringTag : void 0;
function baseGetTag(value) {
if (value == null) {
return value === void 0 ? undefinedTag : nullTag;
}
return symToStringTag && symToStringTag in Object(value) ? getRawTag(value) : objectToString(value);
}
function isObjectLike(value) {
return value != null && typeof value == "object";
}
var symbolTag = "[object Symbol]";
function isSymbol(value) {
return typeof value == "symbol" || isObjectLike(value) && baseGetTag(value) == symbolTag;
}
var NAN = 0 / 0;
var reIsBadHex = /^[-+]0x[0-9a-f]+$/i;
var reIsBinary = /^0b[01]+$/i;
var reIsOctal = /^0o[0-7]+$/i;
var freeParseInt = parseInt;
function toNumber(value) {
if (typeof value == "number") {
return value;
}
if (isSymbol(value)) {
return NAN;
}
if (isObject(value)) {
var other = typeof value.valueOf == "function" ? value.valueOf() : value;
value = isObject(other) ? other + "" : other;
}
if (typeof value != "string") {
return value === 0 ? value : +value;
}
value = baseTrim(value);
var isBinary = reIsBinary.test(value);
return isBinary || reIsOctal.test(value) ? freeParseInt(value.slice(2), isBinary ? 2 : 8) : reIsBadHex.test(value) ? NAN : +value;
}
var FUNC_ERROR_TEXT = "Expected a function";
var nativeMax = Math.max, nativeMin = Math.min;
function debounce(func, wait, options) {
var lastArgs, lastThis, maxWait, result, timerId, lastCallTime, lastInvokeTime = 0, leading = false, maxing = false, trailing = true;
if (typeof func != "function") {
throw new TypeError(FUNC_ERROR_TEXT);
}
wait = toNumber(wait) || 0;
if (isObject(options)) {
leading = !!options.leading;
maxing = "maxWait" in options;
maxWait = maxing ? nativeMax(toNumber(options.maxWait) || 0, wait) : maxWait;
trailing = "trailing" in options ? !!options.trailing : trailing;
}
function invokeFunc(time) {
var args = lastArgs, thisArg = lastThis;
lastArgs = lastThis = void 0;
lastInvokeTime = time;
result = func.apply(thisArg, args);
return result;
}
function leadingEdge(time) {
lastInvokeTime = time;
timerId = setTimeout(timerExpired, wait);
return leading ? invokeFunc(time) : result;
}
function remainingWait(time) {
var timeSinceLastCall = time - lastCallTime, timeSinceLastInvoke = time - lastInvokeTime, timeWaiting = wait - timeSinceLastCall;
return maxing ? nativeMin(timeWaiting, maxWait - timeSinceLastInvoke) : timeWaiting;
}
function shouldInvoke(time) {
var timeSinceLastCall = time - lastCallTime, timeSinceLastInvoke = time - lastInvokeTime;
return lastCallTime === void 0 || timeSinceLastCall >= wait || timeSinceLastCall < 0 || maxing && timeSinceLastInvoke >= maxWait;
}
function timerExpired() {
var time = now();
if (shouldInvoke(time)) {
return trailingEdge(time);
}
timerId = setTimeout(timerExpired, remainingWait(time));
}
function trailingEdge(time) {
timerId = void 0;
if (trailing && lastArgs) {
return invokeFunc(time);
}
lastArgs = lastThis = void 0;
return result;
}
function cancel() {
if (timerId !== void 0) {
clearTimeout(timerId);
}
lastInvokeTime = 0;
lastArgs = lastCallTime = lastThis = timerId = void 0;
}
function flush() {
return timerId === void 0 ? result : trailingEdge(now());
}
function debounced() {
var time = now(), isInvoking = shouldInvoke(time);
lastArgs = arguments;
lastThis = this;
lastCallTime = time;
if (isInvoking) {
if (timerId === void 0) {
return leadingEdge(lastCallTime);
}
if (maxing) {
clearTimeout(timerId);
timerId = setTimeout(timerExpired, wait);
return invokeFunc(lastCallTime);
}
}
if (timerId === void 0) {
timerId = setTimeout(timerExpired, wait);
}
return result;
}
debounced.cancel = cancel;
debounced.flush = flush;
return debounced;
}
function ReactResponsiveScale(props) {
const {
rootValue = 16,
precision = 5,
rootWidth = 1920,
rootHeight = 1080,
wait = 300,
backgroundColor,
backgroundImage,
style,
children
} = props;
const rootRef = react.useRef(null);
const [rootSize, setRootSize] = react.useState(null);
react.useEffect(() => {
const computeSize = (size2) => {
if (!size2 || !size2.width || !size2.height) {
return { width: 0, height: 0, rootFontSize: Math.round(rootValue * 10 ** precision) / 10 ** precision };
}
const aspectRatio = rootWidth / rootHeight;
let width = 0;
let height = 0;
if (size2 && size2.width && size2.height) {
const wrapperWPH = size2.width / size2.height;
if (wrapperWPH > aspectRatio) {
height = size2.height;
width = Math.round(height * aspectRatio * 10 ** precision) / 10 ** precision;
} else if (wrapperWPH < aspectRatio) {
width = size2.width;
height = Math.round(width / aspectRatio * 10 ** precision) / 10 ** precision;
} else {
width = size2.width;
height = size2.height;
}
}
return {
width,
height,
rootFontSize: Math.round(width / (rootWidth / rootValue) * 10 ** precision) / 10 ** precision
};
};
const { clientWidth, clientHeight } = rootRef.current;
const size = computeSize({ width: clientWidth, height: clientHeight });
setRootSize(size);
const onResize = debounce(
() => {
const { clientWidth: clientWidth2, clientHeight: clientHeight2 } = rootRef.current;
const size2 = computeSize({ width: clientWidth2, height: clientHeight2 });
setRootSize(size2);
},
wait
// { leading: false, trailing: true }
);
window.addEventListener("resize", onResize, true);
return () => {
window.removeEventListener("resize", onResize, true);
};
}, [rootValue, precision, rootWidth, rootHeight, wait]);
const calcWidth = react.useCallback(
(percent) => {
if (typeof rootSize?.width !== "number" || typeof percent !== "number" || percent < 0 || percent > 100) {
return 0;
}
return Math.round(rootSize.width * (percent / 100) * 10 ** precision) / 10 ** precision;
},
[rootSize?.width, precision]
);
const calcHeight = react.useCallback(
(percent) => {
if (typeof rootSize?.height !== "number" || typeof percent !== "number" || percent < 0 || percent > 100) {
return 0;
}
return Math.round(rootSize.height * (percent / 100) * 10 ** precision) / 10 ** precision;
},
[rootSize?.height, precision]
);
const calcPx = react.useCallback(
(px) => {
if (typeof rootSize?.rootFontSize !== "number" || typeof px !== "number") {
return px;
}
return Math.round(px * rootSize.rootFontSize / rootValue * 10 ** precision) / 10 ** precision;
},
[rootSize?.rootFontSize, rootValue, precision]
);
const calcRem = react.useCallback(
(px) => {
if (typeof px !== "number") {
return "0rem";
}
return Math.round(px / rootValue * 10 ** precision) / 10 ** precision + "rem";
},
[rootValue, precision]
);
const ScaleContextValue = react.useMemo(
() => ({
rootWidth: rootSize?.width || 0,
rootHeight: rootSize?.height || 0,
rootValue: rootSize?.rootFontSize || 0,
calcWidth,
calcHeight,
calcPx,
calcRem
}),
[rootSize?.width, rootSize?.height, rootSize?.rootFontSize, calcWidth, calcHeight, calcPx, calcRem]
);
react.useEffect(() => {
const fontSize = rootSize?.rootFontSize ?? rootValue;
document.documentElement.style.fontSize = fontSize + "px";
}, [rootValue, rootSize?.rootFontSize]);
return /* @__PURE__ */ jsxRuntime.jsx(ScaleContext.Provider, { value: ScaleContextValue, children: /* @__PURE__ */ jsxRuntime.jsxs(
"div",
{
ref: rootRef,
style: {
width: "100vw",
height: "100vh",
position: "fixed",
left: 0,
top: 0,
display: "flex",
alignItems: "center",
justifyContent: "center",
overflow: "hidden",
backgroundColor,
...style
},
children: [
backgroundImage ? /* @__PURE__ */ jsxRuntime.jsx(
"div",
{
style: {
position: "absolute",
width: "100%",
height: "100%",
top: 0,
left: 0,
backgroundImage,
backgroundSize: "cover",
backgroundRepeat: "no-repeat",
backgroundPosition: "center",
filter: "blur(10px)",
zIndex: -1
}
}
) : null,
/* @__PURE__ */ jsxRuntime.jsx("div", { style: { width: rootSize?.width, height: rootSize?.height, position: "relative" }, children: rootSize ? children : null })
]
}
) });
}
exports2.ResponsiveScale = ReactResponsiveScale;
exports2.ScaleContext = ScaleContext;
exports2.default = ReactResponsiveScale;
Object.defineProperties(exports2, { __esModule: { value: true }, [Symbol.toStringTag]: { value: "Module" } });
});