react-fitter
Version:
<h1 align="center">🫸 𝚛𝚎𝚊𝚌𝚝-𝚏𝚒𝚝𝚝𝚎𝚛 🫷</h1>
141 lines (137 loc) • 4.26 kB
JavaScript
;
var __defProp = Object.defineProperty;
var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
var __getOwnPropNames = Object.getOwnPropertyNames;
var __hasOwnProp = Object.prototype.hasOwnProperty;
var __export = (target, all) => {
for (var name in all)
__defProp(target, name, { get: all[name], enumerable: true });
};
var __copyProps = (to, from, except, desc) => {
if (from && typeof from === "object" || typeof from === "function") {
for (let key of __getOwnPropNames(from))
if (!__hasOwnProp.call(to, key) && key !== except)
__defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
}
return to;
};
var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
// lib/index.ts
var lib_exports = {};
__export(lib_exports, {
Fitter: () => Fitter
});
module.exports = __toCommonJS(lib_exports);
// lib/Fitter.tsx
var import_react2 = require("react");
// lib/hooks.ts
var import_react = require("react");
var debounce = (callback, delay) => {
let timeout;
return () => {
clearTimeout(timeout);
timeout = setTimeout(callback, delay);
};
};
var useDebounce = (callback, delay) => {
const callbackRef = (0, import_react.useRef)(callback);
(0, import_react.useLayoutEffect)(() => {
callbackRef.current = callback;
});
return (0, import_react.useMemo)(
() => debounce((...args) => callbackRef.current(...args), delay),
[delay]
);
};
var useResizeObserver = (ref, callback, enabled) => {
const width = (0, import_react.useRef)(0);
(0, import_react.useEffect)(() => {
if (!ref.current) return;
if (!enabled) return;
const observer = new ResizeObserver((entries) => {
for (const entry of entries) {
const newWidth = entry.contentBoxSize ? entry.contentBoxSize[0].inlineSize : entry.contentRect.width;
if (newWidth !== width.current) {
width.current = newWidth;
callback();
}
}
});
observer.observe(ref.current);
return () => {
observer.disconnect();
};
}, [enabled]);
};
// lib/Fitter.tsx
var import_jsx_runtime = require("react/jsx-runtime");
var Fitter = ({
children,
minSize = 0.25,
maxLines = 1,
settlePrecision = 0.01,
updateOnSizeChange = true,
resizeDebounceMs = 50
}) => {
const wrapperRef = (0, import_react2.useRef)(null);
const textRef = (0, import_react2.useRef)(null);
const [size, setSize] = (0, import_react2.useState)(1);
const [settled, setSettled] = (0, import_react2.useState)(false);
const [targetMax, setTargetMax] = (0, import_react2.useState)(1);
(0, import_react2.useEffect)(() => {
if (settled) return;
if (!textRef.current) throw new Error("Could not access wrapper ref");
const lines = textRef.current.getClientRects().length;
const nextShrinkStep = (size - minSize) / 2;
const nextGrowStep = (targetMax - size) / 2;
const nextShrinkSize = size - nextShrinkStep;
const nextGrowSize = size + nextGrowStep;
const wantsToShrink = lines > maxLines;
if (wantsToShrink) {
if (nextShrinkStep < settlePrecision) {
setSettled(true);
return;
}
setTargetMax(size);
setSize(nextShrinkSize);
return;
}
if (nextGrowStep < settlePrecision) {
setSettled(true);
return;
}
setSize(nextGrowSize);
}, [size, maxLines, minSize, targetMax, settlePrecision, settled]);
const start = useDebounce(() => {
setTargetMax(1);
setSettled(false);
}, resizeDebounceMs);
useResizeObserver(wrapperRef, () => start(), updateOnSizeChange);
return /* @__PURE__ */ (0, import_jsx_runtime.jsx)(
"div",
{
ref: wrapperRef,
className: "react-fitter__wrapper",
style: {
lineHeight: 0
},
children: /* @__PURE__ */ (0, import_jsx_runtime.jsx)(
"span",
{
ref: textRef,
style: {
fontSize: `${size * 100}%`,
lineHeight: 1
},
className: "react-fitter__text",
children
}
)
}
);
};
// Annotate the CommonJS export names for ESM import in node:
0 && (module.exports = {
Fitter
});
//# sourceMappingURL=index.cjs.map